1
2
3
4
5
6
7
8
9
10
11
12#include <linux/module.h>
13#include <linux/sched.h>
14#include <linux/kmod.h>
15#include <linux/err.h>
16#include "internal.h"
17
18struct key_construction {
19 struct list_head link;
20 struct key *key;
21};
22
23
24DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
25
26
27
28
29
30
31
32static int call_request_key(struct key *key,
33 const char *op,
34 const char *callout_info)
35{
36 struct task_struct *tsk = current;
37 char *argv[10], *envp[3], uid_str[12], gid_str[12];
38 char key_str[12], keyring_str[3][12];
39 int i;
40
41
42 sprintf(uid_str, "%d", current->fsuid);
43 sprintf(gid_str, "%d", current->fsgid);
44
45
46 sprintf(key_str, "%d", key->serial);
47
48
49 task_lock(current);
50 sprintf(keyring_str[0], "%d",
51 tsk->thread_keyring ? tsk->thread_keyring->serial : 0);
52 sprintf(keyring_str[1], "%d",
53 tsk->process_keyring ? tsk->process_keyring->serial : 0);
54 sprintf(keyring_str[2], "%d",
55 (tsk->session_keyring ?
56 tsk->session_keyring->serial :
57 tsk->user->session_keyring->serial));
58 task_unlock(tsk);
59
60
61 i = 0;
62 envp[i++] = "HOME=/";
63 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
64 envp[i] = NULL;
65
66
67 i = 0;
68 argv[i++] = "/sbin/request-key";
69 argv[i++] = (char *) op;
70 argv[i++] = key_str;
71 argv[i++] = uid_str;
72 argv[i++] = gid_str;
73 argv[i++] = keyring_str[0];
74 argv[i++] = keyring_str[1];
75 argv[i++] = keyring_str[2];
76 argv[i++] = callout_info[0] ? (char *) callout_info : "-";
77 argv[i] = NULL;
78
79
80 return call_usermodehelper(argv[0], argv, envp, 1);
81
82}
83
84
85
86
87
88
89
90static struct key *__request_key_construction(struct key_type *type,
91 const char *description,
92 const char *callout_info)
93{
94 struct key_construction cons;
95 struct timespec now;
96 struct key *key;
97 int ret, negative;
98
99
100 key = key_alloc(type, description,
101 current->fsuid, current->fsgid, KEY_USR_ALL, 0);
102 if (IS_ERR(key))
103 goto alloc_failed;
104
105 write_lock(&key->lock);
106 key->flags |= KEY_FLAG_USER_CONSTRUCT;
107 write_unlock(&key->lock);
108
109 cons.key = key;
110 list_add_tail(&cons.link, &key->user->consq);
111
112
113 up_write(&key_construction_sem);
114
115
116 ret = call_request_key(key, "create", callout_info);
117 if (ret < 0)
118 goto request_failed;
119
120
121 ret = -ENOKEY;
122 if (!(key->flags & KEY_FLAG_INSTANTIATED))
123 goto request_failed;
124
125 down_write(&key_construction_sem);
126 list_del(&cons.link);
127 up_write(&key_construction_sem);
128
129
130 check_not_negative:
131 if (key->flags & KEY_FLAG_NEGATIVE) {
132 key_put(key);
133 key = ERR_PTR(-ENOKEY);
134 }
135
136 out:
137 return key;
138
139 request_failed:
140
141
142
143
144 negative = 0;
145 down_write(&key_construction_sem);
146
147 list_del(&cons.link);
148
149 write_lock(&key->lock);
150 key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
151
152
153 if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
154 key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE;
155 negative = 1;
156 }
157
158 write_unlock(&key->lock);
159 up_write(&key_construction_sem);
160
161 if (!negative)
162 goto check_not_negative;
163
164
165
166 now = current_kernel_time();
167 key->expiry = now.tv_sec + key_negative_timeout;
168
169 if (current->session_keyring)
170 key_link(current->session_keyring, key);
171 key_put(key);
172
173
174 wake_up_all(&request_key_conswq);
175
176 key = ERR_PTR(ret);
177 goto out;
178
179 alloc_failed:
180 up_write(&key_construction_sem);
181 goto out;
182
183}
184
185
186
187
188
189
190
191static struct key *request_key_construction(struct key_type *type,
192 const char *description,
193 struct key_user *user,
194 const char *callout_info)
195{
196 struct key_construction *pcons;
197 struct key *key, *ckey;
198
199 DECLARE_WAITQUEUE(myself, current);
200
201
202 down_write(&key_construction_sem);
203
204 list_for_each_entry(pcons, &user->consq, link) {
205 ckey = pcons->key;
206
207 if (ckey->type != type)
208 continue;
209
210 if (type->match(ckey, description))
211 goto found_key_under_construction;
212 }
213
214
215 key = __request_key_construction(type, description, callout_info);
216 error:
217 return key;
218
219
220
221
222 found_key_under_construction:
223 atomic_inc(&ckey->usage);
224 up_write(&key_construction_sem);
225
226
227 add_wait_queue(&request_key_conswq, &myself);
228
229 for (;;) {
230 set_current_state(TASK_UNINTERRUPTIBLE);
231 if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT))
232 break;
233 schedule();
234 }
235
236 set_current_state(TASK_RUNNING);
237 remove_wait_queue(&request_key_conswq, &myself);
238
239
240
241
242 key_put(ckey);
243 ckey = NULL;
244
245 key = NULL;
246 goto error;
247
248}
249
250
251
252
253
254
255
256
257
258struct key *request_key(struct key_type *type,
259 const char *description,
260 const char *callout_info)
261{
262 struct key_user *user;
263 struct key *key;
264
265
266 key = search_process_keyrings_aux(type, description, type->match);
267
268 if (PTR_ERR(key) == -EAGAIN) {
269
270
271 key = ERR_PTR(-ENOKEY);
272 if (!callout_info)
273 goto error;
274
275
276 user = key_user_lookup(current->fsuid);
277 if (IS_ERR(user)) {
278 key = ERR_PTR(PTR_ERR(user));
279 goto error;
280 }
281
282 for (;;) {
283
284
285 key = request_key_construction(type, description,
286 user, callout_info);
287 if (key)
288 break;
289
290
291
292 key = search_process_keyrings_aux(type, description,
293 type->match);
294 if (PTR_ERR(key) != -EAGAIN)
295 break;
296 }
297
298 key_user_put(user);
299 }
300
301 error:
302 return key;
303
304}
305
306EXPORT_SYMBOL(request_key);
307
308
309
310
311
312int key_validate(struct key *key)
313{
314 struct timespec now;
315 int ret = 0;
316
317 if (key) {
318
319 ret = -EKEYREVOKED;
320 if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD))
321 goto error;
322
323
324 ret = 0;
325 if (key->expiry) {
326 now = current_kernel_time();
327 if (now.tv_sec >= key->expiry)
328 ret = -EKEYEXPIRED;
329 }
330 }
331
332 error:
333 return ret;
334
335}
336
337EXPORT_SYMBOL(key_validate);
338