diff options
author | David Howells <dhowells@redhat.com> | 2006-01-08 04:02:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 23:13:53 -0500 |
commit | b5f545c880a2a47947ba2118b2509644ab7a2969 (patch) | |
tree | 8720e02262b0ff6309ae79603f6c63965296d378 /security/keys/request_key.c | |
parent | cab8eb594e84b434d20412fc5a3985b0bee3ab9f (diff) |
[PATCH] keys: Permit running process to instantiate keys
Make it possible for a running process (such as gssapid) to be able to
instantiate a key, as was requested by Trond Myklebust for NFS4.
The patch makes the following changes:
(1) A new, optional key type method has been added. This permits a key type
to intercept requests at the point /sbin/request-key is about to be
spawned and do something else with them - passing them over the
rpc_pipefs files or netlink sockets for instance.
The uninstantiated key, the authorisation key and the intended operation
name are passed to the method.
(2) The callout_info is no longer passed as an argument to /sbin/request-key
to prevent unauthorised viewing of this data using ps or by looking in
/proc/pid/cmdline.
This means that the old /sbin/request-key program will not work with the
patched kernel as it will expect to see an extra argument that is no
longer there.
A revised keyutils package will be made available tomorrow.
(3) The callout_info is now attached to the authorisation key. Reading this
key will retrieve the information.
(4) A new field has been added to the task_struct. This holds the
authorisation key currently active for a thread. Searches now look here
for the caller's set of keys rather than looking for an auth key in the
lowest level of the session keyring.
This permits a thread to be servicing multiple requests at once and to
switch between them. Note that this is per-thread, not per-process, and
so is usable in multithreaded programs.
The setting of this field is inherited across fork and exec.
(5) A new keyctl function (KEYCTL_ASSUME_AUTHORITY) has been added that
permits a thread to assume the authority to deal with an uninstantiated
key. Assumption is only permitted if the authorisation key associated
with the uninstantiated key is somewhere in the thread's keyrings.
This function can also clear the assumption.
(6) A new magic key specifier has been added to refer to the currently
assumed authorisation key (KEY_SPEC_REQKEY_AUTH_KEY).
(7) Instantiation will only proceed if the appropriate authorisation key is
assumed first. The assumed authorisation key is discarded if
instantiation is successful.
(8) key_validate() is moved from the file of request_key functions to the
file of permissions functions.
(9) The documentation is updated.
From: <Valdis.Kletnieks@vt.edu>
Build fix.
Signed-off-by: David Howells <dhowells@redhat.com>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Cc: Alexander Zangerl <az@bond.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security/keys/request_key.c')
-rw-r--r-- | security/keys/request_key.c | 108 |
1 files changed, 50 insertions, 58 deletions
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 5cc4bba70db..f030a0ccbb9 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -29,28 +29,36 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); | |||
29 | /*****************************************************************************/ | 29 | /*****************************************************************************/ |
30 | /* | 30 | /* |
31 | * request userspace finish the construction of a key | 31 | * request userspace finish the construction of a key |
32 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>" | 32 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" |
33 | */ | 33 | */ |
34 | static int call_request_key(struct key *key, | 34 | static int call_sbin_request_key(struct key *key, |
35 | const char *op, | 35 | struct key *authkey, |
36 | const char *callout_info) | 36 | const char *op) |
37 | { | 37 | { |
38 | struct task_struct *tsk = current; | 38 | struct task_struct *tsk = current; |
39 | key_serial_t prkey, sskey; | 39 | key_serial_t prkey, sskey; |
40 | struct key *session_keyring, *rkakey; | 40 | struct key *keyring; |
41 | char *argv[10], *envp[3], uid_str[12], gid_str[12]; | 41 | char *argv[9], *envp[3], uid_str[12], gid_str[12]; |
42 | char key_str[12], keyring_str[3][12]; | 42 | char key_str[12], keyring_str[3][12]; |
43 | char desc[20]; | ||
43 | int ret, i; | 44 | int ret, i; |
44 | 45 | ||
45 | kenter("{%d},%s,%s", key->serial, op, callout_info); | 46 | kenter("{%d},{%d},%s", key->serial, authkey->serial, op); |
46 | 47 | ||
47 | /* generate a new session keyring with an auth key in it */ | 48 | /* allocate a new session keyring */ |
48 | session_keyring = request_key_auth_new(key, &rkakey); | 49 | sprintf(desc, "_req.%u", key->serial); |
49 | if (IS_ERR(session_keyring)) { | 50 | |
50 | ret = PTR_ERR(session_keyring); | 51 | keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); |
51 | goto error; | 52 | if (IS_ERR(keyring)) { |
53 | ret = PTR_ERR(keyring); | ||
54 | goto error_alloc; | ||
52 | } | 55 | } |
53 | 56 | ||
57 | /* attach the auth key to the session keyring */ | ||
58 | ret = __key_link(keyring, authkey); | ||
59 | if (ret < 0) | ||
60 | goto error_link; | ||
61 | |||
54 | /* record the UID and GID */ | 62 | /* record the UID and GID */ |
55 | sprintf(uid_str, "%d", current->fsuid); | 63 | sprintf(uid_str, "%d", current->fsuid); |
56 | sprintf(gid_str, "%d", current->fsgid); | 64 | sprintf(gid_str, "%d", current->fsgid); |
@@ -95,22 +103,19 @@ static int call_request_key(struct key *key, | |||
95 | argv[i++] = keyring_str[0]; | 103 | argv[i++] = keyring_str[0]; |
96 | argv[i++] = keyring_str[1]; | 104 | argv[i++] = keyring_str[1]; |
97 | argv[i++] = keyring_str[2]; | 105 | argv[i++] = keyring_str[2]; |
98 | argv[i++] = (char *) callout_info; | ||
99 | argv[i] = NULL; | 106 | argv[i] = NULL; |
100 | 107 | ||
101 | /* do it */ | 108 | /* do it */ |
102 | ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1); | 109 | ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1); |
103 | 110 | ||
104 | /* dispose of the special keys */ | 111 | error_link: |
105 | key_revoke(rkakey); | 112 | key_put(keyring); |
106 | key_put(rkakey); | ||
107 | key_put(session_keyring); | ||
108 | 113 | ||
109 | error: | 114 | error_alloc: |
110 | kleave(" = %d", ret); | 115 | kleave(" = %d", ret); |
111 | return ret; | 116 | return ret; |
112 | 117 | ||
113 | } /* end call_request_key() */ | 118 | } /* end call_sbin_request_key() */ |
114 | 119 | ||
115 | /*****************************************************************************/ | 120 | /*****************************************************************************/ |
116 | /* | 121 | /* |
@@ -122,9 +127,10 @@ static struct key *__request_key_construction(struct key_type *type, | |||
122 | const char *description, | 127 | const char *description, |
123 | const char *callout_info) | 128 | const char *callout_info) |
124 | { | 129 | { |
130 | request_key_actor_t actor; | ||
125 | struct key_construction cons; | 131 | struct key_construction cons; |
126 | struct timespec now; | 132 | struct timespec now; |
127 | struct key *key; | 133 | struct key *key, *authkey; |
128 | int ret, negated; | 134 | int ret, negated; |
129 | 135 | ||
130 | kenter("%s,%s,%s", type->name, description, callout_info); | 136 | kenter("%s,%s,%s", type->name, description, callout_info); |
@@ -143,8 +149,19 @@ static struct key *__request_key_construction(struct key_type *type, | |||
143 | /* we drop the construction sem here on behalf of the caller */ | 149 | /* we drop the construction sem here on behalf of the caller */ |
144 | up_write(&key_construction_sem); | 150 | up_write(&key_construction_sem); |
145 | 151 | ||
152 | /* allocate an authorisation key */ | ||
153 | authkey = request_key_auth_new(key, callout_info); | ||
154 | if (IS_ERR(authkey)) { | ||
155 | ret = PTR_ERR(authkey); | ||
156 | authkey = NULL; | ||
157 | goto alloc_authkey_failed; | ||
158 | } | ||
159 | |||
146 | /* make the call */ | 160 | /* make the call */ |
147 | ret = call_request_key(key, "create", callout_info); | 161 | actor = call_sbin_request_key; |
162 | if (type->request_key) | ||
163 | actor = type->request_key; | ||
164 | ret = actor(key, authkey, "create"); | ||
148 | if (ret < 0) | 165 | if (ret < 0) |
149 | goto request_failed; | 166 | goto request_failed; |
150 | 167 | ||
@@ -153,22 +170,29 @@ static struct key *__request_key_construction(struct key_type *type, | |||
153 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 170 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
154 | goto request_failed; | 171 | goto request_failed; |
155 | 172 | ||
173 | key_revoke(authkey); | ||
174 | key_put(authkey); | ||
175 | |||
156 | down_write(&key_construction_sem); | 176 | down_write(&key_construction_sem); |
157 | list_del(&cons.link); | 177 | list_del(&cons.link); |
158 | up_write(&key_construction_sem); | 178 | up_write(&key_construction_sem); |
159 | 179 | ||
160 | /* also give an error if the key was negatively instantiated */ | 180 | /* also give an error if the key was negatively instantiated */ |
161 | check_not_negative: | 181 | check_not_negative: |
162 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { | 182 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { |
163 | key_put(key); | 183 | key_put(key); |
164 | key = ERR_PTR(-ENOKEY); | 184 | key = ERR_PTR(-ENOKEY); |
165 | } | 185 | } |
166 | 186 | ||
167 | out: | 187 | out: |
168 | kleave(" = %p", key); | 188 | kleave(" = %p", key); |
169 | return key; | 189 | return key; |
170 | 190 | ||
171 | request_failed: | 191 | request_failed: |
192 | key_revoke(authkey); | ||
193 | key_put(authkey); | ||
194 | |||
195 | alloc_authkey_failed: | ||
172 | /* it wasn't instantiated | 196 | /* it wasn't instantiated |
173 | * - remove from construction queue | 197 | * - remove from construction queue |
174 | * - mark the key as dead | 198 | * - mark the key as dead |
@@ -217,7 +241,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
217 | key = ERR_PTR(ret); | 241 | key = ERR_PTR(ret); |
218 | goto out; | 242 | goto out; |
219 | 243 | ||
220 | alloc_failed: | 244 | alloc_failed: |
221 | up_write(&key_construction_sem); | 245 | up_write(&key_construction_sem); |
222 | goto out; | 246 | goto out; |
223 | 247 | ||
@@ -464,35 +488,3 @@ struct key *request_key(struct key_type *type, | |||
464 | } /* end request_key() */ | 488 | } /* end request_key() */ |
465 | 489 | ||
466 | EXPORT_SYMBOL(request_key); | 490 | EXPORT_SYMBOL(request_key); |
467 | |||
468 | /*****************************************************************************/ | ||
469 | /* | ||
470 | * validate a key | ||
471 | */ | ||
472 | int 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; | ||
480 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || | ||
481 | test_bit(KEY_FLAG_DEAD, &key->flags)) | ||
482 | 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 | |||
498 | EXPORT_SYMBOL(key_validate); | ||