Blame view

security/keys/key.c 25.8 KB
76181c134   David Howells   KEYS: Make reques...
1
  /* Basic authentication token and access key management
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
   *
69664cf16   David Howells   keys: don't gener...
3
   * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
   * 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.
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
a7807a32b   Randy Dunlap   [PATCH] poison: a...
14
  #include <linux/poison.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/sched.h>
  #include <linux/slab.h>
29db91906   David Howells   [PATCH] Keys: Add...
17
  #include <linux/security.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include <linux/workqueue.h>
e51f6d343   Michael LeMay   [PATCH] keys: all...
19
  #include <linux/random.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/err.h>
1d1e97562   Serge E. Hallyn   keys: distinguish...
21
  #include <linux/user_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include "internal.h"
8bc16deab   David Howells   KEYS: Move the un...
23
  struct kmem_cache *key_jar;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  struct rb_root		key_serial_tree; /* tree of keys indexed by serial */
  DEFINE_SPINLOCK(key_serial_lock);
  
  struct rb_root	key_user_tree; /* tree of quota records indexed by UID */
  DEFINE_SPINLOCK(key_user_lock);
0b77f5bfb   David Howells   keys: make the ke...
29
30
31
32
  unsigned int key_quota_root_maxkeys = 200;	/* root's key count quota */
  unsigned int key_quota_root_maxbytes = 20000;	/* root's key space quota */
  unsigned int key_quota_maxkeys = 200;		/* general key count quota */
  unsigned int key_quota_maxbytes = 20000;	/* general key space quota */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  static LIST_HEAD(key_types_list);
  static DECLARE_RWSEM(key_types_sem);
973c9f4f4   David Howells   KEYS: Fix up comm...
35
  /* We serialise key instantiation and link */
76181c134   David Howells   KEYS: Make reques...
36
  DEFINE_MUTEX(key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
  #ifdef KEY_DEBUGGING
  void __key_check(const struct key *key)
  {
  	printk("__key_check: key %p {%08x} should be {%08x}
  ",
  	       key, key->magic, KEY_DEBUG_MAGIC);
  	BUG();
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
48
49
   * Get the key quota record for a user, allocating a new record if one doesn't
   * already exist.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
   */
1d1e97562   Serge E. Hallyn   keys: distinguish...
51
  struct key_user *key_user_lookup(uid_t uid, struct user_namespace *user_ns)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
  {
  	struct key_user *candidate = NULL, *user;
  	struct rb_node *parent = NULL;
  	struct rb_node **p;
973c9f4f4   David Howells   KEYS: Fix up comm...
56
  try_again:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
62
63
64
65
66
67
68
  	p = &key_user_tree.rb_node;
  	spin_lock(&key_user_lock);
  
  	/* search the tree for a user record with a matching UID */
  	while (*p) {
  		parent = *p;
  		user = rb_entry(parent, struct key_user, node);
  
  		if (uid < user->uid)
  			p = &(*p)->rb_left;
  		else if (uid > user->uid)
  			p = &(*p)->rb_right;
1d1e97562   Serge E. Hallyn   keys: distinguish...
69
70
71
72
  		else if (user_ns < user->user_ns)
  			p = &(*p)->rb_left;
  		else if (user_ns > user->user_ns)
  			p = &(*p)->rb_right;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  		else
  			goto found;
  	}
  
  	/* if we get here, we failed to find a match in the tree */
  	if (!candidate) {
  		/* allocate a candidate user record if we don't already have
  		 * one */
  		spin_unlock(&key_user_lock);
  
  		user = NULL;
  		candidate = kmalloc(sizeof(struct key_user), GFP_KERNEL);
  		if (unlikely(!candidate))
  			goto out;
  
  		/* the allocation may have scheduled, so we need to repeat the
  		 * search lest someone else added the record whilst we were
  		 * asleep */
  		goto try_again;
  	}
  
  	/* if we get here, then the user record still hadn't appeared on the
  	 * second pass - so we use the candidate record */
  	atomic_set(&candidate->usage, 1);
  	atomic_set(&candidate->nkeys, 0);
  	atomic_set(&candidate->nikeys, 0);
  	candidate->uid = uid;
1d1e97562   Serge E. Hallyn   keys: distinguish...
100
  	candidate->user_ns = get_user_ns(user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
  	candidate->qnkeys = 0;
  	candidate->qnbytes = 0;
  	spin_lock_init(&candidate->lock);
76181c134   David Howells   KEYS: Make reques...
104
  	mutex_init(&candidate->cons_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
110
111
112
  
  	rb_link_node(&candidate->node, parent, p);
  	rb_insert_color(&candidate->node, &key_user_tree);
  	spin_unlock(&key_user_lock);
  	user = candidate;
  	goto out;
  
  	/* okay - we found a user record for this UID */
973c9f4f4   David Howells   KEYS: Fix up comm...
113
  found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
115
  	atomic_inc(&user->usage);
  	spin_unlock(&key_user_lock);
a7f988ba3   Jesper Juhl   [PATCH] kfree cle...
116
  	kfree(candidate);
973c9f4f4   David Howells   KEYS: Fix up comm...
117
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  	return user;
a8b17ed01   David Howells   KEYS: Do some sty...
119
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
122
   * Dispose of a user structure
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
127
128
   */
  void key_user_put(struct key_user *user)
  {
  	if (atomic_dec_and_lock(&user->usage, &key_user_lock)) {
  		rb_erase(&user->node, &key_user_tree);
  		spin_unlock(&key_user_lock);
1d1e97562   Serge E. Hallyn   keys: distinguish...
129
  		put_user_ns(user->user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
  
  		kfree(user);
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
133
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
136
137
   * Allocate a serial number for a key.  These are assigned randomly to avoid
   * security issues through covert channel problems.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
141
142
   */
  static inline void key_alloc_serial(struct key *key)
  {
  	struct rb_node *parent, **p;
  	struct key *xkey;
e51f6d343   Michael LeMay   [PATCH] keys: all...
143
  	/* propose a random serial number and look for a hole for it in the
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  	 * serial number tree */
e51f6d343   Michael LeMay   [PATCH] keys: all...
145
146
147
148
149
150
151
  	do {
  		get_random_bytes(&key->serial, sizeof(key->serial));
  
  		key->serial >>= 1; /* negative numbers are not permitted */
  	} while (key->serial < 3);
  
  	spin_lock(&key_serial_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152

9ad0830f3   David Howells   [PATCH] Keys: Fix...
153
  attempt_insertion:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	parent = NULL;
  	p = &key_serial_tree.rb_node;
  
  	while (*p) {
  		parent = *p;
  		xkey = rb_entry(parent, struct key, serial_node);
  
  		if (key->serial < xkey->serial)
  			p = &(*p)->rb_left;
  		else if (key->serial > xkey->serial)
  			p = &(*p)->rb_right;
  		else
  			goto serial_exists;
  	}
9ad0830f3   David Howells   [PATCH] Keys: Fix...
168
169
170
171
172
173
174
  
  	/* we've found a suitable hole - arrange for this key to occupy it */
  	rb_link_node(&key->serial_node, parent, p);
  	rb_insert_color(&key->serial_node, &key_serial_tree);
  
  	spin_unlock(&key_serial_lock);
  	return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
  
  	/* we found a key with the proposed serial number - walk the tree from
  	 * that point looking for the next unused serial number */
e51f6d343   Michael LeMay   [PATCH] keys: all...
178
  serial_exists:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  	for (;;) {
e51f6d343   Michael LeMay   [PATCH] keys: all...
180
  		key->serial++;
9ad0830f3   David Howells   [PATCH] Keys: Fix...
181
182
183
184
  		if (key->serial < 3) {
  			key->serial = 3;
  			goto attempt_insertion;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  
  		parent = rb_next(parent);
  		if (!parent)
9ad0830f3   David Howells   [PATCH] Keys: Fix...
188
  			goto attempt_insertion;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
  
  		xkey = rb_entry(parent, struct key, serial_node);
  		if (key->serial < xkey->serial)
9ad0830f3   David Howells   [PATCH] Keys: Fix...
192
  			goto attempt_insertion;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
194
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195

973c9f4f4   David Howells   KEYS: Fix up comm...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  /**
   * key_alloc - Allocate a key of the specified type.
   * @type: The type of key to allocate.
   * @desc: The key description to allow the key to be searched out.
   * @uid: The owner of the new key.
   * @gid: The group ID for the new key's group permissions.
   * @cred: The credentials specifying UID namespace.
   * @perm: The permissions mask of the new key.
   * @flags: Flags specifying quota properties.
   *
   * Allocate a key of the specified type with the attributes given.  The key is
   * returned in an uninstantiated state and the caller needs to instantiate the
   * key before returning.
   *
   * The user's key count quota is updated to reflect the creation of the key and
   * the user's key data quota has the default for the key type reserved.  The
   * instantiation function should amend this as necessary.  If insufficient
   * quota is available, -EDQUOT will be returned.
   *
   * The LSM security modules can prevent a key being created, in which case
   * -EACCES will be returned.
   *
   * Returns a pointer to the new key if successful and an error code otherwise.
   *
   * Note that the caller needs to ensure the key type isn't uninstantiated.
   * Internally this can be done by locking key_types_sem.  Externally, this can
   * be done by either never unregistering the key type, or making sure
   * key_alloc() calls don't race with module unloading.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
225
   */
  struct key *key_alloc(struct key_type *type, const char *desc,
d84f4f992   David Howells   CRED: Inaugurate ...
226
  		      uid_t uid, gid_t gid, const struct cred *cred,
7e047ef5f   David Howells   [PATCH] keys: sor...
227
  		      key_perm_t perm, unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
  {
  	struct key_user *user = NULL;
  	struct key *key;
  	size_t desclen, quotalen;
29db91906   David Howells   [PATCH] Keys: Add...
232
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
236
  
  	key = ERR_PTR(-EINVAL);
  	if (!desc || !*desc)
  		goto error;
b9fffa387   David Howells   KEYS: Add a key t...
237
238
239
240
241
242
243
  	if (type->vet_description) {
  		ret = type->vet_description(desc);
  		if (ret < 0) {
  			key = ERR_PTR(ret);
  			goto error;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
  	desclen = strlen(desc) + 1;
  	quotalen = desclen + type->def_datalen;
  
  	/* get hold of the key tracking for this user */
1d1e97562   Serge E. Hallyn   keys: distinguish...
248
  	user = key_user_lookup(uid, cred->user->user_ns);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
  	if (!user)
  		goto no_memory_1;
  
  	/* check that the user's quota permits allocation of another key and
  	 * its description */
7e047ef5f   David Howells   [PATCH] keys: sor...
254
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
0b77f5bfb   David Howells   keys: make the ke...
255
256
257
258
  		unsigned maxkeys = (uid == 0) ?
  			key_quota_root_maxkeys : key_quota_maxkeys;
  		unsigned maxbytes = (uid == 0) ?
  			key_quota_root_maxbytes : key_quota_maxbytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  		spin_lock(&user->lock);
7e047ef5f   David Howells   [PATCH] keys: sor...
260
  		if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
0b77f5bfb   David Howells   keys: make the ke...
261
262
263
  			if (user->qnkeys + 1 >= maxkeys ||
  			    user->qnbytes + quotalen >= maxbytes ||
  			    user->qnbytes + quotalen < user->qnbytes)
7e047ef5f   David Howells   [PATCH] keys: sor...
264
265
  				goto no_quota;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
270
271
272
  
  		user->qnkeys++;
  		user->qnbytes += quotalen;
  		spin_unlock(&user->lock);
  	}
  
  	/* allocate and initialise the key and its description */
e94b17660   Christoph Lameter   [PATCH] slab: rem...
273
  	key = kmem_cache_alloc(key_jar, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
  	if (!key)
  		goto no_memory_2;
  
  	if (desc) {
48ad504ee   Eric Sesterhenn   [PATCH] security/...
278
  		key->description = kmemdup(desc, desclen, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
  		if (!key->description)
  			goto no_memory_3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
  	}
  
  	atomic_set(&key->usage, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  	init_rwsem(&key->sem);
7845bc396   David Howells   KEYS: Give key ty...
285
  	lockdep_set_class(&key->sem, &type->lock_class);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
292
293
294
295
  	key->type = type;
  	key->user = user;
  	key->quotalen = quotalen;
  	key->datalen = type->def_datalen;
  	key->uid = uid;
  	key->gid = gid;
  	key->perm = perm;
  	key->flags = 0;
  	key->expiry = 0;
  	key->payload.data = NULL;
29db91906   David Howells   [PATCH] Keys: Add...
296
  	key->security = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297

7e047ef5f   David Howells   [PATCH] keys: sor...
298
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
76d8aeabf   David Howells   [PATCH] keys: Dis...
299
  		key->flags |= 1 << KEY_FLAG_IN_QUOTA;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
304
305
  
  	memset(&key->type_data, 0, sizeof(key->type_data));
  
  #ifdef KEY_DEBUGGING
  	key->magic = KEY_DEBUG_MAGIC;
  #endif
29db91906   David Howells   [PATCH] Keys: Add...
306
  	/* let the security module know about the key */
d84f4f992   David Howells   CRED: Inaugurate ...
307
  	ret = security_key_alloc(key, cred, flags);
29db91906   David Howells   [PATCH] Keys: Add...
308
309
  	if (ret < 0)
  		goto security_error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
310
311
312
  	/* publish the key by giving it a serial number */
  	atomic_inc(&user->nkeys);
  	key_alloc_serial(key);
29db91906   David Howells   [PATCH] Keys: Add...
313
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  	return key;
29db91906   David Howells   [PATCH] Keys: Add...
315
316
  security_error:
  	kfree(key->description);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  	kmem_cache_free(key_jar, key);
7e047ef5f   David Howells   [PATCH] keys: sor...
318
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
323
324
  		spin_lock(&user->lock);
  		user->qnkeys--;
  		user->qnbytes -= quotalen;
  		spin_unlock(&user->lock);
  	}
  	key_user_put(user);
29db91906   David Howells   [PATCH] Keys: Add...
325
326
327
328
329
330
  	key = ERR_PTR(ret);
  	goto error;
  
  no_memory_3:
  	kmem_cache_free(key_jar, key);
  no_memory_2:
7e047ef5f   David Howells   [PATCH] keys: sor...
331
  	if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
29db91906   David Howells   [PATCH] Keys: Add...
332
333
334
335
336
337
338
  		spin_lock(&user->lock);
  		user->qnkeys--;
  		user->qnbytes -= quotalen;
  		spin_unlock(&user->lock);
  	}
  	key_user_put(user);
  no_memory_1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
340
  	key = ERR_PTR(-ENOMEM);
  	goto error;
29db91906   David Howells   [PATCH] Keys: Add...
341
  no_quota:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
343
344
345
  	spin_unlock(&user->lock);
  	key_user_put(user);
  	key = ERR_PTR(-EDQUOT);
  	goto error;
a8b17ed01   David Howells   KEYS: Do some sty...
346
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  EXPORT_SYMBOL(key_alloc);
973c9f4f4   David Howells   KEYS: Fix up comm...
348
349
350
351
352
353
354
355
356
357
  /**
   * key_payload_reserve - Adjust data quota reservation for the key's payload
   * @key: The key to make the reservation for.
   * @datalen: The amount of data payload the caller now wants.
   *
   * Adjust the amount of the owning user's key data quota that a key reserves.
   * If the amount is increased, then -EDQUOT may be returned if there isn't
   * enough free quota available.
   *
   * If successful, 0 is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
   */
  int key_payload_reserve(struct key *key, size_t datalen)
  {
c5b60b5e6   Justin P. Mattock   security: whitesp...
361
  	int delta = (int)datalen - key->datalen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
  	int ret = 0;
  
  	key_check(key);
  
  	/* contemplate the quota adjustment */
76d8aeabf   David Howells   [PATCH] keys: Dis...
367
  	if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
0b77f5bfb   David Howells   keys: make the ke...
368
369
  		unsigned maxbytes = (key->user->uid == 0) ?
  			key_quota_root_maxbytes : key_quota_maxbytes;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
  		spin_lock(&key->user->lock);
  
  		if (delta > 0 &&
0b77f5bfb   David Howells   keys: make the ke...
373
374
  		    (key->user->qnbytes + delta >= maxbytes ||
  		     key->user->qnbytes + delta < key->user->qnbytes)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
380
381
382
383
384
385
386
387
388
  			ret = -EDQUOT;
  		}
  		else {
  			key->user->qnbytes += delta;
  			key->quotalen += delta;
  		}
  		spin_unlock(&key->user->lock);
  	}
  
  	/* change the recorded data length if that didn't generate an error */
  	if (ret == 0)
  		key->datalen = datalen;
  
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
389
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  EXPORT_SYMBOL(key_payload_reserve);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
392
393
394
395
   * Instantiate a key and link it into the target keyring atomically.  Must be
   * called with the target keyring's semaphore writelocked.  The target key's
   * semaphore need not be locked as instantiation is serialised by
   * key_construction_mutex.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
   */
  static int __key_instantiate_and_link(struct key *key,
  				      const void *data,
  				      size_t datalen,
3e30148c3   David Howells   [PATCH] Keys: Mak...
400
  				      struct key *keyring,
f70e2e061   David Howells   KEYS: Do prealloc...
401
  				      struct key *authkey,
ceb73c120   David Howells   KEYS: Fix __key_l...
402
  				      unsigned long *_prealloc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
407
408
409
410
  {
  	int ret, awaken;
  
  	key_check(key);
  	key_check(keyring);
  
  	awaken = 0;
  	ret = -EBUSY;
76181c134   David Howells   KEYS: Make reques...
411
  	mutex_lock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
  
  	/* can't instantiate twice */
76d8aeabf   David Howells   [PATCH] keys: Dis...
414
  	if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
  		/* instantiate the key */
  		ret = key->type->instantiate(key, data, datalen);
  
  		if (ret == 0) {
  			/* mark the key as being instantiated */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  			atomic_inc(&key->user->nikeys);
76d8aeabf   David Howells   [PATCH] keys: Dis...
421
  			set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422

76d8aeabf   David Howells   [PATCH] keys: Dis...
423
  			if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  				awaken = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
  
  			/* and link it into the destination keyring */
  			if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
428
  				__key_link(keyring, key, _prealloc);
3e30148c3   David Howells   [PATCH] Keys: Mak...
429
430
  
  			/* disable the authorisation key */
d84f4f992   David Howells   CRED: Inaugurate ...
431
432
  			if (authkey)
  				key_revoke(authkey);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
  		}
  	}
76181c134   David Howells   KEYS: Make reques...
435
  	mutex_unlock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
437
438
  
  	/* wake up anyone waiting for a key to be constructed */
  	if (awaken)
76181c134   David Howells   KEYS: Make reques...
439
  		wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
  
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
442
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443

973c9f4f4   David Howells   KEYS: Fix up comm...
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  /**
   * key_instantiate_and_link - Instantiate a key and link it into the keyring.
   * @key: The key to instantiate.
   * @data: The data to use to instantiate the keyring.
   * @datalen: The length of @data.
   * @keyring: Keyring to create a link in on success (or NULL).
   * @authkey: The authorisation token permitting instantiation.
   *
   * Instantiate a key that's in the uninstantiated state using the provided data
   * and, if successful, link it in to the destination keyring if one is
   * supplied.
   *
   * If successful, 0 is returned, the authorisation token is revoked and anyone
   * waiting for the key is woken up.  If the key was already instantiated,
   * -EBUSY will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
461
462
   */
  int key_instantiate_and_link(struct key *key,
  			     const void *data,
  			     size_t datalen,
3e30148c3   David Howells   [PATCH] Keys: Mak...
463
  			     struct key *keyring,
d84f4f992   David Howells   CRED: Inaugurate ...
464
  			     struct key *authkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
466
  	unsigned long prealloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  	int ret;
f70e2e061   David Howells   KEYS: Do prealloc...
468
469
470
471
472
473
  	if (keyring) {
  		ret = __key_link_begin(keyring, key->type, key->description,
  				       &prealloc);
  		if (ret < 0)
  			return ret;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474

f70e2e061   David Howells   KEYS: Do prealloc...
475
476
  	ret = __key_instantiate_and_link(key, data, datalen, keyring, authkey,
  					 &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
  
  	if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
479
  		__key_link_end(keyring, key->type, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
  
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
482
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
  
  EXPORT_SYMBOL(key_instantiate_and_link);
973c9f4f4   David Howells   KEYS: Fix up comm...
485
  /**
fdd1b9458   David Howells   KEYS: Add a new k...
486
   * key_reject_and_link - Negatively instantiate a key and link it into the keyring.
973c9f4f4   David Howells   KEYS: Fix up comm...
487
488
   * @key: The key to instantiate.
   * @timeout: The timeout on the negative key.
fdd1b9458   David Howells   KEYS: Add a new k...
489
   * @error: The error to return when the key is hit.
973c9f4f4   David Howells   KEYS: Fix up comm...
490
491
492
493
   * @keyring: Keyring to create a link in on success (or NULL).
   * @authkey: The authorisation token permitting instantiation.
   *
   * Negatively instantiate a key that's in the uninstantiated state and, if
fdd1b9458   David Howells   KEYS: Add a new k...
494
495
496
   * successful, set its timeout and stored error and link it in to the
   * destination keyring if one is supplied.  The key and any links to the key
   * will be automatically garbage collected after the timeout expires.
973c9f4f4   David Howells   KEYS: Fix up comm...
497
498
   *
   * Negative keys are used to rate limit repeated request_key() calls by causing
fdd1b9458   David Howells   KEYS: Add a new k...
499
500
   * them to return the stored error code (typically ENOKEY) until the negative
   * key expires.
973c9f4f4   David Howells   KEYS: Fix up comm...
501
502
503
504
   *
   * If successful, 0 is returned, the authorisation token is revoked and anyone
   * waiting for the key is woken up.  If the key was already instantiated,
   * -EBUSY will be returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
   */
fdd1b9458   David Howells   KEYS: Add a new k...
506
  int key_reject_and_link(struct key *key,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  			unsigned timeout,
fdd1b9458   David Howells   KEYS: Add a new k...
508
  			unsigned error,
3e30148c3   David Howells   [PATCH] Keys: Mak...
509
  			struct key *keyring,
d84f4f992   David Howells   CRED: Inaugurate ...
510
  			struct key *authkey)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
512
  	unsigned long prealloc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  	struct timespec now;
f70e2e061   David Howells   KEYS: Do prealloc...
514
  	int ret, awaken, link_ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
520
521
522
  
  	key_check(key);
  	key_check(keyring);
  
  	awaken = 0;
  	ret = -EBUSY;
  
  	if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
523
524
  		link_ret = __key_link_begin(keyring, key->type,
  					    key->description, &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525

76181c134   David Howells   KEYS: Make reques...
526
  	mutex_lock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
  
  	/* can't instantiate twice */
76d8aeabf   David Howells   [PATCH] keys: Dis...
529
  	if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  		/* mark the key as being negatively instantiated */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  		atomic_inc(&key->user->nikeys);
76d8aeabf   David Howells   [PATCH] keys: Dis...
532
533
  		set_bit(KEY_FLAG_NEGATIVE, &key->flags);
  		set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
fdd1b9458   David Howells   KEYS: Add a new k...
534
  		key->type_data.reject_error = -error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
  		now = current_kernel_time();
  		key->expiry = now.tv_sec + timeout;
c08ef808e   David Howells   KEYS: Fix garbage...
537
  		key_schedule_gc(key->expiry + key_gc_delay);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538

76d8aeabf   David Howells   [PATCH] keys: Dis...
539
  		if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
  			awaken = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
  		ret = 0;
  
  		/* and link it into the destination keyring */
f70e2e061   David Howells   KEYS: Do prealloc...
545
546
  		if (keyring && link_ret == 0)
  			__key_link(keyring, key, &prealloc);
3e30148c3   David Howells   [PATCH] Keys: Mak...
547
548
  
  		/* disable the authorisation key */
d84f4f992   David Howells   CRED: Inaugurate ...
549
550
  		if (authkey)
  			key_revoke(authkey);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  	}
76181c134   David Howells   KEYS: Make reques...
552
  	mutex_unlock(&key_construction_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
  
  	if (keyring)
f70e2e061   David Howells   KEYS: Do prealloc...
555
  		__key_link_end(keyring, key->type, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
558
  
  	/* wake up anyone waiting for a key to be constructed */
  	if (awaken)
76181c134   David Howells   KEYS: Make reques...
559
  		wake_up_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560

f70e2e061   David Howells   KEYS: Do prealloc...
561
  	return ret == 0 ? link_ret : ret;
a8b17ed01   David Howells   KEYS: Do some sty...
562
  }
fdd1b9458   David Howells   KEYS: Add a new k...
563
  EXPORT_SYMBOL(key_reject_and_link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564

973c9f4f4   David Howells   KEYS: Fix up comm...
565
566
567
568
569
570
571
  /**
   * key_put - Discard a reference to a key.
   * @key: The key to discard a reference from.
   *
   * Discard a reference to a key, and when all the references are gone, we
   * schedule the cleanup task to come and pull it out of the tree in process
   * context at some later time.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
574
575
576
577
578
   */
  void key_put(struct key *key)
  {
  	if (key) {
  		key_check(key);
  
  		if (atomic_dec_and_test(&key->usage))
0c061b570   David Howells   KEYS: Correctly d...
579
  			queue_work(system_nrt_wq, &key_gc_work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	}
a8b17ed01   David Howells   KEYS: Do some sty...
581
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
  EXPORT_SYMBOL(key_put);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
584
   * Find a key by its serial number.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
   */
  struct key *key_lookup(key_serial_t id)
  {
  	struct rb_node *n;
  	struct key *key;
  
  	spin_lock(&key_serial_lock);
  
  	/* search the tree for the specified key */
  	n = key_serial_tree.rb_node;
  	while (n) {
  		key = rb_entry(n, struct key, serial_node);
  
  		if (id < key->serial)
  			n = n->rb_left;
  		else if (id > key->serial)
  			n = n->rb_right;
  		else
  			goto found;
  	}
973c9f4f4   David Howells   KEYS: Fix up comm...
605
  not_found:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
606
607
  	key = ERR_PTR(-ENOKEY);
  	goto error;
973c9f4f4   David Howells   KEYS: Fix up comm...
608
  found:
5593122ee   David Howells   KEYS: Deal with d...
609
610
  	/* pretend it doesn't exist if it is awaiting deletion */
  	if (atomic_read(&key->usage) == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
615
616
  		goto not_found;
  
  	/* this races with key_put(), but that doesn't matter since key_put()
  	 * doesn't actually change the key
  	 */
  	atomic_inc(&key->usage);
973c9f4f4   David Howells   KEYS: Fix up comm...
617
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
  	spin_unlock(&key_serial_lock);
  	return key;
a8b17ed01   David Howells   KEYS: Do some sty...
620
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
623
624
625
626
   * Find and lock the specified key type against removal.
   *
   * We return with the sem read-locked if successful.  If the type wasn't
   * available -ENOKEY is returned instead.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
   */
  struct key_type *key_type_lookup(const char *type)
  {
  	struct key_type *ktype;
  
  	down_read(&key_types_sem);
  
  	/* look up the key type to see if it's one of the registered kernel
  	 * types */
  	list_for_each_entry(ktype, &key_types_list, link) {
  		if (strcmp(ktype->name, type) == 0)
  			goto found_kernel_type;
  	}
  
  	up_read(&key_types_sem);
  	ktype = ERR_PTR(-ENOKEY);
973c9f4f4   David Howells   KEYS: Fix up comm...
643
  found_kernel_type:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
  	return ktype;
a8b17ed01   David Howells   KEYS: Do some sty...
645
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
648
   * Unlock a key type locked by key_type_lookup().
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649
650
651
652
   */
  void key_type_put(struct key_type *ktype)
  {
  	up_read(&key_types_sem);
a8b17ed01   David Howells   KEYS: Do some sty...
653
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
656
657
658
659
   * Attempt to update an existing key.
   *
   * The key is given to us with an incremented refcount that we need to discard
   * if we get an error.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
   */
664cceb00   David Howells   [PATCH] Keys: Add...
661
662
  static inline key_ref_t __key_update(key_ref_t key_ref,
  				     const void *payload, size_t plen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  {
664cceb00   David Howells   [PATCH] Keys: Add...
664
  	struct key *key = key_ref_to_ptr(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665
666
667
  	int ret;
  
  	/* need write permission on the key to update it */
29db91906   David Howells   [PATCH] Keys: Add...
668
669
  	ret = key_permission(key_ref, KEY_WRITE);
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
673
674
675
676
677
678
  		goto error;
  
  	ret = -EEXIST;
  	if (!key->type->update)
  		goto error;
  
  	down_write(&key->sem);
  
  	ret = key->type->update(key, payload, plen);
76d8aeabf   David Howells   [PATCH] keys: Dis...
679
  	if (ret == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  		/* updating a negative key instantiates it */
76d8aeabf   David Howells   [PATCH] keys: Dis...
681
  		clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
684
685
686
  
  	up_write(&key->sem);
  
  	if (ret < 0)
  		goto error;
664cceb00   David Howells   [PATCH] Keys: Add...
687
688
  out:
  	return key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689

664cceb00   David Howells   [PATCH] Keys: Add...
690
  error:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  	key_put(key);
664cceb00   David Howells   [PATCH] Keys: Add...
692
  	key_ref = ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
  	goto out;
a8b17ed01   David Howells   KEYS: Do some sty...
694
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695

973c9f4f4   David Howells   KEYS: Fix up comm...
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
  /**
   * key_create_or_update - Update or create and instantiate a key.
   * @keyring_ref: A pointer to the destination keyring with possession flag.
   * @type: The type of key.
   * @description: The searchable description for the key.
   * @payload: The data to use to instantiate or update the key.
   * @plen: The length of @payload.
   * @perm: The permissions mask for a new key.
   * @flags: The quota flags for a new key.
   *
   * Search the destination keyring for a key of the same description and if one
   * is found, update it, otherwise create and instantiate a new one and create a
   * link to it from that keyring.
   *
   * If perm is KEY_PERM_UNDEF then an appropriate key permissions mask will be
   * concocted.
   *
   * Returns a pointer to the new key if successful, -ENODEV if the key type
   * wasn't available, -ENOTDIR if the keyring wasn't a keyring, -EACCES if the
   * caller isn't permitted to modify the keyring or the LSM did not permit
   * creation of the key.
   *
   * On success, the possession flag from the keyring ref will be tacked on to
   * the key ref before it is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
   */
664cceb00   David Howells   [PATCH] Keys: Add...
721
722
723
724
725
  key_ref_t key_create_or_update(key_ref_t keyring_ref,
  			       const char *type,
  			       const char *description,
  			       const void *payload,
  			       size_t plen,
6b79ccb51   Arun Raghavan   keys: allow clien...
726
  			       key_perm_t perm,
7e047ef5f   David Howells   [PATCH] keys: sor...
727
  			       unsigned long flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
  {
ceb73c120   David Howells   KEYS: Fix __key_l...
729
  	unsigned long prealloc;
d84f4f992   David Howells   CRED: Inaugurate ...
730
  	const struct cred *cred = current_cred();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
  	struct key_type *ktype;
664cceb00   David Howells   [PATCH] Keys: Add...
732
  	struct key *keyring, *key = NULL;
664cceb00   David Howells   [PATCH] Keys: Add...
733
  	key_ref_t key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
737
738
  	/* look up the key type to see if it's one of the registered kernel
  	 * types */
  	ktype = key_type_lookup(type);
  	if (IS_ERR(ktype)) {
664cceb00   David Howells   [PATCH] Keys: Add...
739
  		key_ref = ERR_PTR(-ENODEV);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
  		goto error;
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
742
  	key_ref = ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
  	if (!ktype->match || !ktype->instantiate)
  		goto error_2;
664cceb00   David Howells   [PATCH] Keys: Add...
745
746
747
  	keyring = key_ref_to_ptr(keyring_ref);
  
  	key_check(keyring);
c3a9d6541   David Howells   [Security] Keys: ...
748
749
750
  	key_ref = ERR_PTR(-ENOTDIR);
  	if (keyring->type != &key_type_keyring)
  		goto error_2;
f70e2e061   David Howells   KEYS: Do prealloc...
751
752
753
  	ret = __key_link_begin(keyring, ktype, description, &prealloc);
  	if (ret < 0)
  		goto error_2;
664cceb00   David Howells   [PATCH] Keys: Add...
754
755
756
  
  	/* if we're going to allocate a new key, we're going to have
  	 * to modify the keyring */
29db91906   David Howells   [PATCH] Keys: Add...
757
758
759
  	ret = key_permission(keyring_ref, KEY_WRITE);
  	if (ret < 0) {
  		key_ref = ERR_PTR(ret);
664cceb00   David Howells   [PATCH] Keys: Add...
760
  		goto error_3;
29db91906   David Howells   [PATCH] Keys: Add...
761
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
762

1d9b7d97d   David Howells   [PATCH] Keys: Rep...
763
764
765
  	/* if it's possible to update this type of key, search for an existing
  	 * key of the same type and description in the destination keyring and
  	 * update that instead if possible
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766
  	 */
1d9b7d97d   David Howells   [PATCH] Keys: Rep...
767
768
769
770
771
772
  	if (ktype->update) {
  		key_ref = __keyring_search_one(keyring_ref, ktype, description,
  					       0);
  		if (!IS_ERR(key_ref))
  			goto found_matching_key;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773

6b79ccb51   Arun Raghavan   keys: allow clien...
774
775
776
777
  	/* if the client doesn't provide, decide on the permissions we want */
  	if (perm == KEY_PERM_UNDEF) {
  		perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
  		perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778

6b79ccb51   Arun Raghavan   keys: allow clien...
779
780
  		if (ktype->read)
  			perm |= KEY_POS_READ | KEY_USR_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781

6b79ccb51   Arun Raghavan   keys: allow clien...
782
783
784
  		if (ktype == &key_type_keyring || ktype->update)
  			perm |= KEY_USR_WRITE;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
785
786
  
  	/* allocate a new key */
d84f4f992   David Howells   CRED: Inaugurate ...
787
788
  	key = key_alloc(ktype, description, cred->fsuid, cred->fsgid, cred,
  			perm, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
789
  	if (IS_ERR(key)) {
e231c2ee6   David Howells   Convert ERR_PTR(P...
790
  		key_ref = ERR_CAST(key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
791
792
793
794
  		goto error_3;
  	}
  
  	/* instantiate it and link it into the target keyring */
f70e2e061   David Howells   KEYS: Do prealloc...
795
796
  	ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL,
  					 &prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
  	if (ret < 0) {
  		key_put(key);
664cceb00   David Howells   [PATCH] Keys: Add...
799
800
  		key_ref = ERR_PTR(ret);
  		goto error_3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
801
  	}
664cceb00   David Howells   [PATCH] Keys: Add...
802
  	key_ref = make_key_ref(key, is_key_possessed(keyring_ref));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
   error_3:
f70e2e061   David Howells   KEYS: Do prealloc...
804
  	__key_link_end(keyring, ktype, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
806
807
   error_2:
  	key_type_put(ktype);
   error:
664cceb00   David Howells   [PATCH] Keys: Add...
808
  	return key_ref;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
812
813
  
   found_matching_key:
  	/* we found a matching key, so we're going to try to update it
  	 * - we can drop the locks first as we have the key pinned
  	 */
f70e2e061   David Howells   KEYS: Do prealloc...
814
  	__key_link_end(keyring, ktype, prealloc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
815
  	key_type_put(ktype);
664cceb00   David Howells   [PATCH] Keys: Add...
816
  	key_ref = __key_update(key_ref, payload, plen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  	goto error;
a8b17ed01   David Howells   KEYS: Do some sty...
818
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
819
  EXPORT_SYMBOL(key_create_or_update);
973c9f4f4   David Howells   KEYS: Fix up comm...
820
821
822
823
824
825
826
827
828
829
830
831
  /**
   * key_update - Update a key's contents.
   * @key_ref: The pointer (plus possession flag) to the key.
   * @payload: The data to be used to update the key.
   * @plen: The length of @payload.
   *
   * Attempt to update the contents of a key with the given payload data.  The
   * caller must be granted Write permission on the key.  Negative keys can be
   * instantiated by this method.
   *
   * Returns 0 on success, -EACCES if not permitted and -EOPNOTSUPP if the key
   * type does not support updating.  The key type may return other errors.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
   */
664cceb00   David Howells   [PATCH] Keys: Add...
833
  int key_update(key_ref_t key_ref, const void *payload, size_t plen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
  {
664cceb00   David Howells   [PATCH] Keys: Add...
835
  	struct key *key = key_ref_to_ptr(key_ref);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
837
838
839
840
  	int ret;
  
  	key_check(key);
  
  	/* the key must be writable */
29db91906   David Howells   [PATCH] Keys: Add...
841
842
  	ret = key_permission(key_ref, KEY_WRITE);
  	if (ret < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
845
846
847
848
  		goto error;
  
  	/* attempt to update it if supported */
  	ret = -EOPNOTSUPP;
  	if (key->type->update) {
  		down_write(&key->sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849

29db91906   David Howells   [PATCH] Keys: Add...
850
  		ret = key->type->update(key, payload, plen);
76d8aeabf   David Howells   [PATCH] keys: Dis...
851
  		if (ret == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
  			/* updating a negative key instantiates it */
76d8aeabf   David Howells   [PATCH] keys: Dis...
853
  			clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
854
855
856
857
858
859
  
  		up_write(&key->sem);
  	}
  
   error:
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
860
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
  EXPORT_SYMBOL(key_update);
973c9f4f4   David Howells   KEYS: Fix up comm...
862
863
864
865
866
867
868
869
  /**
   * key_revoke - Revoke a key.
   * @key: The key to be revoked.
   *
   * Mark a key as being revoked and ask the type to free up its resources.  The
   * revocation timeout is set and the key and all its links will be
   * automatically garbage collected after key_gc_delay amount of time if they
   * are not manually dealt with first.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
870
871
872
   */
  void key_revoke(struct key *key)
  {
5d135440f   David Howells   KEYS: Add garbage...
873
874
  	struct timespec now;
  	time_t time;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  	key_check(key);
76181c134   David Howells   KEYS: Make reques...
876
877
878
879
880
881
882
883
  	/* make sure no one's trying to change or use the key when we mark it
  	 * - we tell lockdep that we might nest because we might be revoking an
  	 *   authorisation key whilst holding the sem on a key we've just
  	 *   instantiated
  	 */
  	down_write_nested(&key->sem, 1);
  	if (!test_and_set_bit(KEY_FLAG_REVOKED, &key->flags) &&
  	    key->type->revoke)
04c567d93   David Howells   [PATCH] Keys: Fix...
884
  		key->type->revoke(key);
5d135440f   David Howells   KEYS: Add garbage...
885
886
887
888
889
  	/* set the death time to no more than the expiry time */
  	now = current_kernel_time();
  	time = now.tv_sec;
  	if (key->revoked_at == 0 || key->revoked_at > time) {
  		key->revoked_at = time;
c08ef808e   David Howells   KEYS: Fix garbage...
890
  		key_schedule_gc(key->revoked_at + key_gc_delay);
5d135440f   David Howells   KEYS: Add garbage...
891
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  	up_write(&key->sem);
a8b17ed01   David Howells   KEYS: Do some sty...
893
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  EXPORT_SYMBOL(key_revoke);
973c9f4f4   David Howells   KEYS: Fix up comm...
895
896
897
898
899
900
901
  /**
   * register_key_type - Register a type of key.
   * @ktype: The new key type.
   *
   * Register a new key type.
   *
   * Returns 0 on success or -EEXIST if a type of this name already exists.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
904
905
906
   */
  int register_key_type(struct key_type *ktype)
  {
  	struct key_type *p;
  	int ret;
7845bc396   David Howells   KEYS: Give key ty...
907
  	memset(&ktype->lock_class, 0, sizeof(ktype->lock_class));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
911
912
913
914
915
916
917
918
919
  	ret = -EEXIST;
  	down_write(&key_types_sem);
  
  	/* disallow key types with the same name */
  	list_for_each_entry(p, &key_types_list, link) {
  		if (strcmp(p->name, ktype->name) == 0)
  			goto out;
  	}
  
  	/* store the type */
  	list_add(&ktype->link, &key_types_list);
  	ret = 0;
973c9f4f4   David Howells   KEYS: Fix up comm...
920
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
  	up_write(&key_types_sem);
  	return ret;
a8b17ed01   David Howells   KEYS: Do some sty...
923
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
  EXPORT_SYMBOL(register_key_type);
973c9f4f4   David Howells   KEYS: Fix up comm...
925
926
927
928
929
930
931
  /**
   * unregister_key_type - Unregister a type of key.
   * @ktype: The key type.
   *
   * Unregister a key type and mark all the extant keys of this type as dead.
   * Those keys of this type are then destroyed to get rid of their payloads and
   * they and their links will be garbage collected as soon as possible.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
   */
  void unregister_key_type(struct key_type *ktype)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
935
  	down_write(&key_types_sem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
  	list_del_init(&ktype->link);
0c061b570   David Howells   KEYS: Correctly d...
937
938
939
  	downgrade_write(&key_types_sem);
  	key_gc_keytype(ktype);
  	up_read(&key_types_sem);
a8b17ed01   David Howells   KEYS: Do some sty...
940
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
941
  EXPORT_SYMBOL(unregister_key_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  /*
973c9f4f4   David Howells   KEYS: Fix up comm...
943
   * Initialise the key management state.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
945
946
947
948
   */
  void __init key_init(void)
  {
  	/* allocate a slab in which we can store keys */
  	key_jar = kmem_cache_create("key_jar", sizeof(struct key),
20c2df83d   Paul Mundt   mm: Remove slab d...
949
  			0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
951
952
953
954
955
956
957
958
959
960
961
962
  
  	/* add the special key types */
  	list_add_tail(&key_type_keyring.link, &key_types_list);
  	list_add_tail(&key_type_dead.link, &key_types_list);
  	list_add_tail(&key_type_user.link, &key_types_list);
  
  	/* record the root user tracking */
  	rb_link_node(&root_key_user.node,
  		     NULL,
  		     &key_user_tree.rb_node);
  
  	rb_insert_color(&root_key_user.node,
  			&key_user_tree);
a8b17ed01   David Howells   KEYS: Do some sty...
963
  }