Commit | Line | Data |
---|---|---|
3e30148c DH |
1 | /* request_key_auth.c: request key authorisation controlling key def |
2 | * | |
3 | * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. | |
4 | * Written by David Howells (dhowells@redhat.com) | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
f1a9badc DH |
10 | * |
11 | * See Documentation/keys-request-key.txt | |
3e30148c DH |
12 | */ |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/sched.h> | |
16 | #include <linux/err.h> | |
17 | #include <linux/seq_file.h> | |
fdb89bce | 18 | #include <linux/slab.h> |
b5f545c8 | 19 | #include <asm/uaccess.h> |
3e30148c DH |
20 | #include "internal.h" |
21 | ||
22 | static int request_key_auth_instantiate(struct key *, const void *, size_t); | |
23 | static void request_key_auth_describe(const struct key *, struct seq_file *); | |
04c567d9 | 24 | static void request_key_auth_revoke(struct key *); |
3e30148c | 25 | static void request_key_auth_destroy(struct key *); |
b5f545c8 | 26 | static long request_key_auth_read(const struct key *, char __user *, size_t); |
3e30148c DH |
27 | |
28 | /* | |
29 | * the request-key authorisation key type definition | |
30 | */ | |
31 | struct key_type key_type_request_key_auth = { | |
32 | .name = ".request_key_auth", | |
33 | .def_datalen = sizeof(struct request_key_auth), | |
34 | .instantiate = request_key_auth_instantiate, | |
35 | .describe = request_key_auth_describe, | |
04c567d9 | 36 | .revoke = request_key_auth_revoke, |
3e30148c | 37 | .destroy = request_key_auth_destroy, |
b5f545c8 | 38 | .read = request_key_auth_read, |
3e30148c DH |
39 | }; |
40 | ||
41 | /*****************************************************************************/ | |
42 | /* | |
b5f545c8 | 43 | * instantiate a request-key authorisation key |
3e30148c DH |
44 | */ |
45 | static int request_key_auth_instantiate(struct key *key, | |
46 | const void *data, | |
47 | size_t datalen) | |
48 | { | |
b5f545c8 DH |
49 | key->payload.data = (struct request_key_auth *) data; |
50 | return 0; | |
3e30148c DH |
51 | |
52 | } /* end request_key_auth_instantiate() */ | |
53 | ||
54 | /*****************************************************************************/ | |
55 | /* | |
b5f545c8 | 56 | * reading a request-key authorisation key retrieves the callout information |
3e30148c DH |
57 | */ |
58 | static void request_key_auth_describe(const struct key *key, | |
59 | struct seq_file *m) | |
60 | { | |
61 | struct request_key_auth *rka = key->payload.data; | |
62 | ||
63 | seq_puts(m, "key:"); | |
64 | seq_puts(m, key->description); | |
4a38e122 | 65 | seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len); |
3e30148c DH |
66 | |
67 | } /* end request_key_auth_describe() */ | |
68 | ||
b5f545c8 DH |
69 | /*****************************************************************************/ |
70 | /* | |
71 | * read the callout_info data | |
72 | * - the key's semaphore is read-locked | |
73 | */ | |
74 | static long request_key_auth_read(const struct key *key, | |
75 | char __user *buffer, size_t buflen) | |
76 | { | |
77 | struct request_key_auth *rka = key->payload.data; | |
78 | size_t datalen; | |
79 | long ret; | |
80 | ||
4a38e122 | 81 | datalen = rka->callout_len; |
b5f545c8 DH |
82 | ret = datalen; |
83 | ||
84 | /* we can return the data as is */ | |
85 | if (buffer && buflen > 0) { | |
86 | if (buflen > datalen) | |
87 | buflen = datalen; | |
88 | ||
89 | if (copy_to_user(buffer, rka->callout_info, buflen) != 0) | |
90 | ret = -EFAULT; | |
91 | } | |
92 | ||
93 | return ret; | |
94 | ||
95 | } /* end request_key_auth_read() */ | |
96 | ||
04c567d9 DH |
97 | /*****************************************************************************/ |
98 | /* | |
99 | * handle revocation of an authorisation token key | |
100 | * - called with the key sem write-locked | |
101 | */ | |
102 | static void request_key_auth_revoke(struct key *key) | |
103 | { | |
104 | struct request_key_auth *rka = key->payload.data; | |
105 | ||
106 | kenter("{%d}", key->serial); | |
107 | ||
d84f4f99 DH |
108 | if (rka->cred) { |
109 | put_cred(rka->cred); | |
110 | rka->cred = NULL; | |
04c567d9 DH |
111 | } |
112 | ||
113 | } /* end request_key_auth_revoke() */ | |
114 | ||
3e30148c DH |
115 | /*****************************************************************************/ |
116 | /* | |
117 | * destroy an instantiation authorisation token key | |
118 | */ | |
119 | static void request_key_auth_destroy(struct key *key) | |
120 | { | |
121 | struct request_key_auth *rka = key->payload.data; | |
122 | ||
123 | kenter("{%d}", key->serial); | |
124 | ||
d84f4f99 DH |
125 | if (rka->cred) { |
126 | put_cred(rka->cred); | |
127 | rka->cred = NULL; | |
04c567d9 DH |
128 | } |
129 | ||
3e30148c | 130 | key_put(rka->target_key); |
8bbf4976 | 131 | key_put(rka->dest_keyring); |
76181c13 | 132 | kfree(rka->callout_info); |
74fd92c5 | 133 | kfree(rka); |
3e30148c DH |
134 | |
135 | } /* end request_key_auth_destroy() */ | |
136 | ||
137 | /*****************************************************************************/ | |
138 | /* | |
b5f545c8 DH |
139 | * create an authorisation token for /sbin/request-key or whoever to gain |
140 | * access to the caller's security data | |
3e30148c | 141 | */ |
4a38e122 | 142 | struct key *request_key_auth_new(struct key *target, const void *callout_info, |
8bbf4976 | 143 | size_t callout_len, struct key *dest_keyring) |
3e30148c | 144 | { |
b5f545c8 | 145 | struct request_key_auth *rka, *irka; |
d84f4f99 | 146 | const struct cred *cred = current->cred; |
b5f545c8 | 147 | struct key *authkey = NULL; |
3e30148c DH |
148 | char desc[20]; |
149 | int ret; | |
150 | ||
151 | kenter("%d,", target->serial); | |
152 | ||
b5f545c8 DH |
153 | /* allocate a auth record */ |
154 | rka = kmalloc(sizeof(*rka), GFP_KERNEL); | |
155 | if (!rka) { | |
156 | kleave(" = -ENOMEM"); | |
157 | return ERR_PTR(-ENOMEM); | |
158 | } | |
4a38e122 | 159 | rka->callout_info = kmalloc(callout_len, GFP_KERNEL); |
76181c13 DH |
160 | if (!rka->callout_info) { |
161 | kleave(" = -ENOMEM"); | |
162 | kfree(rka); | |
163 | return ERR_PTR(-ENOMEM); | |
164 | } | |
3e30148c | 165 | |
b5f545c8 DH |
166 | /* see if the calling process is already servicing the key request of |
167 | * another process */ | |
d84f4f99 | 168 | if (cred->request_key_auth) { |
b5f545c8 | 169 | /* it is - use that instantiation context here too */ |
d84f4f99 | 170 | down_read(&cred->request_key_auth->sem); |
04c567d9 DH |
171 | |
172 | /* if the auth key has been revoked, then the key we're | |
173 | * servicing is already instantiated */ | |
d84f4f99 | 174 | if (test_bit(KEY_FLAG_REVOKED, &cred->request_key_auth->flags)) |
04c567d9 DH |
175 | goto auth_key_revoked; |
176 | ||
d84f4f99 DH |
177 | irka = cred->request_key_auth->payload.data; |
178 | rka->cred = get_cred(irka->cred); | |
b5f545c8 | 179 | rka->pid = irka->pid; |
04c567d9 | 180 | |
d84f4f99 | 181 | up_read(&cred->request_key_auth->sem); |
3e30148c | 182 | } |
b5f545c8 DH |
183 | else { |
184 | /* it isn't - use this process as the context */ | |
d84f4f99 | 185 | rka->cred = get_cred(cred); |
b5f545c8 DH |
186 | rka->pid = current->pid; |
187 | } | |
188 | ||
189 | rka->target_key = key_get(target); | |
8bbf4976 | 190 | rka->dest_keyring = key_get(dest_keyring); |
4a38e122 DH |
191 | memcpy(rka->callout_info, callout_info, callout_len); |
192 | rka->callout_len = callout_len; | |
3e30148c DH |
193 | |
194 | /* allocate the auth key */ | |
195 | sprintf(desc, "%x", target->serial); | |
196 | ||
b5f545c8 | 197 | authkey = key_alloc(&key_type_request_key_auth, desc, |
d84f4f99 | 198 | cred->fsuid, cred->fsgid, cred, |
b5f545c8 | 199 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | |
7e047ef5 | 200 | KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA); |
b5f545c8 DH |
201 | if (IS_ERR(authkey)) { |
202 | ret = PTR_ERR(authkey); | |
203 | goto error_alloc; | |
3e30148c DH |
204 | } |
205 | ||
d84f4f99 | 206 | /* construct the auth key */ |
b5f545c8 DH |
207 | ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); |
208 | if (ret < 0) | |
209 | goto error_inst; | |
3e30148c | 210 | |
d84f4f99 | 211 | kleave(" = {%d,%d}", authkey->serial, atomic_read(&authkey->usage)); |
b5f545c8 DH |
212 | return authkey; |
213 | ||
04c567d9 | 214 | auth_key_revoked: |
d84f4f99 | 215 | up_read(&cred->request_key_auth->sem); |
76181c13 | 216 | kfree(rka->callout_info); |
04c567d9 DH |
217 | kfree(rka); |
218 | kleave("= -EKEYREVOKED"); | |
219 | return ERR_PTR(-EKEYREVOKED); | |
220 | ||
b5f545c8 DH |
221 | error_inst: |
222 | key_revoke(authkey); | |
223 | key_put(authkey); | |
224 | error_alloc: | |
225 | key_put(rka->target_key); | |
8bbf4976 | 226 | key_put(rka->dest_keyring); |
76181c13 | 227 | kfree(rka->callout_info); |
b5f545c8 DH |
228 | kfree(rka); |
229 | kleave("= %d", ret); | |
230 | return ERR_PTR(ret); | |
3e30148c DH |
231 | |
232 | } /* end request_key_auth_new() */ | |
233 | ||
b5f545c8 DH |
234 | /*****************************************************************************/ |
235 | /* | |
236 | * see if an authorisation key is associated with a particular key | |
237 | */ | |
238 | static int key_get_instantiation_authkey_match(const struct key *key, | |
239 | const void *_id) | |
240 | { | |
241 | struct request_key_auth *rka = key->payload.data; | |
242 | key_serial_t id = (key_serial_t)(unsigned long) _id; | |
243 | ||
244 | return rka->target_key->serial == id; | |
245 | ||
246 | } /* end key_get_instantiation_authkey_match() */ | |
247 | ||
3e30148c DH |
248 | /*****************************************************************************/ |
249 | /* | |
250 | * get the authorisation key for instantiation of a specific key if attached to | |
251 | * the current process's keyrings | |
252 | * - this key is inserted into a keyring and that is set as /sbin/request-key's | |
253 | * session keyring | |
254 | * - a target_id of zero specifies any valid token | |
255 | */ | |
256 | struct key *key_get_instantiation_authkey(key_serial_t target_id) | |
257 | { | |
d84f4f99 | 258 | const struct cred *cred = current_cred(); |
b5f545c8 DH |
259 | struct key *authkey; |
260 | key_ref_t authkey_ref; | |
261 | ||
262 | authkey_ref = search_process_keyrings( | |
263 | &key_type_request_key_auth, | |
264 | (void *) (unsigned long) target_id, | |
265 | key_get_instantiation_authkey_match, | |
d84f4f99 | 266 | cred); |
b5f545c8 DH |
267 | |
268 | if (IS_ERR(authkey_ref)) { | |
e231c2ee | 269 | authkey = ERR_CAST(authkey_ref); |
b5f545c8 DH |
270 | goto error; |
271 | } | |
3e30148c | 272 | |
b5f545c8 DH |
273 | authkey = key_ref_to_ptr(authkey_ref); |
274 | if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { | |
275 | key_put(authkey); | |
276 | authkey = ERR_PTR(-EKEYREVOKED); | |
277 | } | |
3e30148c | 278 | |
b5f545c8 DH |
279 | error: |
280 | return authkey; | |
3e30148c DH |
281 | |
282 | } /* end key_get_instantiation_authkey() */ |