diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /security/keys/process_keys.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'security/keys/process_keys.c')
-rw-r--r-- | security/keys/process_keys.c | 665 |
1 files changed, 665 insertions, 0 deletions
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c new file mode 100644 index 000000000000..2eb0e471cd40 --- /dev/null +++ b/security/keys/process_keys.c | |||
@@ -0,0 +1,665 @@ | |||
1 | /* process_keys.c: management of a process's keyrings | ||
2 | * | ||
3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/keyctl.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <asm/uaccess.h> | ||
20 | #include "internal.h" | ||
21 | |||
22 | /* session keyring create vs join semaphore */ | ||
23 | static DECLARE_MUTEX(key_session_sem); | ||
24 | |||
25 | /* the root user's tracking struct */ | ||
26 | struct key_user root_key_user = { | ||
27 | .usage = ATOMIC_INIT(3), | ||
28 | .consq = LIST_HEAD_INIT(root_key_user.consq), | ||
29 | .lock = SPIN_LOCK_UNLOCKED, | ||
30 | .nkeys = ATOMIC_INIT(2), | ||
31 | .nikeys = ATOMIC_INIT(2), | ||
32 | .uid = 0, | ||
33 | }; | ||
34 | |||
35 | /* the root user's UID keyring */ | ||
36 | struct key root_user_keyring = { | ||
37 | .usage = ATOMIC_INIT(1), | ||
38 | .serial = 2, | ||
39 | .type = &key_type_keyring, | ||
40 | .user = &root_key_user, | ||
41 | .lock = RW_LOCK_UNLOCKED, | ||
42 | .sem = __RWSEM_INITIALIZER(root_user_keyring.sem), | ||
43 | .perm = KEY_USR_ALL, | ||
44 | .flags = KEY_FLAG_INSTANTIATED, | ||
45 | .description = "_uid.0", | ||
46 | #ifdef KEY_DEBUGGING | ||
47 | .magic = KEY_DEBUG_MAGIC, | ||
48 | #endif | ||
49 | }; | ||
50 | |||
51 | /* the root user's default session keyring */ | ||
52 | struct key root_session_keyring = { | ||
53 | .usage = ATOMIC_INIT(1), | ||
54 | .serial = 1, | ||
55 | .type = &key_type_keyring, | ||
56 | .user = &root_key_user, | ||
57 | .lock = RW_LOCK_UNLOCKED, | ||
58 | .sem = __RWSEM_INITIALIZER(root_session_keyring.sem), | ||
59 | .perm = KEY_USR_ALL, | ||
60 | .flags = KEY_FLAG_INSTANTIATED, | ||
61 | .description = "_uid_ses.0", | ||
62 | #ifdef KEY_DEBUGGING | ||
63 | .magic = KEY_DEBUG_MAGIC, | ||
64 | #endif | ||
65 | }; | ||
66 | |||
67 | /*****************************************************************************/ | ||
68 | /* | ||
69 | * allocate the keyrings to be associated with a UID | ||
70 | */ | ||
71 | int alloc_uid_keyring(struct user_struct *user) | ||
72 | { | ||
73 | struct key *uid_keyring, *session_keyring; | ||
74 | char buf[20]; | ||
75 | int ret; | ||
76 | |||
77 | /* concoct a default session keyring */ | ||
78 | sprintf(buf, "_uid_ses.%u", user->uid); | ||
79 | |||
80 | session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, NULL); | ||
81 | if (IS_ERR(session_keyring)) { | ||
82 | ret = PTR_ERR(session_keyring); | ||
83 | goto error; | ||
84 | } | ||
85 | |||
86 | /* and a UID specific keyring, pointed to by the default session | ||
87 | * keyring */ | ||
88 | sprintf(buf, "_uid.%u", user->uid); | ||
89 | |||
90 | uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, 0, | ||
91 | session_keyring); | ||
92 | if (IS_ERR(uid_keyring)) { | ||
93 | key_put(session_keyring); | ||
94 | ret = PTR_ERR(uid_keyring); | ||
95 | goto error; | ||
96 | } | ||
97 | |||
98 | /* install the keyrings */ | ||
99 | user->uid_keyring = uid_keyring; | ||
100 | user->session_keyring = session_keyring; | ||
101 | ret = 0; | ||
102 | |||
103 | error: | ||
104 | return ret; | ||
105 | |||
106 | } /* end alloc_uid_keyring() */ | ||
107 | |||
108 | /*****************************************************************************/ | ||
109 | /* | ||
110 | * deal with the UID changing | ||
111 | */ | ||
112 | void switch_uid_keyring(struct user_struct *new_user) | ||
113 | { | ||
114 | #if 0 /* do nothing for now */ | ||
115 | struct key *old; | ||
116 | |||
117 | /* switch to the new user's session keyring if we were running under | ||
118 | * root's default session keyring */ | ||
119 | if (new_user->uid != 0 && | ||
120 | current->session_keyring == &root_session_keyring | ||
121 | ) { | ||
122 | atomic_inc(&new_user->session_keyring->usage); | ||
123 | |||
124 | task_lock(current); | ||
125 | old = current->session_keyring; | ||
126 | current->session_keyring = new_user->session_keyring; | ||
127 | task_unlock(current); | ||
128 | |||
129 | key_put(old); | ||
130 | } | ||
131 | #endif | ||
132 | |||
133 | } /* end switch_uid_keyring() */ | ||
134 | |||
135 | /*****************************************************************************/ | ||
136 | /* | ||
137 | * install a fresh thread keyring, discarding the old one | ||
138 | */ | ||
139 | int install_thread_keyring(struct task_struct *tsk) | ||
140 | { | ||
141 | struct key *keyring, *old; | ||
142 | char buf[20]; | ||
143 | int ret; | ||
144 | |||
145 | sprintf(buf, "_tid.%u", tsk->pid); | ||
146 | |||
147 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); | ||
148 | if (IS_ERR(keyring)) { | ||
149 | ret = PTR_ERR(keyring); | ||
150 | goto error; | ||
151 | } | ||
152 | |||
153 | task_lock(tsk); | ||
154 | old = tsk->thread_keyring; | ||
155 | tsk->thread_keyring = keyring; | ||
156 | task_unlock(tsk); | ||
157 | |||
158 | ret = 0; | ||
159 | |||
160 | key_put(old); | ||
161 | error: | ||
162 | return ret; | ||
163 | |||
164 | } /* end install_thread_keyring() */ | ||
165 | |||
166 | /*****************************************************************************/ | ||
167 | /* | ||
168 | * make sure a process keyring is installed | ||
169 | */ | ||
170 | static int install_process_keyring(struct task_struct *tsk) | ||
171 | { | ||
172 | unsigned long flags; | ||
173 | struct key *keyring; | ||
174 | char buf[20]; | ||
175 | int ret; | ||
176 | |||
177 | if (!tsk->signal->process_keyring) { | ||
178 | sprintf(buf, "_pid.%u", tsk->tgid); | ||
179 | |||
180 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); | ||
181 | if (IS_ERR(keyring)) { | ||
182 | ret = PTR_ERR(keyring); | ||
183 | goto error; | ||
184 | } | ||
185 | |||
186 | /* attach or swap keyrings */ | ||
187 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | ||
188 | if (!tsk->signal->process_keyring) { | ||
189 | tsk->signal->process_keyring = keyring; | ||
190 | keyring = NULL; | ||
191 | } | ||
192 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | ||
193 | |||
194 | key_put(keyring); | ||
195 | } | ||
196 | |||
197 | ret = 0; | ||
198 | error: | ||
199 | return ret; | ||
200 | |||
201 | } /* end install_process_keyring() */ | ||
202 | |||
203 | /*****************************************************************************/ | ||
204 | /* | ||
205 | * install a session keyring, discarding the old one | ||
206 | * - if a keyring is not supplied, an empty one is invented | ||
207 | */ | ||
208 | static int install_session_keyring(struct task_struct *tsk, | ||
209 | struct key *keyring) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | struct key *old; | ||
213 | char buf[20]; | ||
214 | int ret; | ||
215 | |||
216 | /* create an empty session keyring */ | ||
217 | if (!keyring) { | ||
218 | sprintf(buf, "_ses.%u", tsk->tgid); | ||
219 | |||
220 | keyring = keyring_alloc(buf, tsk->uid, tsk->gid, 1, NULL); | ||
221 | if (IS_ERR(keyring)) { | ||
222 | ret = PTR_ERR(keyring); | ||
223 | goto error; | ||
224 | } | ||
225 | } | ||
226 | else { | ||
227 | atomic_inc(&keyring->usage); | ||
228 | } | ||
229 | |||
230 | /* install the keyring */ | ||
231 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | ||
232 | old = tsk->signal->session_keyring; | ||
233 | tsk->signal->session_keyring = keyring; | ||
234 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | ||
235 | |||
236 | ret = 0; | ||
237 | |||
238 | key_put(old); | ||
239 | error: | ||
240 | return ret; | ||
241 | |||
242 | } /* end install_session_keyring() */ | ||
243 | |||
244 | /*****************************************************************************/ | ||
245 | /* | ||
246 | * copy the keys in a thread group for fork without CLONE_THREAD | ||
247 | */ | ||
248 | int copy_thread_group_keys(struct task_struct *tsk) | ||
249 | { | ||
250 | unsigned long flags; | ||
251 | |||
252 | key_check(current->thread_group->session_keyring); | ||
253 | key_check(current->thread_group->process_keyring); | ||
254 | |||
255 | /* no process keyring yet */ | ||
256 | tsk->signal->process_keyring = NULL; | ||
257 | |||
258 | /* same session keyring */ | ||
259 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
260 | tsk->signal->session_keyring = | ||
261 | key_get(current->signal->session_keyring); | ||
262 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
263 | |||
264 | return 0; | ||
265 | |||
266 | } /* end copy_thread_group_keys() */ | ||
267 | |||
268 | /*****************************************************************************/ | ||
269 | /* | ||
270 | * copy the keys for fork | ||
271 | */ | ||
272 | int copy_keys(unsigned long clone_flags, struct task_struct *tsk) | ||
273 | { | ||
274 | key_check(tsk->thread_keyring); | ||
275 | |||
276 | /* no thread keyring yet */ | ||
277 | tsk->thread_keyring = NULL; | ||
278 | return 0; | ||
279 | |||
280 | } /* end copy_keys() */ | ||
281 | |||
282 | /*****************************************************************************/ | ||
283 | /* | ||
284 | * dispose of thread group keys upon thread group destruction | ||
285 | */ | ||
286 | void exit_thread_group_keys(struct signal_struct *tg) | ||
287 | { | ||
288 | key_put(tg->session_keyring); | ||
289 | key_put(tg->process_keyring); | ||
290 | |||
291 | } /* end exit_thread_group_keys() */ | ||
292 | |||
293 | /*****************************************************************************/ | ||
294 | /* | ||
295 | * dispose of keys upon thread exit | ||
296 | */ | ||
297 | void exit_keys(struct task_struct *tsk) | ||
298 | { | ||
299 | key_put(tsk->thread_keyring); | ||
300 | |||
301 | } /* end exit_keys() */ | ||
302 | |||
303 | /*****************************************************************************/ | ||
304 | /* | ||
305 | * deal with execve() | ||
306 | */ | ||
307 | int exec_keys(struct task_struct *tsk) | ||
308 | { | ||
309 | unsigned long flags; | ||
310 | struct key *old; | ||
311 | |||
312 | /* newly exec'd tasks don't get a thread keyring */ | ||
313 | task_lock(tsk); | ||
314 | old = tsk->thread_keyring; | ||
315 | tsk->thread_keyring = NULL; | ||
316 | task_unlock(tsk); | ||
317 | |||
318 | key_put(old); | ||
319 | |||
320 | /* discard the process keyring from a newly exec'd task */ | ||
321 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | ||
322 | old = tsk->signal->process_keyring; | ||
323 | tsk->signal->process_keyring = NULL; | ||
324 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | ||
325 | |||
326 | key_put(old); | ||
327 | |||
328 | return 0; | ||
329 | |||
330 | } /* end exec_keys() */ | ||
331 | |||
332 | /*****************************************************************************/ | ||
333 | /* | ||
334 | * deal with SUID programs | ||
335 | * - we might want to make this invent a new session keyring | ||
336 | */ | ||
337 | int suid_keys(struct task_struct *tsk) | ||
338 | { | ||
339 | return 0; | ||
340 | |||
341 | } /* end suid_keys() */ | ||
342 | |||
343 | /*****************************************************************************/ | ||
344 | /* | ||
345 | * the filesystem user ID changed | ||
346 | */ | ||
347 | void key_fsuid_changed(struct task_struct *tsk) | ||
348 | { | ||
349 | /* update the ownership of the thread keyring */ | ||
350 | if (tsk->thread_keyring) { | ||
351 | down_write(&tsk->thread_keyring->sem); | ||
352 | write_lock(&tsk->thread_keyring->lock); | ||
353 | tsk->thread_keyring->uid = tsk->fsuid; | ||
354 | write_unlock(&tsk->thread_keyring->lock); | ||
355 | up_write(&tsk->thread_keyring->sem); | ||
356 | } | ||
357 | |||
358 | } /* end key_fsuid_changed() */ | ||
359 | |||
360 | /*****************************************************************************/ | ||
361 | /* | ||
362 | * the filesystem group ID changed | ||
363 | */ | ||
364 | void key_fsgid_changed(struct task_struct *tsk) | ||
365 | { | ||
366 | /* update the ownership of the thread keyring */ | ||
367 | if (tsk->thread_keyring) { | ||
368 | down_write(&tsk->thread_keyring->sem); | ||
369 | write_lock(&tsk->thread_keyring->lock); | ||
370 | tsk->thread_keyring->gid = tsk->fsgid; | ||
371 | write_unlock(&tsk->thread_keyring->lock); | ||
372 | up_write(&tsk->thread_keyring->sem); | ||
373 | } | ||
374 | |||
375 | } /* end key_fsgid_changed() */ | ||
376 | |||
377 | /*****************************************************************************/ | ||
378 | /* | ||
379 | * search the process keyrings for the first matching key | ||
380 | * - we use the supplied match function to see if the description (or other | ||
381 | * feature of interest) matches | ||
382 | * - we return -EAGAIN if we didn't find any matching key | ||
383 | * - we return -ENOKEY if we found only negative matching keys | ||
384 | */ | ||
385 | struct key *search_process_keyrings_aux(struct key_type *type, | ||
386 | const void *description, | ||
387 | key_match_func_t match) | ||
388 | { | ||
389 | struct task_struct *tsk = current; | ||
390 | unsigned long flags; | ||
391 | struct key *key, *ret, *err, *tmp; | ||
392 | |||
393 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | ||
394 | * searchable, but we failed to find a key or we found a negative key; | ||
395 | * otherwise we want to return a sample error (probably -EACCES) if | ||
396 | * none of the keyrings were searchable | ||
397 | * | ||
398 | * in terms of priority: success > -ENOKEY > -EAGAIN > other error | ||
399 | */ | ||
400 | key = NULL; | ||
401 | ret = NULL; | ||
402 | err = ERR_PTR(-EAGAIN); | ||
403 | |||
404 | /* search the thread keyring first */ | ||
405 | if (tsk->thread_keyring) { | ||
406 | key = keyring_search_aux(tsk->thread_keyring, type, | ||
407 | description, match); | ||
408 | if (!IS_ERR(key)) | ||
409 | goto found; | ||
410 | |||
411 | switch (PTR_ERR(key)) { | ||
412 | case -EAGAIN: /* no key */ | ||
413 | if (ret) | ||
414 | break; | ||
415 | case -ENOKEY: /* negative key */ | ||
416 | ret = key; | ||
417 | break; | ||
418 | default: | ||
419 | err = key; | ||
420 | break; | ||
421 | } | ||
422 | } | ||
423 | |||
424 | /* search the process keyring second */ | ||
425 | if (tsk->signal->process_keyring) { | ||
426 | key = keyring_search_aux(tsk->signal->process_keyring, | ||
427 | type, description, match); | ||
428 | if (!IS_ERR(key)) | ||
429 | goto found; | ||
430 | |||
431 | switch (PTR_ERR(key)) { | ||
432 | case -EAGAIN: /* no key */ | ||
433 | if (ret) | ||
434 | break; | ||
435 | case -ENOKEY: /* negative key */ | ||
436 | ret = key; | ||
437 | break; | ||
438 | default: | ||
439 | err = key; | ||
440 | break; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | /* search the session keyring last */ | ||
445 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | ||
446 | |||
447 | tmp = tsk->signal->session_keyring; | ||
448 | if (!tmp) | ||
449 | tmp = tsk->user->session_keyring; | ||
450 | atomic_inc(&tmp->usage); | ||
451 | |||
452 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | ||
453 | |||
454 | key = keyring_search_aux(tmp, type, description, match); | ||
455 | key_put(tmp); | ||
456 | if (!IS_ERR(key)) | ||
457 | goto found; | ||
458 | |||
459 | switch (PTR_ERR(key)) { | ||
460 | case -EAGAIN: /* no key */ | ||
461 | if (ret) | ||
462 | break; | ||
463 | case -ENOKEY: /* negative key */ | ||
464 | ret = key; | ||
465 | break; | ||
466 | default: | ||
467 | err = key; | ||
468 | break; | ||
469 | } | ||
470 | |||
471 | /* no key - decide on the error we're going to go for */ | ||
472 | key = ret ? ret : err; | ||
473 | |||
474 | found: | ||
475 | return key; | ||
476 | |||
477 | } /* end search_process_keyrings_aux() */ | ||
478 | |||
479 | /*****************************************************************************/ | ||
480 | /* | ||
481 | * search the process keyrings for the first matching key | ||
482 | * - we return -EAGAIN if we didn't find any matching key | ||
483 | * - we return -ENOKEY if we found only negative matching keys | ||
484 | */ | ||
485 | struct key *search_process_keyrings(struct key_type *type, | ||
486 | const char *description) | ||
487 | { | ||
488 | return search_process_keyrings_aux(type, description, type->match); | ||
489 | |||
490 | } /* end search_process_keyrings() */ | ||
491 | |||
492 | /*****************************************************************************/ | ||
493 | /* | ||
494 | * lookup a key given a key ID from userspace with a given permissions mask | ||
495 | * - don't create special keyrings unless so requested | ||
496 | * - partially constructed keys aren't found unless requested | ||
497 | */ | ||
498 | struct key *lookup_user_key(key_serial_t id, int create, int partial, | ||
499 | key_perm_t perm) | ||
500 | { | ||
501 | struct task_struct *tsk = current; | ||
502 | unsigned long flags; | ||
503 | struct key *key; | ||
504 | int ret; | ||
505 | |||
506 | key = ERR_PTR(-ENOKEY); | ||
507 | |||
508 | switch (id) { | ||
509 | case KEY_SPEC_THREAD_KEYRING: | ||
510 | if (!tsk->thread_keyring) { | ||
511 | if (!create) | ||
512 | goto error; | ||
513 | |||
514 | ret = install_thread_keyring(tsk); | ||
515 | if (ret < 0) { | ||
516 | key = ERR_PTR(ret); | ||
517 | goto error; | ||
518 | } | ||
519 | } | ||
520 | |||
521 | key = tsk->thread_keyring; | ||
522 | atomic_inc(&key->usage); | ||
523 | break; | ||
524 | |||
525 | case KEY_SPEC_PROCESS_KEYRING: | ||
526 | if (!tsk->signal->process_keyring) { | ||
527 | if (!create) | ||
528 | goto error; | ||
529 | |||
530 | ret = install_process_keyring(tsk); | ||
531 | if (ret < 0) { | ||
532 | key = ERR_PTR(ret); | ||
533 | goto error; | ||
534 | } | ||
535 | } | ||
536 | |||
537 | key = tsk->signal->process_keyring; | ||
538 | atomic_inc(&key->usage); | ||
539 | break; | ||
540 | |||
541 | case KEY_SPEC_SESSION_KEYRING: | ||
542 | if (!tsk->signal->session_keyring) { | ||
543 | /* always install a session keyring upon access if one | ||
544 | * doesn't exist yet */ | ||
545 | ret = install_session_keyring( | ||
546 | tsk, tsk->user->session_keyring); | ||
547 | if (ret < 0) | ||
548 | goto error; | ||
549 | } | ||
550 | |||
551 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | ||
552 | key = tsk->signal->session_keyring; | ||
553 | atomic_inc(&key->usage); | ||
554 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | ||
555 | break; | ||
556 | |||
557 | case KEY_SPEC_USER_KEYRING: | ||
558 | key = tsk->user->uid_keyring; | ||
559 | atomic_inc(&key->usage); | ||
560 | break; | ||
561 | |||
562 | case KEY_SPEC_USER_SESSION_KEYRING: | ||
563 | key = tsk->user->session_keyring; | ||
564 | atomic_inc(&key->usage); | ||
565 | break; | ||
566 | |||
567 | case KEY_SPEC_GROUP_KEYRING: | ||
568 | /* group keyrings are not yet supported */ | ||
569 | key = ERR_PTR(-EINVAL); | ||
570 | goto error; | ||
571 | |||
572 | default: | ||
573 | key = ERR_PTR(-EINVAL); | ||
574 | if (id < 1) | ||
575 | goto error; | ||
576 | |||
577 | key = key_lookup(id); | ||
578 | if (IS_ERR(key)) | ||
579 | goto error; | ||
580 | break; | ||
581 | } | ||
582 | |||
583 | /* check the status and permissions */ | ||
584 | if (perm) { | ||
585 | ret = key_validate(key); | ||
586 | if (ret < 0) | ||
587 | goto invalid_key; | ||
588 | } | ||
589 | |||
590 | ret = -EIO; | ||
591 | if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED)) | ||
592 | goto invalid_key; | ||
593 | |||
594 | ret = -EACCES; | ||
595 | if (!key_permission(key, perm)) | ||
596 | goto invalid_key; | ||
597 | |||
598 | error: | ||
599 | return key; | ||
600 | |||
601 | invalid_key: | ||
602 | key_put(key); | ||
603 | key = ERR_PTR(ret); | ||
604 | goto error; | ||
605 | |||
606 | } /* end lookup_user_key() */ | ||
607 | |||
608 | /*****************************************************************************/ | ||
609 | /* | ||
610 | * join the named keyring as the session keyring if possible, or attempt to | ||
611 | * create a new one of that name if not | ||
612 | * - if the name is NULL, an empty anonymous keyring is installed instead | ||
613 | * - named session keyring joining is done with a semaphore held | ||
614 | */ | ||
615 | long join_session_keyring(const char *name) | ||
616 | { | ||
617 | struct task_struct *tsk = current; | ||
618 | unsigned long flags; | ||
619 | struct key *keyring; | ||
620 | long ret; | ||
621 | |||
622 | /* if no name is provided, install an anonymous keyring */ | ||
623 | if (!name) { | ||
624 | ret = install_session_keyring(tsk, NULL); | ||
625 | if (ret < 0) | ||
626 | goto error; | ||
627 | |||
628 | spin_lock_irqsave(&tsk->sighand->siglock, flags); | ||
629 | ret = tsk->signal->session_keyring->serial; | ||
630 | spin_unlock_irqrestore(&tsk->sighand->siglock, flags); | ||
631 | goto error; | ||
632 | } | ||
633 | |||
634 | /* allow the user to join or create a named keyring */ | ||
635 | down(&key_session_sem); | ||
636 | |||
637 | /* look for an existing keyring of this name */ | ||
638 | keyring = find_keyring_by_name(name, 0); | ||
639 | if (PTR_ERR(keyring) == -ENOKEY) { | ||
640 | /* not found - try and create a new one */ | ||
641 | keyring = keyring_alloc(name, tsk->uid, tsk->gid, 0, NULL); | ||
642 | if (IS_ERR(keyring)) { | ||
643 | ret = PTR_ERR(keyring); | ||
644 | goto error; | ||
645 | } | ||
646 | } | ||
647 | else if (IS_ERR(keyring)) { | ||
648 | ret = PTR_ERR(keyring); | ||
649 | goto error2; | ||
650 | } | ||
651 | |||
652 | /* we've got a keyring - now to install it */ | ||
653 | ret = install_session_keyring(tsk, keyring); | ||
654 | if (ret < 0) | ||
655 | goto error2; | ||
656 | |||
657 | ret = keyring->serial; | ||
658 | key_put(keyring); | ||
659 | |||
660 | error2: | ||
661 | up(&key_session_sem); | ||
662 | error: | ||
663 | return ret; | ||
664 | |||
665 | } /* end join_session_keyring() */ | ||