Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* keyctl.c: userspace keyctl operations |
2 | * | |
3e30148c | 3 | * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved. |
1da177e4 LT |
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/syscalls.h> | |
17 | #include <linux/keyctl.h> | |
18 | #include <linux/fs.h> | |
c59ede7b | 19 | #include <linux/capability.h> |
0cb409d9 | 20 | #include <linux/string.h> |
1da177e4 | 21 | #include <linux/err.h> |
38bbca6b | 22 | #include <linux/vmalloc.h> |
1da177e4 LT |
23 | #include <asm/uaccess.h> |
24 | #include "internal.h" | |
25 | ||
0cb409d9 DA |
26 | static int key_get_type_from_user(char *type, |
27 | const char __user *_type, | |
28 | unsigned len) | |
29 | { | |
30 | int ret; | |
31 | ||
32 | ret = strncpy_from_user(type, _type, len); | |
33 | ||
34 | if (ret < 0) | |
35 | return -EFAULT; | |
36 | ||
37 | if (ret == 0 || ret >= len) | |
38 | return -EINVAL; | |
39 | ||
40 | if (type[0] == '.') | |
41 | return -EPERM; | |
42 | ||
43 | type[len - 1] = '\0'; | |
44 | ||
45 | return 0; | |
46 | } | |
47 | ||
1da177e4 LT |
48 | /*****************************************************************************/ |
49 | /* | |
50 | * extract the description of a new key from userspace and either add it as a | |
51 | * new key to the specified keyring or update a matching key in that keyring | |
52 | * - the keyring must be writable | |
53 | * - returns the new key's serial number | |
54 | * - implements add_key() | |
55 | */ | |
56 | asmlinkage long sys_add_key(const char __user *_type, | |
57 | const char __user *_description, | |
58 | const void __user *_payload, | |
59 | size_t plen, | |
60 | key_serial_t ringid) | |
61 | { | |
664cceb0 | 62 | key_ref_t keyring_ref, key_ref; |
1da177e4 LT |
63 | char type[32], *description; |
64 | void *payload; | |
0cb409d9 | 65 | long ret; |
38bbca6b | 66 | bool vm; |
1da177e4 LT |
67 | |
68 | ret = -EINVAL; | |
38bbca6b | 69 | if (plen > 1024 * 1024 - 1) |
1da177e4 LT |
70 | goto error; |
71 | ||
72 | /* draw all the data into kernel space */ | |
0cb409d9 | 73 | ret = key_get_type_from_user(type, _type, sizeof(type)); |
1da177e4 LT |
74 | if (ret < 0) |
75 | goto error; | |
1da177e4 | 76 | |
0cb409d9 DA |
77 | description = strndup_user(_description, PAGE_SIZE); |
78 | if (IS_ERR(description)) { | |
79 | ret = PTR_ERR(description); | |
1da177e4 | 80 | goto error; |
0cb409d9 | 81 | } |
1da177e4 LT |
82 | |
83 | /* pull the payload in if one was supplied */ | |
84 | payload = NULL; | |
85 | ||
38bbca6b | 86 | vm = false; |
1da177e4 LT |
87 | if (_payload) { |
88 | ret = -ENOMEM; | |
89 | payload = kmalloc(plen, GFP_KERNEL); | |
38bbca6b DH |
90 | if (!payload) { |
91 | if (plen <= PAGE_SIZE) | |
92 | goto error2; | |
93 | vm = true; | |
94 | payload = vmalloc(plen); | |
95 | if (!payload) | |
96 | goto error2; | |
97 | } | |
1da177e4 LT |
98 | |
99 | ret = -EFAULT; | |
100 | if (copy_from_user(payload, _payload, plen) != 0) | |
101 | goto error3; | |
102 | } | |
103 | ||
104 | /* find the target keyring (which must be writable) */ | |
664cceb0 DH |
105 | keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
106 | if (IS_ERR(keyring_ref)) { | |
107 | ret = PTR_ERR(keyring_ref); | |
1da177e4 LT |
108 | goto error3; |
109 | } | |
110 | ||
111 | /* create or update the requested key and add it to the target | |
112 | * keyring */ | |
664cceb0 | 113 | key_ref = key_create_or_update(keyring_ref, type, description, |
7e047ef5 | 114 | payload, plen, KEY_ALLOC_IN_QUOTA); |
664cceb0 DH |
115 | if (!IS_ERR(key_ref)) { |
116 | ret = key_ref_to_ptr(key_ref)->serial; | |
117 | key_ref_put(key_ref); | |
1da177e4 LT |
118 | } |
119 | else { | |
664cceb0 | 120 | ret = PTR_ERR(key_ref); |
1da177e4 LT |
121 | } |
122 | ||
664cceb0 | 123 | key_ref_put(keyring_ref); |
1da177e4 | 124 | error3: |
38bbca6b DH |
125 | if (!vm) |
126 | kfree(payload); | |
127 | else | |
128 | vfree(payload); | |
1da177e4 LT |
129 | error2: |
130 | kfree(description); | |
131 | error: | |
132 | return ret; | |
133 | ||
134 | } /* end sys_add_key() */ | |
135 | ||
136 | /*****************************************************************************/ | |
137 | /* | |
138 | * search the process keyrings for a matching key | |
139 | * - nested keyrings may also be searched if they have Search permission | |
140 | * - if a key is found, it will be attached to the destination keyring if | |
141 | * there's one specified | |
142 | * - /sbin/request-key will be invoked if _callout_info is non-NULL | |
143 | * - the _callout_info string will be passed to /sbin/request-key | |
144 | * - if the _callout_info string is empty, it will be rendered as "-" | |
145 | * - implements request_key() | |
146 | */ | |
147 | asmlinkage long sys_request_key(const char __user *_type, | |
148 | const char __user *_description, | |
149 | const char __user *_callout_info, | |
150 | key_serial_t destringid) | |
151 | { | |
152 | struct key_type *ktype; | |
664cceb0 DH |
153 | struct key *key; |
154 | key_ref_t dest_ref; | |
1da177e4 | 155 | char type[32], *description, *callout_info; |
0cb409d9 | 156 | long ret; |
1da177e4 LT |
157 | |
158 | /* pull the type into kernel space */ | |
0cb409d9 | 159 | ret = key_get_type_from_user(type, _type, sizeof(type)); |
1da177e4 LT |
160 | if (ret < 0) |
161 | goto error; | |
1260f801 | 162 | |
1da177e4 | 163 | /* pull the description into kernel space */ |
0cb409d9 DA |
164 | description = strndup_user(_description, PAGE_SIZE); |
165 | if (IS_ERR(description)) { | |
166 | ret = PTR_ERR(description); | |
1da177e4 | 167 | goto error; |
0cb409d9 | 168 | } |
1da177e4 LT |
169 | |
170 | /* pull the callout info into kernel space */ | |
171 | callout_info = NULL; | |
172 | if (_callout_info) { | |
0cb409d9 DA |
173 | callout_info = strndup_user(_callout_info, PAGE_SIZE); |
174 | if (IS_ERR(callout_info)) { | |
175 | ret = PTR_ERR(callout_info); | |
1da177e4 | 176 | goto error2; |
0cb409d9 | 177 | } |
1da177e4 LT |
178 | } |
179 | ||
180 | /* get the destination keyring if specified */ | |
664cceb0 | 181 | dest_ref = NULL; |
1da177e4 | 182 | if (destringid) { |
664cceb0 DH |
183 | dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); |
184 | if (IS_ERR(dest_ref)) { | |
185 | ret = PTR_ERR(dest_ref); | |
1da177e4 LT |
186 | goto error3; |
187 | } | |
188 | } | |
189 | ||
190 | /* find the key type */ | |
191 | ktype = key_type_lookup(type); | |
192 | if (IS_ERR(ktype)) { | |
193 | ret = PTR_ERR(ktype); | |
194 | goto error4; | |
195 | } | |
196 | ||
197 | /* do the search */ | |
4e54f085 | 198 | key = request_key_and_link(ktype, description, callout_info, NULL, |
7e047ef5 DH |
199 | key_ref_to_ptr(dest_ref), |
200 | KEY_ALLOC_IN_QUOTA); | |
1da177e4 LT |
201 | if (IS_ERR(key)) { |
202 | ret = PTR_ERR(key); | |
203 | goto error5; | |
204 | } | |
205 | ||
1da177e4 LT |
206 | ret = key->serial; |
207 | ||
3e30148c | 208 | key_put(key); |
1da177e4 LT |
209 | error5: |
210 | key_type_put(ktype); | |
211 | error4: | |
664cceb0 | 212 | key_ref_put(dest_ref); |
1da177e4 LT |
213 | error3: |
214 | kfree(callout_info); | |
215 | error2: | |
216 | kfree(description); | |
217 | error: | |
218 | return ret; | |
219 | ||
220 | } /* end sys_request_key() */ | |
221 | ||
222 | /*****************************************************************************/ | |
223 | /* | |
224 | * get the ID of the specified process keyring | |
225 | * - the keyring must have search permission to be found | |
226 | * - implements keyctl(KEYCTL_GET_KEYRING_ID) | |
227 | */ | |
228 | long keyctl_get_keyring_ID(key_serial_t id, int create) | |
229 | { | |
664cceb0 | 230 | key_ref_t key_ref; |
1da177e4 LT |
231 | long ret; |
232 | ||
664cceb0 DH |
233 | key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH); |
234 | if (IS_ERR(key_ref)) { | |
235 | ret = PTR_ERR(key_ref); | |
1da177e4 LT |
236 | goto error; |
237 | } | |
238 | ||
664cceb0 DH |
239 | ret = key_ref_to_ptr(key_ref)->serial; |
240 | key_ref_put(key_ref); | |
1da177e4 LT |
241 | error: |
242 | return ret; | |
243 | ||
244 | } /* end keyctl_get_keyring_ID() */ | |
245 | ||
246 | /*****************************************************************************/ | |
247 | /* | |
248 | * join the session keyring | |
249 | * - implements keyctl(KEYCTL_JOIN_SESSION_KEYRING) | |
250 | */ | |
251 | long keyctl_join_session_keyring(const char __user *_name) | |
252 | { | |
253 | char *name; | |
0cb409d9 | 254 | long ret; |
1da177e4 LT |
255 | |
256 | /* fetch the name from userspace */ | |
257 | name = NULL; | |
258 | if (_name) { | |
0cb409d9 DA |
259 | name = strndup_user(_name, PAGE_SIZE); |
260 | if (IS_ERR(name)) { | |
261 | ret = PTR_ERR(name); | |
1da177e4 | 262 | goto error; |
0cb409d9 | 263 | } |
1da177e4 LT |
264 | } |
265 | ||
266 | /* join the session */ | |
267 | ret = join_session_keyring(name); | |
268 | ||
1da177e4 LT |
269 | error: |
270 | return ret; | |
271 | ||
272 | } /* end keyctl_join_session_keyring() */ | |
273 | ||
274 | /*****************************************************************************/ | |
275 | /* | |
276 | * update a key's data payload | |
277 | * - the key must be writable | |
278 | * - implements keyctl(KEYCTL_UPDATE) | |
279 | */ | |
280 | long keyctl_update_key(key_serial_t id, | |
281 | const void __user *_payload, | |
282 | size_t plen) | |
283 | { | |
664cceb0 | 284 | key_ref_t key_ref; |
1da177e4 LT |
285 | void *payload; |
286 | long ret; | |
287 | ||
288 | ret = -EINVAL; | |
289 | if (plen > PAGE_SIZE) | |
290 | goto error; | |
291 | ||
292 | /* pull the payload in if one was supplied */ | |
293 | payload = NULL; | |
294 | if (_payload) { | |
295 | ret = -ENOMEM; | |
296 | payload = kmalloc(plen, GFP_KERNEL); | |
297 | if (!payload) | |
298 | goto error; | |
299 | ||
300 | ret = -EFAULT; | |
301 | if (copy_from_user(payload, _payload, plen) != 0) | |
302 | goto error2; | |
303 | } | |
304 | ||
305 | /* find the target key (which must be writable) */ | |
664cceb0 DH |
306 | key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); |
307 | if (IS_ERR(key_ref)) { | |
308 | ret = PTR_ERR(key_ref); | |
1da177e4 LT |
309 | goto error2; |
310 | } | |
311 | ||
312 | /* update the key */ | |
664cceb0 | 313 | ret = key_update(key_ref, payload, plen); |
1da177e4 | 314 | |
664cceb0 | 315 | key_ref_put(key_ref); |
1da177e4 LT |
316 | error2: |
317 | kfree(payload); | |
318 | error: | |
319 | return ret; | |
320 | ||
321 | } /* end keyctl_update_key() */ | |
322 | ||
323 | /*****************************************************************************/ | |
324 | /* | |
325 | * revoke a key | |
326 | * - the key must be writable | |
327 | * - implements keyctl(KEYCTL_REVOKE) | |
328 | */ | |
329 | long keyctl_revoke_key(key_serial_t id) | |
330 | { | |
664cceb0 | 331 | key_ref_t key_ref; |
1da177e4 LT |
332 | long ret; |
333 | ||
664cceb0 DH |
334 | key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE); |
335 | if (IS_ERR(key_ref)) { | |
336 | ret = PTR_ERR(key_ref); | |
1da177e4 LT |
337 | goto error; |
338 | } | |
339 | ||
664cceb0 | 340 | key_revoke(key_ref_to_ptr(key_ref)); |
1da177e4 LT |
341 | ret = 0; |
342 | ||
664cceb0 | 343 | key_ref_put(key_ref); |
1da177e4 | 344 | error: |
1260f801 | 345 | return ret; |
1da177e4 LT |
346 | |
347 | } /* end keyctl_revoke_key() */ | |
348 | ||
349 | /*****************************************************************************/ | |
350 | /* | |
351 | * clear the specified process keyring | |
352 | * - the keyring must be writable | |
353 | * - implements keyctl(KEYCTL_CLEAR) | |
354 | */ | |
355 | long keyctl_keyring_clear(key_serial_t ringid) | |
356 | { | |
664cceb0 | 357 | key_ref_t keyring_ref; |
1da177e4 LT |
358 | long ret; |
359 | ||
664cceb0 DH |
360 | keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
361 | if (IS_ERR(keyring_ref)) { | |
362 | ret = PTR_ERR(keyring_ref); | |
1da177e4 LT |
363 | goto error; |
364 | } | |
365 | ||
664cceb0 | 366 | ret = keyring_clear(key_ref_to_ptr(keyring_ref)); |
1da177e4 | 367 | |
664cceb0 | 368 | key_ref_put(keyring_ref); |
1da177e4 LT |
369 | error: |
370 | return ret; | |
371 | ||
372 | } /* end keyctl_keyring_clear() */ | |
373 | ||
374 | /*****************************************************************************/ | |
375 | /* | |
376 | * link a key into a keyring | |
377 | * - the keyring must be writable | |
378 | * - the key must be linkable | |
379 | * - implements keyctl(KEYCTL_LINK) | |
380 | */ | |
381 | long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |
382 | { | |
664cceb0 | 383 | key_ref_t keyring_ref, key_ref; |
1da177e4 LT |
384 | long ret; |
385 | ||
664cceb0 DH |
386 | keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
387 | if (IS_ERR(keyring_ref)) { | |
388 | ret = PTR_ERR(keyring_ref); | |
1da177e4 LT |
389 | goto error; |
390 | } | |
391 | ||
664cceb0 DH |
392 | key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK); |
393 | if (IS_ERR(key_ref)) { | |
394 | ret = PTR_ERR(key_ref); | |
1da177e4 LT |
395 | goto error2; |
396 | } | |
397 | ||
664cceb0 | 398 | ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); |
1da177e4 | 399 | |
664cceb0 | 400 | key_ref_put(key_ref); |
1da177e4 | 401 | error2: |
664cceb0 | 402 | key_ref_put(keyring_ref); |
1da177e4 LT |
403 | error: |
404 | return ret; | |
405 | ||
406 | } /* end keyctl_keyring_link() */ | |
407 | ||
408 | /*****************************************************************************/ | |
409 | /* | |
410 | * unlink the first attachment of a key from a keyring | |
411 | * - the keyring must be writable | |
412 | * - we don't need any permissions on the key | |
413 | * - implements keyctl(KEYCTL_UNLINK) | |
414 | */ | |
415 | long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |
416 | { | |
664cceb0 | 417 | key_ref_t keyring_ref, key_ref; |
1da177e4 LT |
418 | long ret; |
419 | ||
664cceb0 DH |
420 | keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE); |
421 | if (IS_ERR(keyring_ref)) { | |
422 | ret = PTR_ERR(keyring_ref); | |
1da177e4 LT |
423 | goto error; |
424 | } | |
425 | ||
664cceb0 DH |
426 | key_ref = lookup_user_key(NULL, id, 0, 0, 0); |
427 | if (IS_ERR(key_ref)) { | |
428 | ret = PTR_ERR(key_ref); | |
1da177e4 LT |
429 | goto error2; |
430 | } | |
431 | ||
664cceb0 | 432 | ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref)); |
1da177e4 | 433 | |
664cceb0 | 434 | key_ref_put(key_ref); |
1da177e4 | 435 | error2: |
664cceb0 | 436 | key_ref_put(keyring_ref); |
1da177e4 LT |
437 | error: |
438 | return ret; | |
439 | ||
440 | } /* end keyctl_keyring_unlink() */ | |
441 | ||
442 | /*****************************************************************************/ | |
443 | /* | |
444 | * describe a user key | |
445 | * - the key must have view permission | |
446 | * - if there's a buffer, we place up to buflen bytes of data into it | |
447 | * - unless there's an error, we return the amount of description available, | |
448 | * irrespective of how much we may have copied | |
449 | * - the description is formatted thus: | |
450 | * type;uid;gid;perm;description<NUL> | |
451 | * - implements keyctl(KEYCTL_DESCRIBE) | |
452 | */ | |
453 | long keyctl_describe_key(key_serial_t keyid, | |
454 | char __user *buffer, | |
455 | size_t buflen) | |
456 | { | |
3e30148c | 457 | struct key *key, *instkey; |
664cceb0 | 458 | key_ref_t key_ref; |
1da177e4 LT |
459 | char *tmpbuf; |
460 | long ret; | |
461 | ||
664cceb0 DH |
462 | key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW); |
463 | if (IS_ERR(key_ref)) { | |
3e30148c DH |
464 | /* viewing a key under construction is permitted if we have the |
465 | * authorisation token handy */ | |
664cceb0 | 466 | if (PTR_ERR(key_ref) == -EACCES) { |
3e30148c DH |
467 | instkey = key_get_instantiation_authkey(keyid); |
468 | if (!IS_ERR(instkey)) { | |
469 | key_put(instkey); | |
664cceb0 DH |
470 | key_ref = lookup_user_key(NULL, keyid, |
471 | 0, 1, 0); | |
472 | if (!IS_ERR(key_ref)) | |
3e30148c DH |
473 | goto okay; |
474 | } | |
475 | } | |
476 | ||
664cceb0 | 477 | ret = PTR_ERR(key_ref); |
1da177e4 LT |
478 | goto error; |
479 | } | |
480 | ||
3e30148c | 481 | okay: |
1da177e4 LT |
482 | /* calculate how much description we're going to return */ |
483 | ret = -ENOMEM; | |
484 | tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | |
485 | if (!tmpbuf) | |
486 | goto error2; | |
487 | ||
664cceb0 DH |
488 | key = key_ref_to_ptr(key_ref); |
489 | ||
1da177e4 | 490 | ret = snprintf(tmpbuf, PAGE_SIZE - 1, |
664cceb0 DH |
491 | "%s;%d;%d;%08x;%s", |
492 | key_ref_to_ptr(key_ref)->type->name, | |
493 | key_ref_to_ptr(key_ref)->uid, | |
494 | key_ref_to_ptr(key_ref)->gid, | |
495 | key_ref_to_ptr(key_ref)->perm, | |
496 | key_ref_to_ptr(key_ref)->description ? | |
497 | key_ref_to_ptr(key_ref)->description : "" | |
1da177e4 LT |
498 | ); |
499 | ||
500 | /* include a NUL char at the end of the data */ | |
501 | if (ret > PAGE_SIZE - 1) | |
502 | ret = PAGE_SIZE - 1; | |
503 | tmpbuf[ret] = 0; | |
504 | ret++; | |
505 | ||
506 | /* consider returning the data */ | |
507 | if (buffer && buflen > 0) { | |
508 | if (buflen > ret) | |
509 | buflen = ret; | |
510 | ||
511 | if (copy_to_user(buffer, tmpbuf, buflen) != 0) | |
512 | ret = -EFAULT; | |
513 | } | |
514 | ||
515 | kfree(tmpbuf); | |
516 | error2: | |
664cceb0 | 517 | key_ref_put(key_ref); |
1da177e4 LT |
518 | error: |
519 | return ret; | |
520 | ||
521 | } /* end keyctl_describe_key() */ | |
522 | ||
523 | /*****************************************************************************/ | |
524 | /* | |
525 | * search the specified keyring for a matching key | |
526 | * - the start keyring must be searchable | |
527 | * - nested keyrings may also be searched if they are searchable | |
528 | * - only keys with search permission may be found | |
529 | * - if a key is found, it will be attached to the destination keyring if | |
530 | * there's one specified | |
531 | * - implements keyctl(KEYCTL_SEARCH) | |
532 | */ | |
533 | long keyctl_keyring_search(key_serial_t ringid, | |
534 | const char __user *_type, | |
535 | const char __user *_description, | |
536 | key_serial_t destringid) | |
537 | { | |
538 | struct key_type *ktype; | |
664cceb0 | 539 | key_ref_t keyring_ref, key_ref, dest_ref; |
1da177e4 | 540 | char type[32], *description; |
0cb409d9 | 541 | long ret; |
1da177e4 LT |
542 | |
543 | /* pull the type and description into kernel space */ | |
0cb409d9 | 544 | ret = key_get_type_from_user(type, _type, sizeof(type)); |
1da177e4 LT |
545 | if (ret < 0) |
546 | goto error; | |
1da177e4 | 547 | |
0cb409d9 DA |
548 | description = strndup_user(_description, PAGE_SIZE); |
549 | if (IS_ERR(description)) { | |
550 | ret = PTR_ERR(description); | |
1da177e4 | 551 | goto error; |
0cb409d9 | 552 | } |
1da177e4 LT |
553 | |
554 | /* get the keyring at which to begin the search */ | |
664cceb0 DH |
555 | keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH); |
556 | if (IS_ERR(keyring_ref)) { | |
557 | ret = PTR_ERR(keyring_ref); | |
1da177e4 LT |
558 | goto error2; |
559 | } | |
560 | ||
561 | /* get the destination keyring if specified */ | |
664cceb0 | 562 | dest_ref = NULL; |
1da177e4 | 563 | if (destringid) { |
664cceb0 DH |
564 | dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE); |
565 | if (IS_ERR(dest_ref)) { | |
566 | ret = PTR_ERR(dest_ref); | |
1da177e4 LT |
567 | goto error3; |
568 | } | |
569 | } | |
570 | ||
571 | /* find the key type */ | |
572 | ktype = key_type_lookup(type); | |
573 | if (IS_ERR(ktype)) { | |
574 | ret = PTR_ERR(ktype); | |
575 | goto error4; | |
576 | } | |
577 | ||
578 | /* do the search */ | |
664cceb0 DH |
579 | key_ref = keyring_search(keyring_ref, ktype, description); |
580 | if (IS_ERR(key_ref)) { | |
581 | ret = PTR_ERR(key_ref); | |
1da177e4 LT |
582 | |
583 | /* treat lack or presence of a negative key the same */ | |
584 | if (ret == -EAGAIN) | |
585 | ret = -ENOKEY; | |
586 | goto error5; | |
587 | } | |
588 | ||
589 | /* link the resulting key to the destination keyring if we can */ | |
664cceb0 | 590 | if (dest_ref) { |
29db9190 DH |
591 | ret = key_permission(key_ref, KEY_LINK); |
592 | if (ret < 0) | |
1da177e4 LT |
593 | goto error6; |
594 | ||
664cceb0 | 595 | ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref)); |
1da177e4 LT |
596 | if (ret < 0) |
597 | goto error6; | |
598 | } | |
599 | ||
664cceb0 | 600 | ret = key_ref_to_ptr(key_ref)->serial; |
1da177e4 LT |
601 | |
602 | error6: | |
664cceb0 | 603 | key_ref_put(key_ref); |
1da177e4 LT |
604 | error5: |
605 | key_type_put(ktype); | |
606 | error4: | |
664cceb0 | 607 | key_ref_put(dest_ref); |
1da177e4 | 608 | error3: |
664cceb0 | 609 | key_ref_put(keyring_ref); |
1da177e4 LT |
610 | error2: |
611 | kfree(description); | |
612 | error: | |
613 | return ret; | |
614 | ||
615 | } /* end keyctl_keyring_search() */ | |
616 | ||
1da177e4 LT |
617 | /*****************************************************************************/ |
618 | /* | |
619 | * read a user key's payload | |
620 | * - the keyring must be readable or the key must be searchable from the | |
621 | * process's keyrings | |
622 | * - if there's a buffer, we place up to buflen bytes of data into it | |
623 | * - unless there's an error, we return the amount of data in the key, | |
624 | * irrespective of how much we may have copied | |
625 | * - implements keyctl(KEYCTL_READ) | |
626 | */ | |
627 | long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |
628 | { | |
664cceb0 DH |
629 | struct key *key; |
630 | key_ref_t key_ref; | |
1da177e4 LT |
631 | long ret; |
632 | ||
633 | /* find the key first */ | |
664cceb0 DH |
634 | key_ref = lookup_user_key(NULL, keyid, 0, 0, 0); |
635 | if (IS_ERR(key_ref)) { | |
636 | ret = -ENOKEY; | |
637 | goto error; | |
1da177e4 LT |
638 | } |
639 | ||
664cceb0 DH |
640 | key = key_ref_to_ptr(key_ref); |
641 | ||
642 | /* see if we can read it directly */ | |
29db9190 DH |
643 | ret = key_permission(key_ref, KEY_READ); |
644 | if (ret == 0) | |
664cceb0 | 645 | goto can_read_key; |
29db9190 DH |
646 | if (ret != -EACCES) |
647 | goto error; | |
664cceb0 DH |
648 | |
649 | /* we can't; see if it's searchable from this process's keyrings | |
650 | * - we automatically take account of the fact that it may be | |
651 | * dangling off an instantiation key | |
652 | */ | |
653 | if (!is_key_possessed(key_ref)) { | |
654 | ret = -EACCES; | |
655 | goto error2; | |
656 | } | |
1da177e4 LT |
657 | |
658 | /* the key is probably readable - now try to read it */ | |
1da177e4 LT |
659 | can_read_key: |
660 | ret = key_validate(key); | |
661 | if (ret == 0) { | |
662 | ret = -EOPNOTSUPP; | |
663 | if (key->type->read) { | |
664 | /* read the data with the semaphore held (since we | |
665 | * might sleep) */ | |
666 | down_read(&key->sem); | |
667 | ret = key->type->read(key, buffer, buflen); | |
668 | up_read(&key->sem); | |
669 | } | |
670 | } | |
671 | ||
672 | error2: | |
673 | key_put(key); | |
674 | error: | |
675 | return ret; | |
676 | ||
677 | } /* end keyctl_read_key() */ | |
678 | ||
679 | /*****************************************************************************/ | |
680 | /* | |
681 | * change the ownership of a key | |
682 | * - the keyring owned by the changer | |
683 | * - if the uid or gid is -1, then that parameter is not changed | |
684 | * - implements keyctl(KEYCTL_CHOWN) | |
685 | */ | |
686 | long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |
687 | { | |
5801649d | 688 | struct key_user *newowner, *zapowner = NULL; |
1da177e4 | 689 | struct key *key; |
664cceb0 | 690 | key_ref_t key_ref; |
1da177e4 LT |
691 | long ret; |
692 | ||
693 | ret = 0; | |
694 | if (uid == (uid_t) -1 && gid == (gid_t) -1) | |
695 | goto error; | |
696 | ||
29db9190 | 697 | key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); |
664cceb0 DH |
698 | if (IS_ERR(key_ref)) { |
699 | ret = PTR_ERR(key_ref); | |
1da177e4 LT |
700 | goto error; |
701 | } | |
702 | ||
664cceb0 DH |
703 | key = key_ref_to_ptr(key_ref); |
704 | ||
1da177e4 LT |
705 | /* make the changes with the locks held to prevent chown/chown races */ |
706 | ret = -EACCES; | |
707 | down_write(&key->sem); | |
1da177e4 LT |
708 | |
709 | if (!capable(CAP_SYS_ADMIN)) { | |
710 | /* only the sysadmin can chown a key to some other UID */ | |
711 | if (uid != (uid_t) -1 && key->uid != uid) | |
5801649d | 712 | goto error_put; |
1da177e4 LT |
713 | |
714 | /* only the sysadmin can set the key's GID to a group other | |
715 | * than one of those that the current process subscribes to */ | |
716 | if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) | |
5801649d | 717 | goto error_put; |
1da177e4 LT |
718 | } |
719 | ||
5801649d | 720 | /* change the UID */ |
1da177e4 | 721 | if (uid != (uid_t) -1 && uid != key->uid) { |
5801649d FT |
722 | ret = -ENOMEM; |
723 | newowner = key_user_lookup(uid); | |
724 | if (!newowner) | |
725 | goto error_put; | |
726 | ||
727 | /* transfer the quota burden to the new user */ | |
728 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | |
729 | spin_lock(&newowner->lock); | |
730 | if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || | |
731 | newowner->qnbytes + key->quotalen >= | |
732 | KEYQUOTA_MAX_BYTES) | |
733 | goto quota_overrun; | |
734 | ||
735 | newowner->qnkeys++; | |
736 | newowner->qnbytes += key->quotalen; | |
737 | spin_unlock(&newowner->lock); | |
738 | ||
739 | spin_lock(&key->user->lock); | |
740 | key->user->qnkeys--; | |
741 | key->user->qnbytes -= key->quotalen; | |
742 | spin_unlock(&key->user->lock); | |
743 | } | |
744 | ||
745 | atomic_dec(&key->user->nkeys); | |
746 | atomic_inc(&newowner->nkeys); | |
747 | ||
748 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { | |
749 | atomic_dec(&key->user->nikeys); | |
750 | atomic_inc(&newowner->nikeys); | |
751 | } | |
752 | ||
753 | zapowner = key->user; | |
754 | key->user = newowner; | |
755 | key->uid = uid; | |
1da177e4 LT |
756 | } |
757 | ||
758 | /* change the GID */ | |
759 | if (gid != (gid_t) -1) | |
760 | key->gid = gid; | |
761 | ||
762 | ret = 0; | |
763 | ||
5801649d | 764 | error_put: |
1da177e4 LT |
765 | up_write(&key->sem); |
766 | key_put(key); | |
5801649d FT |
767 | if (zapowner) |
768 | key_user_put(zapowner); | |
769 | error: | |
1da177e4 LT |
770 | return ret; |
771 | ||
5801649d FT |
772 | quota_overrun: |
773 | spin_unlock(&newowner->lock); | |
774 | zapowner = newowner; | |
775 | ret = -EDQUOT; | |
776 | goto error_put; | |
777 | ||
1da177e4 LT |
778 | } /* end keyctl_chown_key() */ |
779 | ||
780 | /*****************************************************************************/ | |
781 | /* | |
782 | * change the permission mask on a key | |
783 | * - the keyring owned by the changer | |
784 | * - implements keyctl(KEYCTL_SETPERM) | |
785 | */ | |
786 | long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |
787 | { | |
788 | struct key *key; | |
664cceb0 | 789 | key_ref_t key_ref; |
1da177e4 LT |
790 | long ret; |
791 | ||
792 | ret = -EINVAL; | |
664cceb0 | 793 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) |
1da177e4 LT |
794 | goto error; |
795 | ||
29db9190 | 796 | key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); |
664cceb0 DH |
797 | if (IS_ERR(key_ref)) { |
798 | ret = PTR_ERR(key_ref); | |
1da177e4 LT |
799 | goto error; |
800 | } | |
801 | ||
664cceb0 DH |
802 | key = key_ref_to_ptr(key_ref); |
803 | ||
76d8aeab | 804 | /* make the changes with the locks held to prevent chown/chmod races */ |
1da177e4 LT |
805 | ret = -EACCES; |
806 | down_write(&key->sem); | |
1da177e4 | 807 | |
76d8aeab DH |
808 | /* if we're not the sysadmin, we can only change a key that we own */ |
809 | if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) { | |
810 | key->perm = perm; | |
811 | ret = 0; | |
812 | } | |
1da177e4 | 813 | |
1da177e4 LT |
814 | up_write(&key->sem); |
815 | key_put(key); | |
76d8aeab | 816 | error: |
1da177e4 LT |
817 | return ret; |
818 | ||
819 | } /* end keyctl_setperm_key() */ | |
820 | ||
821 | /*****************************************************************************/ | |
822 | /* | |
823 | * instantiate the key with the specified payload, and, if one is given, link | |
824 | * the key into the keyring | |
825 | */ | |
826 | long keyctl_instantiate_key(key_serial_t id, | |
827 | const void __user *_payload, | |
828 | size_t plen, | |
829 | key_serial_t ringid) | |
830 | { | |
3e30148c | 831 | struct request_key_auth *rka; |
664cceb0 DH |
832 | struct key *instkey; |
833 | key_ref_t keyring_ref; | |
1da177e4 LT |
834 | void *payload; |
835 | long ret; | |
38bbca6b | 836 | bool vm = false; |
1da177e4 LT |
837 | |
838 | ret = -EINVAL; | |
38bbca6b | 839 | if (plen > 1024 * 1024 - 1) |
1da177e4 LT |
840 | goto error; |
841 | ||
b5f545c8 DH |
842 | /* the appropriate instantiation authorisation key must have been |
843 | * assumed before calling this */ | |
844 | ret = -EPERM; | |
845 | instkey = current->request_key_auth; | |
846 | if (!instkey) | |
847 | goto error; | |
848 | ||
849 | rka = instkey->payload.data; | |
850 | if (rka->target_key->serial != id) | |
851 | goto error; | |
852 | ||
1da177e4 LT |
853 | /* pull the payload in if one was supplied */ |
854 | payload = NULL; | |
855 | ||
856 | if (_payload) { | |
857 | ret = -ENOMEM; | |
858 | payload = kmalloc(plen, GFP_KERNEL); | |
38bbca6b DH |
859 | if (!payload) { |
860 | if (plen <= PAGE_SIZE) | |
861 | goto error; | |
862 | vm = true; | |
863 | payload = vmalloc(plen); | |
864 | if (!payload) | |
865 | goto error; | |
866 | } | |
1da177e4 LT |
867 | |
868 | ret = -EFAULT; | |
869 | if (copy_from_user(payload, _payload, plen) != 0) | |
870 | goto error2; | |
871 | } | |
872 | ||
3e30148c DH |
873 | /* find the destination keyring amongst those belonging to the |
874 | * requesting task */ | |
664cceb0 | 875 | keyring_ref = NULL; |
1da177e4 | 876 | if (ringid) { |
664cceb0 DH |
877 | keyring_ref = lookup_user_key(rka->context, ringid, 1, 0, |
878 | KEY_WRITE); | |
879 | if (IS_ERR(keyring_ref)) { | |
880 | ret = PTR_ERR(keyring_ref); | |
b5f545c8 | 881 | goto error2; |
1da177e4 LT |
882 | } |
883 | } | |
884 | ||
885 | /* instantiate the key and link it into a keyring */ | |
3e30148c | 886 | ret = key_instantiate_and_link(rka->target_key, payload, plen, |
664cceb0 | 887 | key_ref_to_ptr(keyring_ref), instkey); |
1da177e4 | 888 | |
664cceb0 | 889 | key_ref_put(keyring_ref); |
b5f545c8 DH |
890 | |
891 | /* discard the assumed authority if it's just been disabled by | |
892 | * instantiation of the key */ | |
893 | if (ret == 0) { | |
894 | key_put(current->request_key_auth); | |
895 | current->request_key_auth = NULL; | |
896 | } | |
897 | ||
898 | error2: | |
38bbca6b DH |
899 | if (!vm) |
900 | kfree(payload); | |
901 | else | |
902 | vfree(payload); | |
b5f545c8 | 903 | error: |
1da177e4 LT |
904 | return ret; |
905 | ||
906 | } /* end keyctl_instantiate_key() */ | |
907 | ||
908 | /*****************************************************************************/ | |
909 | /* | |
910 | * negatively instantiate the key with the given timeout (in seconds), and, if | |
911 | * one is given, link the key into the keyring | |
912 | */ | |
913 | long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | |
914 | { | |
3e30148c | 915 | struct request_key_auth *rka; |
664cceb0 DH |
916 | struct key *instkey; |
917 | key_ref_t keyring_ref; | |
1da177e4 LT |
918 | long ret; |
919 | ||
b5f545c8 DH |
920 | /* the appropriate instantiation authorisation key must have been |
921 | * assumed before calling this */ | |
922 | ret = -EPERM; | |
923 | instkey = current->request_key_auth; | |
924 | if (!instkey) | |
1da177e4 | 925 | goto error; |
1da177e4 | 926 | |
3e30148c | 927 | rka = instkey->payload.data; |
b5f545c8 DH |
928 | if (rka->target_key->serial != id) |
929 | goto error; | |
3e30148c | 930 | |
1da177e4 LT |
931 | /* find the destination keyring if present (which must also be |
932 | * writable) */ | |
664cceb0 | 933 | keyring_ref = NULL; |
1da177e4 | 934 | if (ringid) { |
664cceb0 DH |
935 | keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
936 | if (IS_ERR(keyring_ref)) { | |
937 | ret = PTR_ERR(keyring_ref); | |
b5f545c8 | 938 | goto error; |
1da177e4 LT |
939 | } |
940 | } | |
941 | ||
942 | /* instantiate the key and link it into a keyring */ | |
664cceb0 DH |
943 | ret = key_negate_and_link(rka->target_key, timeout, |
944 | key_ref_to_ptr(keyring_ref), instkey); | |
1da177e4 | 945 | |
664cceb0 | 946 | key_ref_put(keyring_ref); |
b5f545c8 DH |
947 | |
948 | /* discard the assumed authority if it's just been disabled by | |
949 | * instantiation of the key */ | |
950 | if (ret == 0) { | |
951 | key_put(current->request_key_auth); | |
952 | current->request_key_auth = NULL; | |
953 | } | |
954 | ||
955 | error: | |
1da177e4 LT |
956 | return ret; |
957 | ||
958 | } /* end keyctl_negate_key() */ | |
959 | ||
3e30148c DH |
960 | /*****************************************************************************/ |
961 | /* | |
962 | * set the default keyring in which request_key() will cache keys | |
963 | * - return the old setting | |
964 | */ | |
965 | long keyctl_set_reqkey_keyring(int reqkey_defl) | |
966 | { | |
967 | int ret; | |
968 | ||
969 | switch (reqkey_defl) { | |
970 | case KEY_REQKEY_DEFL_THREAD_KEYRING: | |
971 | ret = install_thread_keyring(current); | |
972 | if (ret < 0) | |
973 | return ret; | |
974 | goto set; | |
975 | ||
976 | case KEY_REQKEY_DEFL_PROCESS_KEYRING: | |
977 | ret = install_process_keyring(current); | |
978 | if (ret < 0) | |
979 | return ret; | |
980 | ||
981 | case KEY_REQKEY_DEFL_DEFAULT: | |
982 | case KEY_REQKEY_DEFL_SESSION_KEYRING: | |
983 | case KEY_REQKEY_DEFL_USER_KEYRING: | |
984 | case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: | |
985 | set: | |
986 | current->jit_keyring = reqkey_defl; | |
987 | ||
988 | case KEY_REQKEY_DEFL_NO_CHANGE: | |
989 | return current->jit_keyring; | |
990 | ||
991 | case KEY_REQKEY_DEFL_GROUP_KEYRING: | |
992 | default: | |
993 | return -EINVAL; | |
994 | } | |
995 | ||
996 | } /* end keyctl_set_reqkey_keyring() */ | |
997 | ||
017679c4 DH |
998 | /*****************************************************************************/ |
999 | /* | |
1000 | * set or clear the timeout for a key | |
1001 | */ | |
1002 | long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |
1003 | { | |
1004 | struct timespec now; | |
1005 | struct key *key; | |
1006 | key_ref_t key_ref; | |
1007 | time_t expiry; | |
1008 | long ret; | |
1009 | ||
1010 | key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); | |
1011 | if (IS_ERR(key_ref)) { | |
1012 | ret = PTR_ERR(key_ref); | |
1013 | goto error; | |
1014 | } | |
1015 | ||
1016 | key = key_ref_to_ptr(key_ref); | |
1017 | ||
1018 | /* make the changes with the locks held to prevent races */ | |
1019 | down_write(&key->sem); | |
1020 | ||
1021 | expiry = 0; | |
1022 | if (timeout > 0) { | |
1023 | now = current_kernel_time(); | |
1024 | expiry = now.tv_sec + timeout; | |
1025 | } | |
1026 | ||
1027 | key->expiry = expiry; | |
1028 | ||
1029 | up_write(&key->sem); | |
1030 | key_put(key); | |
1031 | ||
1032 | ret = 0; | |
1033 | error: | |
1034 | return ret; | |
1035 | ||
1036 | } /* end keyctl_set_timeout() */ | |
1037 | ||
b5f545c8 DH |
1038 | /*****************************************************************************/ |
1039 | /* | |
1040 | * assume the authority to instantiate the specified key | |
1041 | */ | |
1042 | long keyctl_assume_authority(key_serial_t id) | |
1043 | { | |
1044 | struct key *authkey; | |
1045 | long ret; | |
1046 | ||
1047 | /* special key IDs aren't permitted */ | |
1048 | ret = -EINVAL; | |
1049 | if (id < 0) | |
1050 | goto error; | |
1051 | ||
1052 | /* we divest ourselves of authority if given an ID of 0 */ | |
1053 | if (id == 0) { | |
1054 | key_put(current->request_key_auth); | |
1055 | current->request_key_auth = NULL; | |
1056 | ret = 0; | |
1057 | goto error; | |
1058 | } | |
1059 | ||
1060 | /* attempt to assume the authority temporarily granted to us whilst we | |
1061 | * instantiate the specified key | |
1062 | * - the authorisation key must be in the current task's keyrings | |
1063 | * somewhere | |
1064 | */ | |
1065 | authkey = key_get_instantiation_authkey(id); | |
1066 | if (IS_ERR(authkey)) { | |
1067 | ret = PTR_ERR(authkey); | |
1068 | goto error; | |
1069 | } | |
1070 | ||
1071 | key_put(current->request_key_auth); | |
1072 | current->request_key_auth = authkey; | |
1073 | ret = authkey->serial; | |
1074 | ||
1075 | error: | |
1076 | return ret; | |
1077 | ||
1078 | } /* end keyctl_assume_authority() */ | |
1079 | ||
1da177e4 LT |
1080 | /*****************************************************************************/ |
1081 | /* | |
1082 | * the key control system call | |
1083 | */ | |
1084 | asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |
1085 | unsigned long arg4, unsigned long arg5) | |
1086 | { | |
1087 | switch (option) { | |
1088 | case KEYCTL_GET_KEYRING_ID: | |
1089 | return keyctl_get_keyring_ID((key_serial_t) arg2, | |
1090 | (int) arg3); | |
1091 | ||
1092 | case KEYCTL_JOIN_SESSION_KEYRING: | |
1093 | return keyctl_join_session_keyring((const char __user *) arg2); | |
1094 | ||
1095 | case KEYCTL_UPDATE: | |
1096 | return keyctl_update_key((key_serial_t) arg2, | |
1097 | (const void __user *) arg3, | |
1098 | (size_t) arg4); | |
1099 | ||
1100 | case KEYCTL_REVOKE: | |
1101 | return keyctl_revoke_key((key_serial_t) arg2); | |
1102 | ||
1103 | case KEYCTL_DESCRIBE: | |
1104 | return keyctl_describe_key((key_serial_t) arg2, | |
1105 | (char __user *) arg3, | |
1106 | (unsigned) arg4); | |
1107 | ||
1108 | case KEYCTL_CLEAR: | |
1109 | return keyctl_keyring_clear((key_serial_t) arg2); | |
1110 | ||
1111 | case KEYCTL_LINK: | |
1112 | return keyctl_keyring_link((key_serial_t) arg2, | |
1113 | (key_serial_t) arg3); | |
1114 | ||
1115 | case KEYCTL_UNLINK: | |
1116 | return keyctl_keyring_unlink((key_serial_t) arg2, | |
1117 | (key_serial_t) arg3); | |
1118 | ||
1119 | case KEYCTL_SEARCH: | |
1120 | return keyctl_keyring_search((key_serial_t) arg2, | |
1121 | (const char __user *) arg3, | |
1122 | (const char __user *) arg4, | |
1123 | (key_serial_t) arg5); | |
1124 | ||
1125 | case KEYCTL_READ: | |
1126 | return keyctl_read_key((key_serial_t) arg2, | |
1127 | (char __user *) arg3, | |
1128 | (size_t) arg4); | |
1129 | ||
1130 | case KEYCTL_CHOWN: | |
1131 | return keyctl_chown_key((key_serial_t) arg2, | |
1132 | (uid_t) arg3, | |
1133 | (gid_t) arg4); | |
1134 | ||
1135 | case KEYCTL_SETPERM: | |
1136 | return keyctl_setperm_key((key_serial_t) arg2, | |
1137 | (key_perm_t) arg3); | |
1138 | ||
1139 | case KEYCTL_INSTANTIATE: | |
1140 | return keyctl_instantiate_key((key_serial_t) arg2, | |
1141 | (const void __user *) arg3, | |
1142 | (size_t) arg4, | |
1143 | (key_serial_t) arg5); | |
1144 | ||
1145 | case KEYCTL_NEGATE: | |
1146 | return keyctl_negate_key((key_serial_t) arg2, | |
1147 | (unsigned) arg3, | |
1148 | (key_serial_t) arg4); | |
1149 | ||
3e30148c DH |
1150 | case KEYCTL_SET_REQKEY_KEYRING: |
1151 | return keyctl_set_reqkey_keyring(arg2); | |
1152 | ||
017679c4 DH |
1153 | case KEYCTL_SET_TIMEOUT: |
1154 | return keyctl_set_timeout((key_serial_t) arg2, | |
1155 | (unsigned) arg3); | |
1156 | ||
b5f545c8 DH |
1157 | case KEYCTL_ASSUME_AUTHORITY: |
1158 | return keyctl_assume_authority((key_serial_t) arg2); | |
1159 | ||
1da177e4 LT |
1160 | default: |
1161 | return -EOPNOTSUPP; | |
1162 | } | |
1163 | ||
1164 | } /* end sys_keyctl() */ |