Blame view
security/keys/request_key.c
19.6 KB
76181c134 KEYS: Make reques... |
1 |
/* Request a key from userspace |
1da177e4c Linux-2.6.12-rc2 |
2 |
* |
76181c134 KEYS: Make reques... |
3 |
* Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. |
1da177e4c Linux-2.6.12-rc2 |
4 5 6 7 8 9 |
* Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. |
f1a9badcf [PATCH] Keys: Add... |
10 |
* |
d410fa4ef Create Documentat... |
11 |
* See Documentation/security/keys-request-key.txt |
1da177e4c Linux-2.6.12-rc2 |
12 13 14 15 16 17 |
*/ #include <linux/module.h> #include <linux/sched.h> #include <linux/kmod.h> #include <linux/err.h> |
3e30148c3 [PATCH] Keys: Mak... |
18 |
#include <linux/keyctl.h> |
fdb89bce6 keys: explicitly ... |
19 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
20 |
#include "internal.h" |
e9e349b05 KEYS: Disperse li... |
21 |
#define key_negative_timeout 60 /* default timeout on a negative key's existence */ |
973c9f4f4 KEYS: Fix up comm... |
22 23 24 25 26 27 28 29 |
/** * complete_request_key - Complete the construction of a key. * @cons: The key construction record. * @error: The success or failute of the construction. * * Complete the attempt to construct a key. The key will be negated * if an error is indicated. The authorisation key will be revoked * unconditionally. |
76181c134 KEYS: Make reques... |
30 31 32 33 |
*/ void complete_request_key(struct key_construction *cons, int error) { kenter("{%d,%d},%d", cons->key->serial, cons->authkey->serial, error); |
1da177e4c Linux-2.6.12-rc2 |
34 |
|
76181c134 KEYS: Make reques... |
35 36 37 38 39 40 41 42 43 44 45 |
if (error < 0) key_negate_and_link(cons->key, key_negative_timeout, NULL, cons->authkey); else key_revoke(cons->authkey); key_put(cons->key); key_put(cons->authkey); kfree(cons); } EXPORT_SYMBOL(complete_request_key); |
1da177e4c Linux-2.6.12-rc2 |
46 |
|
973c9f4f4 KEYS: Fix up comm... |
47 48 49 50 51 52 53 |
/* * Initialise a usermode helper that is going to have a specific session * keyring. * * This is called in context of freshly forked kthread before kernel_execve(), * so we can simply install the desired session_keyring at this point. */ |
879669961 KEYS/DNS: Fix ___... |
54 |
static int umh_keys_init(struct subprocess_info *info, struct cred *cred) |
685bfd2c4 umh: creds: conve... |
55 |
{ |
685bfd2c4 umh: creds: conve... |
56 |
struct key *keyring = info->data; |
973c9f4f4 KEYS: Fix up comm... |
57 |
|
685bfd2c4 umh: creds: conve... |
58 59 |
return install_session_keyring_to_cred(cred, keyring); } |
973c9f4f4 KEYS: Fix up comm... |
60 61 62 |
/* * Clean up a usermode helper with session keyring. */ |
685bfd2c4 umh: creds: conve... |
63 64 65 66 67 |
static void umh_keys_cleanup(struct subprocess_info *info) { struct key *keyring = info->data; key_put(keyring); } |
973c9f4f4 KEYS: Fix up comm... |
68 69 70 |
/* * Call a usermode helper with a specific session keyring. */ |
685bfd2c4 umh: creds: conve... |
71 |
static int call_usermodehelper_keys(char *path, char **argv, char **envp, |
9d944ef32 usermodehelper: k... |
72 |
struct key *session_keyring, int wait) |
685bfd2c4 umh: creds: conve... |
73 |
{ |
93997f6dd KEYS: split call ... |
74 75 76 77 78 79 80 81 82 83 |
struct subprocess_info *info; info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL, umh_keys_init, umh_keys_cleanup, session_keyring); if (!info) return -ENOMEM; key_get(session_keyring); return call_usermodehelper_exec(info, wait); |
685bfd2c4 umh: creds: conve... |
84 |
} |
1da177e4c Linux-2.6.12-rc2 |
85 |
/* |
973c9f4f4 KEYS: Fix up comm... |
86 |
* Request userspace finish the construction of a key |
b5f545c88 [PATCH] keys: Per... |
87 |
* - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" |
1da177e4c Linux-2.6.12-rc2 |
88 |
*/ |
76181c134 KEYS: Make reques... |
89 |
static int call_sbin_request_key(struct key_construction *cons, |
4e54f0854 [PATCH] Keys: All... |
90 91 |
const char *op, void *aux) |
1da177e4c Linux-2.6.12-rc2 |
92 |
{ |
86a264abe CRED: Wrap curren... |
93 |
const struct cred *cred = current_cred(); |
1da177e4c Linux-2.6.12-rc2 |
94 |
key_serial_t prkey, sskey; |
93b4a44f3 keys: fix an RCU ... |
95 96 |
struct key *key = cons->key, *authkey = cons->authkey, *keyring, *session; |
b5f545c88 [PATCH] keys: Per... |
97 |
char *argv[9], *envp[3], uid_str[12], gid_str[12]; |
1da177e4c Linux-2.6.12-rc2 |
98 |
char key_str[12], keyring_str[3][12]; |
b5f545c88 [PATCH] keys: Per... |
99 |
char desc[20]; |
3e30148c3 [PATCH] Keys: Mak... |
100 |
int ret, i; |
b5f545c88 [PATCH] keys: Per... |
101 |
kenter("{%d},{%d},%s", key->serial, authkey->serial, op); |
3e30148c3 [PATCH] Keys: Mak... |
102 |
|
8bbf4976b KEYS: Alter use o... |
103 104 105 |
ret = install_user_keyrings(); if (ret < 0) goto error_alloc; |
b5f545c88 [PATCH] keys: Per... |
106 107 |
/* allocate a new session keyring */ sprintf(desc, "_req.%u", key->serial); |
d84f4f992 CRED: Inaugurate ... |
108 109 |
cred = get_current_cred(); keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred, |
96b5c8fea KEYS: Reduce init... |
110 |
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ, |
7e047ef5f [PATCH] keys: sor... |
111 |
KEY_ALLOC_QUOTA_OVERRUN, NULL); |
d84f4f992 CRED: Inaugurate ... |
112 |
put_cred(cred); |
b5f545c88 [PATCH] keys: Per... |
113 114 115 |
if (IS_ERR(keyring)) { ret = PTR_ERR(keyring); goto error_alloc; |
3e30148c3 [PATCH] Keys: Mak... |
116 |
} |
1da177e4c Linux-2.6.12-rc2 |
117 |
|
b5f545c88 [PATCH] keys: Per... |
118 |
/* attach the auth key to the session keyring */ |
896903c2f KEYS: call_sbin_r... |
119 |
ret = key_link(keyring, authkey); |
b5f545c88 [PATCH] keys: Per... |
120 121 |
if (ret < 0) goto error_link; |
1da177e4c Linux-2.6.12-rc2 |
122 |
/* record the UID and GID */ |
9a56c2db4 userns: Convert s... |
123 124 |
sprintf(uid_str, "%d", from_kuid(&init_user_ns, cred->fsuid)); sprintf(gid_str, "%d", from_kgid(&init_user_ns, cred->fsgid)); |
1da177e4c Linux-2.6.12-rc2 |
125 126 127 128 129 130 |
/* we say which key is under construction */ sprintf(key_str, "%d", key->serial); /* we specify the process's default keyrings */ sprintf(keyring_str[0], "%d", |
d84f4f992 CRED: Inaugurate ... |
131 |
cred->thread_keyring ? cred->thread_keyring->serial : 0); |
1da177e4c Linux-2.6.12-rc2 |
132 133 |
prkey = 0; |
3a50597de KEYS: Make the se... |
134 135 |
if (cred->process_keyring) prkey = cred->process_keyring->serial; |
5ad18a0d5 KEYS: Reinstate l... |
136 |
sprintf(keyring_str[1], "%d", prkey); |
1da177e4c Linux-2.6.12-rc2 |
137 |
|
93b4a44f3 keys: fix an RCU ... |
138 |
rcu_read_lock(); |
3a50597de KEYS: Make the se... |
139 |
session = rcu_dereference(cred->session_keyring); |
93b4a44f3 keys: fix an RCU ... |
140 141 142 143 |
if (!session) session = cred->user->session_keyring; sskey = session->serial; rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
144 |
|
1da177e4c Linux-2.6.12-rc2 |
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
sprintf(keyring_str[2], "%d", sskey); /* set up a minimal environment */ i = 0; envp[i++] = "HOME=/"; envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; envp[i] = NULL; /* set up the argument list */ i = 0; argv[i++] = "/sbin/request-key"; argv[i++] = (char *) op; argv[i++] = key_str; argv[i++] = uid_str; argv[i++] = gid_str; argv[i++] = keyring_str[0]; argv[i++] = keyring_str[1]; argv[i++] = keyring_str[2]; |
1da177e4c Linux-2.6.12-rc2 |
163 164 165 |
argv[i] = NULL; /* do it */ |
86313c488 usermodehelper: T... |
166 167 |
ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, UMH_WAIT_PROC); |
76181c134 KEYS: Make reques... |
168 169 170 171 172 173 174 175 176 177 178 |
kdebug("usermode -> 0x%x", ret); if (ret >= 0) { /* ret is the exit/wait code */ if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) || key_validate(key) < 0) ret = -ENOKEY; else /* ignore any errors from userspace if the key was * instantiated */ ret = 0; } |
3e30148c3 [PATCH] Keys: Mak... |
179 |
|
b5f545c88 [PATCH] keys: Per... |
180 181 |
error_link: key_put(keyring); |
3e30148c3 [PATCH] Keys: Mak... |
182 |
|
b5f545c88 [PATCH] keys: Per... |
183 |
error_alloc: |
76181c134 KEYS: Make reques... |
184 |
complete_request_key(cons, ret); |
d84f4f992 CRED: Inaugurate ... |
185 |
kleave(" = %d", ret); |
3e30148c3 [PATCH] Keys: Mak... |
186 |
return ret; |
76181c134 KEYS: Make reques... |
187 |
} |
1da177e4c Linux-2.6.12-rc2 |
188 |
|
1da177e4c Linux-2.6.12-rc2 |
189 |
/* |
973c9f4f4 KEYS: Fix up comm... |
190 191 192 |
* Call out to userspace for key construction. * * Program failure is ignored in favour of key status. |
1da177e4c Linux-2.6.12-rc2 |
193 |
*/ |
4a38e122e keys: allow the c... |
194 |
static int construct_key(struct key *key, const void *callout_info, |
8bbf4976b KEYS: Alter use o... |
195 196 |
size_t callout_len, void *aux, struct key *dest_keyring) |
1da177e4c Linux-2.6.12-rc2 |
197 |
{ |
76181c134 KEYS: Make reques... |
198 |
struct key_construction *cons; |
b5f545c88 [PATCH] keys: Per... |
199 |
request_key_actor_t actor; |
76181c134 KEYS: Make reques... |
200 201 |
struct key *authkey; int ret; |
1da177e4c Linux-2.6.12-rc2 |
202 |
|
4a38e122e keys: allow the c... |
203 |
kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux); |
3e30148c3 [PATCH] Keys: Mak... |
204 |
|
76181c134 KEYS: Make reques... |
205 206 207 |
cons = kmalloc(sizeof(*cons), GFP_KERNEL); if (!cons) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
208 |
|
b5f545c88 [PATCH] keys: Per... |
209 |
/* allocate an authorisation key */ |
8bbf4976b KEYS: Alter use o... |
210 211 |
authkey = request_key_auth_new(key, callout_info, callout_len, dest_keyring); |
b5f545c88 [PATCH] keys: Per... |
212 |
if (IS_ERR(authkey)) { |
76181c134 KEYS: Make reques... |
213 |
kfree(cons); |
b5f545c88 [PATCH] keys: Per... |
214 215 |
ret = PTR_ERR(authkey); authkey = NULL; |
76181c134 KEYS: Make reques... |
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
} else { cons->authkey = key_get(authkey); cons->key = key_get(key); /* make the call */ actor = call_sbin_request_key; if (key->type->request_key) actor = key->type->request_key; ret = actor(cons, "create", aux); /* check that the actor called complete_request_key() prior to * returning an error */ WARN_ON(ret < 0 && !test_bit(KEY_FLAG_REVOKED, &authkey->flags)); key_put(authkey); |
1da177e4c Linux-2.6.12-rc2 |
232 |
} |
76181c134 KEYS: Make reques... |
233 234 235 |
kleave(" = %d", ret); return ret; } |
1da177e4c Linux-2.6.12-rc2 |
236 |
|
1da177e4c Linux-2.6.12-rc2 |
237 |
/* |
973c9f4f4 KEYS: Fix up comm... |
238 239 240 241 |
* Get the appropriate destination keyring for the request. * * The keyring selected is returned with an extra reference upon it which the * caller must release. |
3e30148c3 [PATCH] Keys: Mak... |
242 |
*/ |
8bbf4976b KEYS: Alter use o... |
243 |
static void construct_get_dest_keyring(struct key **_dest_keyring) |
3e30148c3 [PATCH] Keys: Mak... |
244 |
{ |
8bbf4976b KEYS: Alter use o... |
245 |
struct request_key_auth *rka; |
bb952bb98 CRED: Separate pe... |
246 |
const struct cred *cred = current_cred(); |
8bbf4976b KEYS: Alter use o... |
247 |
struct key *dest_keyring = *_dest_keyring, *authkey; |
3e30148c3 [PATCH] Keys: Mak... |
248 |
|
8bbf4976b KEYS: Alter use o... |
249 |
kenter("%p", dest_keyring); |
3e30148c3 [PATCH] Keys: Mak... |
250 251 |
/* find the appropriate keyring */ |
8bbf4976b KEYS: Alter use o... |
252 253 254 255 256 257 |
if (dest_keyring) { /* the caller supplied one */ key_get(dest_keyring); } else { /* use a default keyring; falling through the cases until we * find one that we actually have */ |
bb952bb98 CRED: Separate pe... |
258 |
switch (cred->jit_keyring) { |
3e30148c3 [PATCH] Keys: Mak... |
259 |
case KEY_REQKEY_DEFL_DEFAULT: |
8bbf4976b KEYS: Alter use o... |
260 |
case KEY_REQKEY_DEFL_REQUESTOR_KEYRING: |
bb952bb98 CRED: Separate pe... |
261 262 |
if (cred->request_key_auth) { authkey = cred->request_key_auth; |
8bbf4976b KEYS: Alter use o... |
263 264 265 266 267 268 269 270 271 272 |
down_read(&authkey->sem); rka = authkey->payload.data; if (!test_bit(KEY_FLAG_REVOKED, &authkey->flags)) dest_keyring = key_get(rka->dest_keyring); up_read(&authkey->sem); if (dest_keyring) break; } |
3e30148c3 [PATCH] Keys: Mak... |
273 |
case KEY_REQKEY_DEFL_THREAD_KEYRING: |
bb952bb98 CRED: Separate pe... |
274 |
dest_keyring = key_get(cred->thread_keyring); |
3e30148c3 [PATCH] Keys: Mak... |
275 276 277 278 |
if (dest_keyring) break; case KEY_REQKEY_DEFL_PROCESS_KEYRING: |
3a50597de KEYS: Make the se... |
279 |
dest_keyring = key_get(cred->process_keyring); |
3e30148c3 [PATCH] Keys: Mak... |
280 281 282 283 284 285 |
if (dest_keyring) break; case KEY_REQKEY_DEFL_SESSION_KEYRING: rcu_read_lock(); dest_keyring = key_get( |
3a50597de KEYS: Make the se... |
286 |
rcu_dereference(cred->session_keyring)); |
3e30148c3 [PATCH] Keys: Mak... |
287 |
rcu_read_unlock(); |
3e30148c3 [PATCH] Keys: Mak... |
288 289 290 291 292 |
if (dest_keyring) break; case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: |
b6dff3ec5 CRED: Separate ta... |
293 |
dest_keyring = |
bb952bb98 CRED: Separate pe... |
294 |
key_get(cred->user->session_keyring); |
3e30148c3 [PATCH] Keys: Mak... |
295 296 297 |
break; case KEY_REQKEY_DEFL_USER_KEYRING: |
bb952bb98 CRED: Separate pe... |
298 |
dest_keyring = key_get(cred->user->uid_keyring); |
3e30148c3 [PATCH] Keys: Mak... |
299 300 301 302 303 304 305 |
break; case KEY_REQKEY_DEFL_GROUP_KEYRING: default: BUG(); } } |
8bbf4976b KEYS: Alter use o... |
306 307 308 |
*_dest_keyring = dest_keyring; kleave(" [dk %d]", key_serial(dest_keyring)); return; |
76181c134 KEYS: Make reques... |
309 |
} |
3e30148c3 [PATCH] Keys: Mak... |
310 |
|
76181c134 KEYS: Make reques... |
311 |
/* |
973c9f4f4 KEYS: Fix up comm... |
312 313 314 315 316 |
* Allocate a new key in under-construction state and attempt to link it in to * the requested keyring. * * May return a key that's already under construction instead if there was a * race between two thread calling request_key(). |
76181c134 KEYS: Make reques... |
317 |
*/ |
4bdf0bc30 KEYS: Introduce a... |
318 |
static int construct_alloc_key(struct keyring_search_context *ctx, |
76181c134 KEYS: Make reques... |
319 320 321 322 323 |
struct key *dest_keyring, unsigned long flags, struct key_user *user, struct key **_key) { |
b2a4df200 KEYS: Expand the ... |
324 |
struct assoc_array_edit *edit; |
76181c134 KEYS: Make reques... |
325 |
struct key *key; |
96b5c8fea KEYS: Reduce init... |
326 |
key_perm_t perm; |
76181c134 KEYS: Make reques... |
327 |
key_ref_t key_ref; |
2b9e4688f KEYS: Better hand... |
328 |
int ret; |
76181c134 KEYS: Make reques... |
329 |
|
4bdf0bc30 KEYS: Introduce a... |
330 331 |
kenter("%s,%s,,,", ctx->index_key.type->name, ctx->index_key.description); |
76181c134 KEYS: Make reques... |
332 |
|
f70e2e061 KEYS: Do prealloc... |
333 |
*_key = NULL; |
76181c134 KEYS: Make reques... |
334 |
mutex_lock(&user->cons_lock); |
96b5c8fea KEYS: Reduce init... |
335 336 |
perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR; perm |= KEY_USR_VIEW; |
4bdf0bc30 KEYS: Introduce a... |
337 |
if (ctx->index_key.type->read) |
96b5c8fea KEYS: Reduce init... |
338 |
perm |= KEY_POS_READ; |
4bdf0bc30 KEYS: Introduce a... |
339 340 |
if (ctx->index_key.type == &key_type_keyring || ctx->index_key.type->update) |
96b5c8fea KEYS: Reduce init... |
341 |
perm |= KEY_POS_WRITE; |
4bdf0bc30 KEYS: Introduce a... |
342 343 |
key = key_alloc(ctx->index_key.type, ctx->index_key.description, ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred, |
96b5c8fea KEYS: Reduce init... |
344 |
perm, flags); |
76181c134 KEYS: Make reques... |
345 346 347 348 |
if (IS_ERR(key)) goto alloc_failed; set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags); |
f70e2e061 KEYS: Do prealloc... |
349 |
if (dest_keyring) { |
b2a4df200 KEYS: Expand the ... |
350 |
ret = __key_link_begin(dest_keyring, &ctx->index_key, &edit); |
f70e2e061 KEYS: Do prealloc... |
351 352 353 |
if (ret < 0) goto link_prealloc_failed; } |
76181c134 KEYS: Make reques... |
354 355 356 357 358 |
/* attach the key to the destination keyring under lock, but we do need * to do another check just in case someone beat us to it whilst we * waited for locks */ mutex_lock(&key_construction_mutex); |
4bdf0bc30 KEYS: Introduce a... |
359 |
key_ref = search_process_keyrings(ctx); |
76181c134 KEYS: Make reques... |
360 361 |
if (!IS_ERR(key_ref)) goto key_already_present; |
34574dd10 keys: Handle ther... |
362 |
if (dest_keyring) |
b2a4df200 KEYS: Expand the ... |
363 |
__key_link(key, &edit); |
76181c134 KEYS: Make reques... |
364 365 |
mutex_unlock(&key_construction_mutex); |
34574dd10 keys: Handle ther... |
366 |
if (dest_keyring) |
b2a4df200 KEYS: Expand the ... |
367 |
__key_link_end(dest_keyring, &ctx->index_key, edit); |
76181c134 KEYS: Make reques... |
368 369 370 371 |
mutex_unlock(&user->cons_lock); *_key = key; kleave(" = 0 [%d]", key_serial(key)); return 0; |
2b9e4688f KEYS: Better hand... |
372 373 |
/* the key is now present - we tell the caller that we found it by * returning -EINPROGRESS */ |
76181c134 KEYS: Make reques... |
374 |
key_already_present: |
f70e2e061 KEYS: Do prealloc... |
375 |
key_put(key); |
76181c134 KEYS: Make reques... |
376 |
mutex_unlock(&key_construction_mutex); |
f70e2e061 KEYS: Do prealloc... |
377 |
key = key_ref_to_ptr(key_ref); |
03449cd9e keys: the request... |
378 |
if (dest_keyring) { |
f70e2e061 KEYS: Do prealloc... |
379 380 |
ret = __key_link_check_live_key(dest_keyring, key); if (ret == 0) |
b2a4df200 KEYS: Expand the ... |
381 382 |
__key_link(key, &edit); __key_link_end(dest_keyring, &ctx->index_key, edit); |
f70e2e061 KEYS: Do prealloc... |
383 384 |
if (ret < 0) goto link_check_failed; |
03449cd9e keys: the request... |
385 |
} |
76181c134 KEYS: Make reques... |
386 |
mutex_unlock(&user->cons_lock); |
f70e2e061 KEYS: Do prealloc... |
387 |
*_key = key; |
76181c134 KEYS: Make reques... |
388 389 |
kleave(" = -EINPROGRESS [%d]", key_serial(key)); return -EINPROGRESS; |
f70e2e061 KEYS: Do prealloc... |
390 391 392 393 394 395 396 |
link_check_failed: mutex_unlock(&user->cons_lock); key_put(key); kleave(" = %d [linkcheck]", ret); return ret; link_prealloc_failed: |
f70e2e061 KEYS: Do prealloc... |
397 |
mutex_unlock(&user->cons_lock); |
d0709f1e6 Don't leak a key ... |
398 |
key_put(key); |
f70e2e061 KEYS: Do prealloc... |
399 400 |
kleave(" = %d [prelink]", ret); return ret; |
76181c134 KEYS: Make reques... |
401 402 |
alloc_failed: mutex_unlock(&user->cons_lock); |
76181c134 KEYS: Make reques... |
403 404 405 406 407 |
kleave(" = %ld", PTR_ERR(key)); return PTR_ERR(key); } /* |
973c9f4f4 KEYS: Fix up comm... |
408 |
* Commence key construction. |
76181c134 KEYS: Make reques... |
409 |
*/ |
4bdf0bc30 KEYS: Introduce a... |
410 |
static struct key *construct_key_and_link(struct keyring_search_context *ctx, |
76181c134 KEYS: Make reques... |
411 |
const char *callout_info, |
4a38e122e keys: allow the c... |
412 |
size_t callout_len, |
76181c134 KEYS: Make reques... |
413 414 415 416 417 418 419 |
void *aux, struct key *dest_keyring, unsigned long flags) { struct key_user *user; struct key *key; int ret; |
d84f4f992 CRED: Inaugurate ... |
420 |
kenter(""); |
9a56c2db4 userns: Convert s... |
421 |
user = key_user_lookup(current_fsuid()); |
76181c134 KEYS: Make reques... |
422 423 |
if (!user) return ERR_PTR(-ENOMEM); |
8bbf4976b KEYS: Alter use o... |
424 |
construct_get_dest_keyring(&dest_keyring); |
4bdf0bc30 KEYS: Introduce a... |
425 |
ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); |
76181c134 KEYS: Make reques... |
426 427 428 |
key_user_put(user); if (ret == 0) { |
8bbf4976b KEYS: Alter use o... |
429 430 |
ret = construct_key(key, callout_info, callout_len, aux, dest_keyring); |
d84f4f992 CRED: Inaugurate ... |
431 432 |
if (ret < 0) { kdebug("cons failed"); |
76181c134 KEYS: Make reques... |
433 |
goto construction_failed; |
d84f4f992 CRED: Inaugurate ... |
434 |
} |
2b9e4688f KEYS: Better hand... |
435 436 437 |
} else if (ret == -EINPROGRESS) { ret = 0; } else { |
b1d7dd80a KEYS: Fix error h... |
438 |
goto couldnt_alloc_key; |
76181c134 KEYS: Make reques... |
439 |
} |
8bbf4976b KEYS: Alter use o... |
440 |
key_put(dest_keyring); |
d84f4f992 CRED: Inaugurate ... |
441 |
kleave(" = key %d", key_serial(key)); |
76181c134 KEYS: Make reques... |
442 443 444 445 446 |
return key; construction_failed: key_negate_and_link(key, key_negative_timeout, NULL, NULL); key_put(key); |
b1d7dd80a KEYS: Fix error h... |
447 |
couldnt_alloc_key: |
8bbf4976b KEYS: Alter use o... |
448 |
key_put(dest_keyring); |
d84f4f992 CRED: Inaugurate ... |
449 |
kleave(" = %d", ret); |
76181c134 KEYS: Make reques... |
450 451 |
return ERR_PTR(ret); } |
3e30148c3 [PATCH] Keys: Mak... |
452 |
|
973c9f4f4 KEYS: Fix up comm... |
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
/** * request_key_and_link - Request a key and cache it in a keyring. * @type: The type of key we want. * @description: The searchable description of the key. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. * @dest_keyring: Where to cache the key. * @flags: Flags to key_alloc(). * * A key matching the specified criteria is searched for in the process's * keyrings and returned with its usage count incremented if found. Otherwise, * if callout_info is not NULL, a key will be allocated and some service * (probably in userspace) will be asked to instantiate it. * * If successfully found or created, the key will be linked to the destination * keyring if one is provided. * * Returns a pointer to the key if successful; -EACCES, -ENOKEY, -EKEYREVOKED * or -EKEYEXPIRED if an inaccessible, negative, revoked or expired key was * found; -ENOKEY if no key was found and no @callout_info was given; -EDQUOT * if insufficient key quota was available to create a new key; or -ENOMEM if * insufficient memory was available. * * If the returned key was created, then it may still be under construction, * and wait_for_key_construction() should be used to wait for that to complete. |
1da177e4c Linux-2.6.12-rc2 |
479 |
*/ |
3e30148c3 [PATCH] Keys: Mak... |
480 481 |
struct key *request_key_and_link(struct key_type *type, const char *description, |
4a38e122e keys: allow the c... |
482 483 |
const void *callout_info, size_t callout_len, |
4e54f0854 [PATCH] Keys: All... |
484 |
void *aux, |
7e047ef5f [PATCH] keys: sor... |
485 486 |
struct key *dest_keyring, unsigned long flags) |
1da177e4c Linux-2.6.12-rc2 |
487 |
{ |
4bdf0bc30 KEYS: Introduce a... |
488 489 490 491 |
struct keyring_search_context ctx = { .index_key.type = type, .index_key.description = description, .cred = current_cred(), |
c06cfb08b KEYS: Remove key_... |
492 |
.match_data.cmp = key_default_cmp, |
462919591 KEYS: Preparse ma... |
493 494 |
.match_data.raw_data = description, .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
0b0a84154 KEYS: request_key... |
495 496 |
.flags = (KEYRING_SEARCH_DO_STATE_CHECK | KEYRING_SEARCH_SKIP_EXPIRED), |
4bdf0bc30 KEYS: Introduce a... |
497 |
}; |
1da177e4c Linux-2.6.12-rc2 |
498 |
struct key *key; |
664cceb00 [PATCH] Keys: Add... |
499 |
key_ref_t key_ref; |
2b9e4688f KEYS: Better hand... |
500 |
int ret; |
1da177e4c Linux-2.6.12-rc2 |
501 |
|
4a38e122e keys: allow the c... |
502 |
kenter("%s,%s,%p,%zu,%p,%p,%lx", |
4bdf0bc30 KEYS: Introduce a... |
503 504 |
ctx.index_key.type->name, ctx.index_key.description, callout_info, callout_len, aux, dest_keyring, flags); |
3e30148c3 [PATCH] Keys: Mak... |
505 |
|
462919591 KEYS: Preparse ma... |
506 507 508 509 510 511 512 |
if (type->match_preparse) { ret = type->match_preparse(&ctx.match_data); if (ret < 0) { key = ERR_PTR(ret); goto error; } } |
1da177e4c Linux-2.6.12-rc2 |
513 |
/* search all the process keyrings for a key */ |
4bdf0bc30 KEYS: Introduce a... |
514 |
key_ref = search_process_keyrings(&ctx); |
1da177e4c Linux-2.6.12-rc2 |
515 |
|
664cceb00 [PATCH] Keys: Add... |
516 517 |
if (!IS_ERR(key_ref)) { key = key_ref_to_ptr(key_ref); |
03449cd9e keys: the request... |
518 519 |
if (dest_keyring) { construct_get_dest_keyring(&dest_keyring); |
2b9e4688f KEYS: Better hand... |
520 |
ret = key_link(dest_keyring, key); |
03449cd9e keys: the request... |
521 |
key_put(dest_keyring); |
2b9e4688f KEYS: Better hand... |
522 523 524 |
if (ret < 0) { key_put(key); key = ERR_PTR(ret); |
462919591 KEYS: Preparse ma... |
525 |
goto error_free; |
2b9e4688f KEYS: Better hand... |
526 |
} |
03449cd9e keys: the request... |
527 |
} |
76181c134 KEYS: Make reques... |
528 |
} else if (PTR_ERR(key_ref) != -EAGAIN) { |
e231c2ee6 Convert ERR_PTR(P... |
529 |
key = ERR_CAST(key_ref); |
76181c134 KEYS: Make reques... |
530 |
} else { |
1da177e4c Linux-2.6.12-rc2 |
531 532 533 534 |
/* the search failed, but the keyrings were searchable, so we * should consult userspace if we can */ key = ERR_PTR(-ENOKEY); if (!callout_info) |
462919591 KEYS: Preparse ma... |
535 |
goto error_free; |
1da177e4c Linux-2.6.12-rc2 |
536 |
|
4bdf0bc30 KEYS: Introduce a... |
537 538 |
key = construct_key_and_link(&ctx, callout_info, callout_len, aux, dest_keyring, flags); |
1da177e4c Linux-2.6.12-rc2 |
539 |
} |
462919591 KEYS: Preparse ma... |
540 541 542 |
error_free: if (type->match_free) type->match_free(&ctx.match_data); |
3e30148c3 [PATCH] Keys: Mak... |
543 544 |
error: kleave(" = %p", key); |
1da177e4c Linux-2.6.12-rc2 |
545 |
return key; |
76181c134 KEYS: Make reques... |
546 |
} |
1da177e4c Linux-2.6.12-rc2 |
547 |
|
973c9f4f4 KEYS: Fix up comm... |
548 549 550 551 552 553 554 555 556 557 |
/** * wait_for_key_construction - Wait for construction of a key to complete * @key: The key being waited for. * @intr: Whether to wait interruptibly. * * Wait for a key to finish being constructed. * * Returns 0 if successful; -ERESTARTSYS if the wait was interrupted; -ENOKEY * if the key was negated; or -EKEYREVOKED or -EKEYEXPIRED if the key was * revoked or expired. |
76181c134 KEYS: Make reques... |
558 559 560 561 |
*/ int wait_for_key_construction(struct key *key, bool intr) { int ret; |
3e30148c3 [PATCH] Keys: Mak... |
562 |
|
76181c134 KEYS: Make reques... |
563 |
ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT, |
76181c134 KEYS: Make reques... |
564 |
intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); |
743162013 sched: Remove pro... |
565 566 |
if (ret) return -ERESTARTSYS; |
74792b000 KEYS: Fix a race ... |
567 568 |
if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { smp_rmb(); |
fdd1b9458 KEYS: Add a new k... |
569 |
return key->type_data.reject_error; |
74792b000 KEYS: Fix a race ... |
570 |
} |
76181c134 KEYS: Make reques... |
571 572 573 |
return key_validate(key); } EXPORT_SYMBOL(wait_for_key_construction); |
3e30148c3 [PATCH] Keys: Mak... |
574 |
|
973c9f4f4 KEYS: Fix up comm... |
575 576 577 578 579 580 581 582 583 584 585 586 587 |
/** * request_key - Request a key and wait for construction * @type: Type of key. * @description: The searchable description of the key. * @callout_info: The data to pass to the instantiation upcall (or NULL). * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found, new keys are always allocated in the user's quota, * the callout_info must be a NUL-terminated string and no auxiliary data can * be passed. * * Furthermore, it then works as wait_for_key_construction() to wait for the * completion of keys undergoing construction with a non-interruptible wait. |
3e30148c3 [PATCH] Keys: Mak... |
588 589 590 591 592 |
*/ struct key *request_key(struct key_type *type, const char *description, const char *callout_info) { |
76181c134 KEYS: Make reques... |
593 |
struct key *key; |
4a38e122e keys: allow the c... |
594 |
size_t callout_len = 0; |
76181c134 KEYS: Make reques... |
595 |
int ret; |
4a38e122e keys: allow the c... |
596 597 598 599 |
if (callout_info) callout_len = strlen(callout_info); key = request_key_and_link(type, description, callout_info, callout_len, NULL, NULL, KEY_ALLOC_IN_QUOTA); |
76181c134 KEYS: Make reques... |
600 601 602 603 604 605 606 607 608 |
if (!IS_ERR(key)) { ret = wait_for_key_construction(key, false); if (ret < 0) { key_put(key); return ERR_PTR(ret); } } return key; } |
1da177e4c Linux-2.6.12-rc2 |
609 |
EXPORT_SYMBOL(request_key); |
4e54f0854 [PATCH] Keys: All... |
610 |
|
973c9f4f4 KEYS: Fix up comm... |
611 612 613 614 615 616 617 618 619 620 621 622 623 |
/** * request_key_with_auxdata - Request a key with auxiliary data for the upcaller * @type: The type of key we want. * @description: The searchable description of the key. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found and new keys are always allocated in the user's quota. * * Furthermore, it then works as wait_for_key_construction() to wait for the * completion of keys undergoing construction with a non-interruptible wait. |
4e54f0854 [PATCH] Keys: All... |
624 625 626 |
*/ struct key *request_key_with_auxdata(struct key_type *type, const char *description, |
4a38e122e keys: allow the c... |
627 628 |
const void *callout_info, size_t callout_len, |
4e54f0854 [PATCH] Keys: All... |
629 630 |
void *aux) { |
76181c134 KEYS: Make reques... |
631 632 |
struct key *key; int ret; |
4a38e122e keys: allow the c... |
633 634 |
key = request_key_and_link(type, description, callout_info, callout_len, aux, NULL, KEY_ALLOC_IN_QUOTA); |
76181c134 KEYS: Make reques... |
635 636 637 638 639 640 641 642 643 644 |
if (!IS_ERR(key)) { ret = wait_for_key_construction(key, false); if (ret < 0) { key_put(key); return ERR_PTR(ret); } } return key; } EXPORT_SYMBOL(request_key_with_auxdata); |
4e54f0854 [PATCH] Keys: All... |
645 |
|
76181c134 KEYS: Make reques... |
646 |
/* |
973c9f4f4 KEYS: Fix up comm... |
647 648 649 650 651 652 653 654 655 656 657 658 |
* request_key_async - Request a key (allow async construction) * @type: Type of key. * @description: The searchable description of the key. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found, new keys are always allocated in the user's quota and * no auxiliary data can be passed. * * The caller should call wait_for_key_construction() to wait for the * completion of the returned key if it is still undergoing construction. |
76181c134 KEYS: Make reques... |
659 660 661 |
*/ struct key *request_key_async(struct key_type *type, const char *description, |
4a38e122e keys: allow the c... |
662 663 |
const void *callout_info, size_t callout_len) |
76181c134 KEYS: Make reques... |
664 |
{ |
4a38e122e keys: allow the c... |
665 666 667 |
return request_key_and_link(type, description, callout_info, callout_len, NULL, NULL, KEY_ALLOC_IN_QUOTA); |
76181c134 KEYS: Make reques... |
668 669 |
} EXPORT_SYMBOL(request_key_async); |
4e54f0854 [PATCH] Keys: All... |
670 |
|
76181c134 KEYS: Make reques... |
671 672 |
/* * request a key with auxiliary data for the upcaller (allow async construction) |
973c9f4f4 KEYS: Fix up comm... |
673 674 675 676 677 678 679 680 681 682 683 |
* @type: Type of key. * @description: The searchable description of the key. * @callout_info: The data to pass to the instantiation upcall (or NULL). * @callout_len: The length of callout_info. * @aux: Auxiliary data for the upcall. * * As for request_key_and_link() except that it does not add the returned key * to a keyring if found and new keys are always allocated in the user's quota. * * The caller should call wait_for_key_construction() to wait for the * completion of the returned key if it is still undergoing construction. |
76181c134 KEYS: Make reques... |
684 685 686 |
*/ struct key *request_key_async_with_auxdata(struct key_type *type, const char *description, |
4a38e122e keys: allow the c... |
687 688 |
const void *callout_info, size_t callout_len, |
76181c134 KEYS: Make reques... |
689 690 |
void *aux) { |
4a38e122e keys: allow the c... |
691 692 |
return request_key_and_link(type, description, callout_info, callout_len, aux, NULL, KEY_ALLOC_IN_QUOTA); |
76181c134 KEYS: Make reques... |
693 694 |
} EXPORT_SYMBOL(request_key_async_with_auxdata); |