blob: 5cc4bba70db61eab5157bb0bb7ffe6b673a11ab3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* request_key.c: request a key from userspace
2 *
David Howells3e301482005-06-23 22:00:56 -07003 * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * 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.
David Howellsf1a9bad2005-10-07 15:04:52 +010010 *
11 * See Documentation/keys-request-key.txt
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 */
13
14#include <linux/module.h>
15#include <linux/sched.h>
16#include <linux/kmod.h>
17#include <linux/err.h>
David Howells3e301482005-06-23 22:00:56 -070018#include <linux/keyctl.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include "internal.h"
20
21struct key_construction {
22 struct list_head link; /* link in construction queue */
23 struct key *key; /* key being constructed */
24};
25
26/* when waiting for someone else's keys, you get added to this */
27DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
28
29/*****************************************************************************/
30/*
31 * request userspace finish the construction of a key
32 * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 */
34static int call_request_key(struct key *key,
35 const char *op,
36 const char *callout_info)
37{
38 struct task_struct *tsk = current;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 key_serial_t prkey, sskey;
David Howells3e301482005-06-23 22:00:56 -070040 struct key *session_keyring, *rkakey;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 char *argv[10], *envp[3], uid_str[12], gid_str[12];
42 char key_str[12], keyring_str[3][12];
David Howells3e301482005-06-23 22:00:56 -070043 int ret, i;
44
45 kenter("{%d},%s,%s", key->serial, op, callout_info);
46
47 /* generate a new session keyring with an auth key in it */
48 session_keyring = request_key_auth_new(key, &rkakey);
49 if (IS_ERR(session_keyring)) {
50 ret = PTR_ERR(session_keyring);
51 goto error;
52 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54 /* record the UID and GID */
55 sprintf(uid_str, "%d", current->fsuid);
56 sprintf(gid_str, "%d", current->fsgid);
57
58 /* we say which key is under construction */
59 sprintf(key_str, "%d", key->serial);
60
61 /* we specify the process's default keyrings */
62 sprintf(keyring_str[0], "%d",
63 tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
64
65 prkey = 0;
66 if (tsk->signal->process_keyring)
67 prkey = tsk->signal->process_keyring->serial;
68
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 sprintf(keyring_str[1], "%d", prkey);
David Howells3e301482005-06-23 22:00:56 -070070
71 if (tsk->signal->session_keyring) {
72 rcu_read_lock();
73 sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
74 rcu_read_unlock();
75 }
76 else {
77 sskey = tsk->user->session_keyring->serial;
78 }
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 sprintf(keyring_str[2], "%d", sskey);
81
82 /* set up a minimal environment */
83 i = 0;
84 envp[i++] = "HOME=/";
85 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
86 envp[i] = NULL;
87
88 /* set up the argument list */
89 i = 0;
90 argv[i++] = "/sbin/request-key";
91 argv[i++] = (char *) op;
92 argv[i++] = key_str;
93 argv[i++] = uid_str;
94 argv[i++] = gid_str;
95 argv[i++] = keyring_str[0];
96 argv[i++] = keyring_str[1];
97 argv[i++] = keyring_str[2];
David Howells3e301482005-06-23 22:00:56 -070098 argv[i++] = (char *) callout_info;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 argv[i] = NULL;
100
101 /* do it */
David Howells3e301482005-06-23 22:00:56 -0700102 ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1);
103
104 /* dispose of the special keys */
105 key_revoke(rkakey);
106 key_put(rkakey);
107 key_put(session_keyring);
108
109 error:
110 kleave(" = %d", ret);
111 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113} /* end call_request_key() */
114
115/*****************************************************************************/
116/*
117 * call out to userspace for the key
118 * - called with the construction sem held, but the sem is dropped here
119 * - we ignore program failure and go on key status instead
120 */
121static struct key *__request_key_construction(struct key_type *type,
122 const char *description,
123 const char *callout_info)
124{
125 struct key_construction cons;
126 struct timespec now;
127 struct key *key;
David Howells76d8aea2005-06-23 22:00:49 -0700128 int ret, negated;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
David Howells3e301482005-06-23 22:00:56 -0700130 kenter("%s,%s,%s", type->name, description, callout_info);
131
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 /* create a key and add it to the queue */
133 key = key_alloc(type, description,
David Howells664cceb2005-09-28 17:03:15 +0100134 current->fsuid, current->fsgid, KEY_POS_ALL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 if (IS_ERR(key))
136 goto alloc_failed;
137
David Howells76d8aea2005-06-23 22:00:49 -0700138 set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
140 cons.key = key;
141 list_add_tail(&cons.link, &key->user->consq);
142
143 /* we drop the construction sem here on behalf of the caller */
144 up_write(&key_construction_sem);
145
146 /* make the call */
147 ret = call_request_key(key, "create", callout_info);
148 if (ret < 0)
149 goto request_failed;
150
151 /* if the key wasn't instantiated, then we want to give an error */
152 ret = -ENOKEY;
David Howells76d8aea2005-06-23 22:00:49 -0700153 if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 goto request_failed;
155
156 down_write(&key_construction_sem);
157 list_del(&cons.link);
158 up_write(&key_construction_sem);
159
160 /* also give an error if the key was negatively instantiated */
161 check_not_negative:
David Howells76d8aea2005-06-23 22:00:49 -0700162 if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 key_put(key);
164 key = ERR_PTR(-ENOKEY);
165 }
166
167 out:
David Howells3e301482005-06-23 22:00:56 -0700168 kleave(" = %p", key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 return key;
170
171 request_failed:
172 /* it wasn't instantiated
173 * - remove from construction queue
174 * - mark the key as dead
175 */
David Howells76d8aea2005-06-23 22:00:49 -0700176 negated = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 down_write(&key_construction_sem);
178
179 list_del(&cons.link);
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 /* check it didn't get instantiated between the check and the down */
David Howells76d8aea2005-06-23 22:00:49 -0700182 if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
183 set_bit(KEY_FLAG_NEGATIVE, &key->flags);
184 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
185 negated = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 }
187
David Howells76d8aea2005-06-23 22:00:49 -0700188 clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 up_write(&key_construction_sem);
191
David Howells76d8aea2005-06-23 22:00:49 -0700192 if (!negated)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 goto check_not_negative; /* surprisingly, the key got
194 * instantiated */
195
196 /* set the timeout and store in the session keyring if we can */
197 now = current_kernel_time();
198 key->expiry = now.tv_sec + key_negative_timeout;
199
200 if (current->signal->session_keyring) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 struct key *keyring;
202
David Howells8589b4e2005-06-23 22:00:53 -0700203 rcu_read_lock();
204 keyring = rcu_dereference(current->signal->session_keyring);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 atomic_inc(&keyring->usage);
David Howells8589b4e2005-06-23 22:00:53 -0700206 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 key_link(keyring, key);
209 key_put(keyring);
210 }
211
212 key_put(key);
213
214 /* notify anyone who was waiting */
215 wake_up_all(&request_key_conswq);
216
217 key = ERR_PTR(ret);
218 goto out;
219
220 alloc_failed:
221 up_write(&key_construction_sem);
222 goto out;
223
224} /* end __request_key_construction() */
225
226/*****************************************************************************/
227/*
228 * call out to userspace to request the key
229 * - we check the construction queue first to see if an appropriate key is
230 * already being constructed by userspace
231 */
232static struct key *request_key_construction(struct key_type *type,
233 const char *description,
234 struct key_user *user,
235 const char *callout_info)
236{
237 struct key_construction *pcons;
238 struct key *key, *ckey;
239
240 DECLARE_WAITQUEUE(myself, current);
241
David Howells3e301482005-06-23 22:00:56 -0700242 kenter("%s,%s,{%d},%s",
243 type->name, description, user->uid, callout_info);
244
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 /* see if there's such a key under construction already */
246 down_write(&key_construction_sem);
247
248 list_for_each_entry(pcons, &user->consq, link) {
249 ckey = pcons->key;
250
251 if (ckey->type != type)
252 continue;
253
254 if (type->match(ckey, description))
255 goto found_key_under_construction;
256 }
257
258 /* see about getting userspace to construct the key */
259 key = __request_key_construction(type, description, callout_info);
260 error:
David Howells3e301482005-06-23 22:00:56 -0700261 kleave(" = %p", key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 return key;
263
264 /* someone else has the same key under construction
265 * - we want to keep an eye on their key
266 */
267 found_key_under_construction:
268 atomic_inc(&ckey->usage);
269 up_write(&key_construction_sem);
270
271 /* wait for the key to be completed one way or another */
272 add_wait_queue(&request_key_conswq, &myself);
273
274 for (;;) {
David Howells3e301482005-06-23 22:00:56 -0700275 set_current_state(TASK_INTERRUPTIBLE);
David Howells76d8aea2005-06-23 22:00:49 -0700276 if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 break;
David Howells3e301482005-06-23 22:00:56 -0700278 if (signal_pending(current))
279 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 schedule();
281 }
282
283 set_current_state(TASK_RUNNING);
284 remove_wait_queue(&request_key_conswq, &myself);
285
286 /* we'll need to search this process's keyrings to see if the key is
287 * now there since we can't automatically assume it's also available
288 * there */
289 key_put(ckey);
290 ckey = NULL;
291
292 key = NULL; /* request a retry */
293 goto error;
294
295} /* end request_key_construction() */
296
297/*****************************************************************************/
298/*
David Howells3e301482005-06-23 22:00:56 -0700299 * link a freshly minted key to an appropriate destination keyring
300 */
301static void request_key_link(struct key *key, struct key *dest_keyring)
302{
303 struct task_struct *tsk = current;
304 struct key *drop = NULL;
305
306 kenter("{%d},%p", key->serial, dest_keyring);
307
308 /* find the appropriate keyring */
309 if (!dest_keyring) {
310 switch (tsk->jit_keyring) {
311 case KEY_REQKEY_DEFL_DEFAULT:
312 case KEY_REQKEY_DEFL_THREAD_KEYRING:
313 dest_keyring = tsk->thread_keyring;
314 if (dest_keyring)
315 break;
316
317 case KEY_REQKEY_DEFL_PROCESS_KEYRING:
318 dest_keyring = tsk->signal->process_keyring;
319 if (dest_keyring)
320 break;
321
322 case KEY_REQKEY_DEFL_SESSION_KEYRING:
323 rcu_read_lock();
324 dest_keyring = key_get(
325 rcu_dereference(tsk->signal->session_keyring));
326 rcu_read_unlock();
327 drop = dest_keyring;
328
329 if (dest_keyring)
330 break;
331
332 case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
333 dest_keyring = current->user->session_keyring;
334 break;
335
336 case KEY_REQKEY_DEFL_USER_KEYRING:
337 dest_keyring = current->user->uid_keyring;
338 break;
339
340 case KEY_REQKEY_DEFL_GROUP_KEYRING:
341 default:
342 BUG();
343 }
344 }
345
346 /* and attach the key to it */
347 key_link(dest_keyring, key);
348
349 key_put(drop);
350
351 kleave("");
352
353} /* end request_key_link() */
354
355/*****************************************************************************/
356/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 * request a key
358 * - search the process's keyrings
359 * - check the list of keys being created or updated
David Howells3e301482005-06-23 22:00:56 -0700360 * - call out to userspace for a key if supplementary info was provided
361 * - cache the key in an appropriate keyring
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 */
David Howells3e301482005-06-23 22:00:56 -0700363struct key *request_key_and_link(struct key_type *type,
364 const char *description,
365 const char *callout_info,
366 struct key *dest_keyring)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367{
368 struct key_user *user;
369 struct key *key;
David Howells664cceb2005-09-28 17:03:15 +0100370 key_ref_t key_ref;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371
David Howells3e301482005-06-23 22:00:56 -0700372 kenter("%s,%s,%s,%p",
373 type->name, description, callout_info, dest_keyring);
374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 /* search all the process keyrings for a key */
David Howells664cceb2005-09-28 17:03:15 +0100376 key_ref = search_process_keyrings(type, description, type->match,
377 current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
David Howells664cceb2005-09-28 17:03:15 +0100379 kdebug("search 1: %p", key_ref);
380
381 if (!IS_ERR(key_ref)) {
382 key = key_ref_to_ptr(key_ref);
383 }
384 else if (PTR_ERR(key_ref) != -EAGAIN) {
385 key = ERR_PTR(PTR_ERR(key_ref));
386 }
387 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 /* the search failed, but the keyrings were searchable, so we
389 * should consult userspace if we can */
390 key = ERR_PTR(-ENOKEY);
391 if (!callout_info)
392 goto error;
393
394 /* - get hold of the user's construction queue */
395 user = key_user_lookup(current->fsuid);
David Howells3e301482005-06-23 22:00:56 -0700396 if (!user)
397 goto nomem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
David Howells664cceb2005-09-28 17:03:15 +0100399 for (;;) {
David Howells3e301482005-06-23 22:00:56 -0700400 if (signal_pending(current))
401 goto interrupted;
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 /* ask userspace (returns NULL if it waited on a key
404 * being constructed) */
405 key = request_key_construction(type, description,
406 user, callout_info);
407 if (key)
408 break;
409
410 /* someone else made the key we want, so we need to
411 * search again as it might now be available to us */
David Howells664cceb2005-09-28 17:03:15 +0100412 key_ref = search_process_keyrings(type, description,
413 type->match,
414 current);
David Howells3e301482005-06-23 22:00:56 -0700415
David Howells664cceb2005-09-28 17:03:15 +0100416 kdebug("search 2: %p", key_ref);
417
418 if (!IS_ERR(key_ref)) {
419 key = key_ref_to_ptr(key_ref);
420 break;
421 }
422
423 if (PTR_ERR(key_ref) != -EAGAIN) {
424 key = ERR_PTR(PTR_ERR(key_ref));
425 break;
426 }
427 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428
429 key_user_put(user);
David Howells3e301482005-06-23 22:00:56 -0700430
431 /* link the new key into the appropriate keyring */
David Howells1260f802005-08-04 11:50:01 +0100432 if (!IS_ERR(key))
David Howells3e301482005-06-23 22:00:56 -0700433 request_key_link(key, dest_keyring);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 }
435
David Howells3e301482005-06-23 22:00:56 -0700436error:
437 kleave(" = %p", key);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700438 return key;
439
David Howells3e301482005-06-23 22:00:56 -0700440nomem:
441 key = ERR_PTR(-ENOMEM);
442 goto error;
443
444interrupted:
445 key_user_put(user);
446 key = ERR_PTR(-EINTR);
447 goto error;
448
449} /* end request_key_and_link() */
450
451/*****************************************************************************/
452/*
453 * request a key
454 * - search the process's keyrings
455 * - check the list of keys being created or updated
456 * - call out to userspace for a key if supplementary info was provided
457 */
458struct key *request_key(struct key_type *type,
459 const char *description,
460 const char *callout_info)
461{
462 return request_key_and_link(type, description, callout_info, NULL);
463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464} /* end request_key() */
465
466EXPORT_SYMBOL(request_key);
467
468/*****************************************************************************/
469/*
470 * validate a key
471 */
472int key_validate(struct key *key)
473{
474 struct timespec now;
475 int ret = 0;
476
477 if (key) {
478 /* check it's still accessible */
479 ret = -EKEYREVOKED;
David Howells76d8aea2005-06-23 22:00:49 -0700480 if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
481 test_bit(KEY_FLAG_DEAD, &key->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 goto error;
483
484 /* check it hasn't expired */
485 ret = 0;
486 if (key->expiry) {
487 now = current_kernel_time();
488 if (now.tv_sec >= key->expiry)
489 ret = -EKEYEXPIRED;
490 }
491 }
492
493 error:
494 return ret;
495
496} /* end key_validate() */
497
498EXPORT_SYMBOL(key_validate);