[PATCH] move capable() to capability.h
[pandora-kernel.git] / security / keys / keyctl.c
index a6516a6..90db5c7 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/syscalls.h>
 #include <linux/keyctl.h>
 #include <linux/fs.h>
+#include <linux/capability.h>
 #include <linux/err.h>
 #include <asm/uaccess.h>
 #include "internal.h"
@@ -34,7 +35,7 @@ asmlinkage long sys_add_key(const char __user *_type,
                            size_t plen,
                            key_serial_t ringid)
 {
-       struct key *keyring, *key;
+       key_ref_t keyring_ref, key_ref;
        char type[32], *description;
        void *payload;
        long dlen, ret;
@@ -86,25 +87,25 @@ asmlinkage long sys_add_key(const char __user *_type,
        }
 
        /* find the target keyring (which must be writable) */
-       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-       if (IS_ERR(keyring)) {
-               ret = PTR_ERR(keyring);
+       keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+       if (IS_ERR(keyring_ref)) {
+               ret = PTR_ERR(keyring_ref);
                goto error3;
        }
 
        /* create or update the requested key and add it to the target
         * keyring */
-       key = key_create_or_update(keyring, type, description,
-                                  payload, plen, 0);
-       if (!IS_ERR(key)) {
-               ret = key->serial;
-               key_put(key);
+       key_ref = key_create_or_update(keyring_ref, type, description,
+                                      payload, plen, 0);
+       if (!IS_ERR(key_ref)) {
+               ret = key_ref_to_ptr(key_ref)->serial;
+               key_ref_put(key_ref);
        }
        else {
-               ret = PTR_ERR(key);
+               ret = PTR_ERR(key_ref);
        }
 
-       key_put(keyring);
+       key_ref_put(keyring_ref);
  error3:
        kfree(payload);
  error2:
@@ -131,7 +132,8 @@ asmlinkage long sys_request_key(const char __user *_type,
                                key_serial_t destringid)
 {
        struct key_type *ktype;
-       struct key *key, *dest;
+       struct key *key;
+       key_ref_t dest_ref;
        char type[32], *description, *callout_info;
        long dlen, ret;
 
@@ -187,11 +189,11 @@ asmlinkage long sys_request_key(const char __user *_type,
        }
 
        /* get the destination keyring if specified */
-       dest = NULL;
+       dest_ref = NULL;
        if (destringid) {
-               dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
-               if (IS_ERR(dest)) {
-                       ret = PTR_ERR(dest);
+               dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+               if (IS_ERR(dest_ref)) {
+                       ret = PTR_ERR(dest_ref);
                        goto error3;
                }
        }
@@ -204,7 +206,8 @@ asmlinkage long sys_request_key(const char __user *_type,
        }
 
        /* do the search */
-       key = request_key_and_link(ktype, description, callout_info, dest);
+       key = request_key_and_link(ktype, description, callout_info,
+                                  key_ref_to_ptr(dest_ref));
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error5;
@@ -216,7 +219,7 @@ asmlinkage long sys_request_key(const char __user *_type,
  error5:
        key_type_put(ktype);
  error4:
-       key_put(dest);
+       key_ref_put(dest_ref);
  error3:
        kfree(callout_info);
  error2:
@@ -234,17 +237,17 @@ asmlinkage long sys_request_key(const char __user *_type,
  */
 long keyctl_get_keyring_ID(key_serial_t id, int create)
 {
-       struct key *key;
+       key_ref_t key_ref;
        long ret;
 
-       key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       key_ref = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
                goto error;
        }
 
-       ret = key->serial;
-       key_put(key);
+       ret = key_ref_to_ptr(key_ref)->serial;
+       key_ref_put(key_ref);
  error:
        return ret;
 
@@ -302,7 +305,7 @@ long keyctl_update_key(key_serial_t id,
                       const void __user *_payload,
                       size_t plen)
 {
-       struct key *key;
+       key_ref_t key_ref;
        void *payload;
        long ret;
 
@@ -324,16 +327,16 @@ long keyctl_update_key(key_serial_t id,
        }
 
        /* find the target key (which must be writable) */
-       key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
                goto error2;
        }
 
        /* update the key */
-       ret = key_update(key, payload, plen);
+       ret = key_update(key_ref, payload, plen);
 
-       key_put(key);
+       key_ref_put(key_ref);
  error2:
        kfree(payload);
  error:
@@ -349,19 +352,19 @@ long keyctl_update_key(key_serial_t id,
  */
 long keyctl_revoke_key(key_serial_t id)
 {
-       struct key *key;
+       key_ref_t key_ref;
        long ret;
 
-       key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       key_ref = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
                goto error;
        }
 
-       key_revoke(key);
+       key_revoke(key_ref_to_ptr(key_ref));
        ret = 0;
 
-       key_put(key);
+       key_ref_put(key_ref);
  error:
        return ret;
 
@@ -375,18 +378,18 @@ long keyctl_revoke_key(key_serial_t id)
  */
 long keyctl_keyring_clear(key_serial_t ringid)
 {
-       struct key *keyring;
+       key_ref_t keyring_ref;
        long ret;
 
-       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-       if (IS_ERR(keyring)) {
-               ret = PTR_ERR(keyring);
+       keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+       if (IS_ERR(keyring_ref)) {
+               ret = PTR_ERR(keyring_ref);
                goto error;
        }
 
-       ret = keyring_clear(keyring);
+       ret = keyring_clear(key_ref_to_ptr(keyring_ref));
 
-       key_put(keyring);
+       key_ref_put(keyring_ref);
  error:
        return ret;
 
@@ -401,26 +404,26 @@ long keyctl_keyring_clear(key_serial_t ringid)
  */
 long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
 {
-       struct key *keyring, *key;
+       key_ref_t keyring_ref, key_ref;
        long ret;
 
-       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-       if (IS_ERR(keyring)) {
-               ret = PTR_ERR(keyring);
+       keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+       if (IS_ERR(keyring_ref)) {
+               ret = PTR_ERR(keyring_ref);
                goto error;
        }
 
-       key = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       key_ref = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
                goto error2;
        }
 
-       ret = key_link(keyring, key);
+       ret = key_link(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
 
-       key_put(key);
+       key_ref_put(key_ref);
  error2:
-       key_put(keyring);
+       key_ref_put(keyring_ref);
  error:
        return ret;
 
@@ -435,26 +438,26 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
  */
 long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
 {
-       struct key *keyring, *key;
+       key_ref_t keyring_ref, key_ref;
        long ret;
 
-       keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
-       if (IS_ERR(keyring)) {
-               ret = PTR_ERR(keyring);
+       keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
+       if (IS_ERR(keyring_ref)) {
+               ret = PTR_ERR(keyring_ref);
                goto error;
        }
 
-       key = lookup_user_key(NULL, id, 0, 0, 0);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       key_ref = lookup_user_key(NULL, id, 0, 0, 0);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
                goto error2;
        }
 
-       ret = key_unlink(keyring, key);
+       ret = key_unlink(key_ref_to_ptr(keyring_ref), key_ref_to_ptr(key_ref));
 
-       key_put(key);
+       key_ref_put(key_ref);
  error2:
-       key_put(keyring);
+       key_ref_put(keyring_ref);
  error:
        return ret;
 
@@ -476,24 +479,26 @@ long keyctl_describe_key(key_serial_t keyid,
                         size_t buflen)
 {
        struct key *key, *instkey;
+       key_ref_t key_ref;
        char *tmpbuf;
        long ret;
 
-       key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
-       if (IS_ERR(key)) {
+       key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+       if (IS_ERR(key_ref)) {
                /* viewing a key under construction is permitted if we have the
                 * authorisation token handy */
-               if (PTR_ERR(key) == -EACCES) {
+               if (PTR_ERR(key_ref) == -EACCES) {
                        instkey = key_get_instantiation_authkey(keyid);
                        if (!IS_ERR(instkey)) {
                                key_put(instkey);
-                               key = lookup_user_key(NULL, keyid, 0, 1, 0);
-                               if (!IS_ERR(key))
+                               key_ref = lookup_user_key(NULL, keyid,
+                                                         0, 1, 0);
+                               if (!IS_ERR(key_ref))
                                        goto okay;
                        }
                }
 
-               ret = PTR_ERR(key);
+               ret = PTR_ERR(key_ref);
                goto error;
        }
 
@@ -504,13 +509,16 @@ okay:
        if (!tmpbuf)
                goto error2;
 
+       key = key_ref_to_ptr(key_ref);
+
        ret = snprintf(tmpbuf, PAGE_SIZE - 1,
-                      "%s;%d;%d;%06x;%s",
-                      key->type->name,
-                      key->uid,
-                      key->gid,
-                      key->perm,
-                      key->description ? key->description :""
+                      "%s;%d;%d;%08x;%s",
+                      key_ref_to_ptr(key_ref)->type->name,
+                      key_ref_to_ptr(key_ref)->uid,
+                      key_ref_to_ptr(key_ref)->gid,
+                      key_ref_to_ptr(key_ref)->perm,
+                      key_ref_to_ptr(key_ref)->description ?
+                      key_ref_to_ptr(key_ref)->description : ""
                       );
 
        /* include a NUL char at the end of the data */
@@ -530,7 +538,7 @@ okay:
 
        kfree(tmpbuf);
  error2:
-       key_put(key);
+       key_ref_put(key_ref);
  error:
        return ret;
 
@@ -552,7 +560,7 @@ long keyctl_keyring_search(key_serial_t ringid,
                           key_serial_t destringid)
 {
        struct key_type *ktype;
-       struct key *keyring, *key, *dest;
+       key_ref_t keyring_ref, key_ref, dest_ref;
        char type[32], *description;
        long dlen, ret;
 
@@ -581,18 +589,18 @@ long keyctl_keyring_search(key_serial_t ringid,
                goto error2;
 
        /* get the keyring at which to begin the search */
-       keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
-       if (IS_ERR(keyring)) {
-               ret = PTR_ERR(keyring);
+       keyring_ref = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
+       if (IS_ERR(keyring_ref)) {
+               ret = PTR_ERR(keyring_ref);
                goto error2;
        }
 
        /* get the destination keyring if specified */
-       dest = NULL;
+       dest_ref = NULL;
        if (destringid) {
-               dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
-               if (IS_ERR(dest)) {
-                       ret = PTR_ERR(dest);
+               dest_ref = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
+               if (IS_ERR(dest_ref)) {
+                       ret = PTR_ERR(dest_ref);
                        goto error3;
                }
        }
@@ -605,9 +613,9 @@ long keyctl_keyring_search(key_serial_t ringid,
        }
 
        /* do the search */
-       key = keyring_search(keyring, ktype, description);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       key_ref = keyring_search(keyring_ref, ktype, description);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
 
                /* treat lack or presence of a negative key the same */
                if (ret == -EAGAIN)
@@ -616,26 +624,26 @@ long keyctl_keyring_search(key_serial_t ringid,
        }
 
        /* link the resulting key to the destination keyring if we can */
-       if (dest) {
-               ret = -EACCES;
-               if (!key_permission(key, KEY_LINK))
+       if (dest_ref) {
+               ret = key_permission(key_ref, KEY_LINK);
+               if (ret < 0)
                        goto error6;
 
-               ret = key_link(dest, key);
+               ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref));
                if (ret < 0)
                        goto error6;
        }
 
-       ret = key->serial;
+       ret = key_ref_to_ptr(key_ref)->serial;
 
  error6:
-       key_put(key);
+       key_ref_put(key_ref);
  error5:
        key_type_put(ktype);
  error4:
-       key_put(dest);
+       key_ref_put(dest_ref);
  error3:
-       key_put(keyring);
+       key_ref_put(keyring_ref);
  error2:
        kfree(description);
  error:
@@ -643,16 +651,6 @@ long keyctl_keyring_search(key_serial_t ringid,
 
 } /* end keyctl_keyring_search() */
 
-/*****************************************************************************/
-/*
- * see if the key we're looking at is the target key
- */
-static int keyctl_read_key_same(const struct key *key, const void *target)
-{
-       return key == target;
-
-} /* end keyctl_read_key_same() */
-
 /*****************************************************************************/
 /*
  * read a user key's payload
@@ -665,38 +663,36 @@ static int keyctl_read_key_same(const struct key *key, const void *target)
  */
 long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 {
-       struct key *key, *skey;
+       struct key *key;
+       key_ref_t key_ref;
        long ret;
 
        /* find the key first */
-       key = lookup_user_key(NULL, keyid, 0, 0, 0);
-       if (!IS_ERR(key)) {
-               /* see if we can read it directly */
-               if (key_permission(key, KEY_READ))
-                       goto can_read_key;
-
-               /* we can't; see if it's searchable from this process's
-                * keyrings
-                * - we automatically take account of the fact that it may be
-                *   dangling off an instantiation key
-                */
-               skey = search_process_keyrings(key->type, key,
-                                              keyctl_read_key_same, current);
-               if (!IS_ERR(skey))
-                       goto can_read_key2;
-
-               ret = PTR_ERR(skey);
-               if (ret == -EAGAIN)
-                       ret = -EACCES;
-               goto error2;
+       key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
+       if (IS_ERR(key_ref)) {
+               ret = -ENOKEY;
+               goto error;
        }
 
-       ret = -ENOKEY;
-       goto error;
+       key = key_ref_to_ptr(key_ref);
+
+       /* see if we can read it directly */
+       ret = key_permission(key_ref, KEY_READ);
+       if (ret == 0)
+               goto can_read_key;
+       if (ret != -EACCES)
+               goto error;
+
+       /* we can't; see if it's searchable from this process's keyrings
+        * - we automatically take account of the fact that it may be
+        *   dangling off an instantiation key
+        */
+       if (!is_key_possessed(key_ref)) {
+               ret = -EACCES;
+               goto error2;
+       }
 
        /* the key is probably readable - now try to read it */
- can_read_key2:
-       key_put(skey);
  can_read_key:
        ret = key_validate(key);
        if (ret == 0) {
@@ -727,18 +723,21 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
 long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 {
        struct key *key;
+       key_ref_t key_ref;
        long ret;
 
        ret = 0;
        if (uid == (uid_t) -1 && gid == (gid_t) -1)
                goto error;
 
-       key = lookup_user_key(NULL, id, 1, 1, 0);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
                goto error;
        }
 
+       key = key_ref_to_ptr(key_ref);
+
        /* make the changes with the locks held to prevent chown/chown races */
        ret = -EACCES;
        down_write(&key->sem);
@@ -784,18 +783,21 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
 long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
 {
        struct key *key;
+       key_ref_t key_ref;
        long ret;
 
        ret = -EINVAL;
-       if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
+       if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
                goto error;
 
-       key = lookup_user_key(NULL, id, 1, 1, 0);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
                goto error;
        }
 
+       key = key_ref_to_ptr(key_ref);
+
        /* make the changes with the locks held to prevent chown/chmod races */
        ret = -EACCES;
        down_write(&key->sem);
@@ -824,7 +826,8 @@ long keyctl_instantiate_key(key_serial_t id,
                            key_serial_t ringid)
 {
        struct request_key_auth *rka;
-       struct key *instkey, *keyring;
+       struct key *instkey;
+       key_ref_t keyring_ref;
        void *payload;
        long ret;
 
@@ -832,6 +835,17 @@ long keyctl_instantiate_key(key_serial_t id,
        if (plen > 32767)
                goto error;
 
+       /* the appropriate instantiation authorisation key must have been
+        * assumed before calling this */
+       ret = -EPERM;
+       instkey = current->request_key_auth;
+       if (!instkey)
+               goto error;
+
+       rka = instkey->payload.data;
+       if (rka->target_key->serial != id)
+               goto error;
+
        /* pull the payload in if one was supplied */
        payload = NULL;
 
@@ -846,37 +860,34 @@ long keyctl_instantiate_key(key_serial_t id,
                        goto error2;
        }
 
-       /* find the instantiation authorisation key */
-       instkey = key_get_instantiation_authkey(id);
-       if (IS_ERR(instkey)) {
-               ret = PTR_ERR(instkey);
-               goto error2;
-       }
-
-       rka = instkey->payload.data;
-
        /* find the destination keyring amongst those belonging to the
         * requesting task */
-       keyring = NULL;
+       keyring_ref = NULL;
        if (ringid) {
-               keyring = lookup_user_key(rka->context, ringid, 1, 0,
-                                         KEY_WRITE);
-               if (IS_ERR(keyring)) {
-                       ret = PTR_ERR(keyring);
-                       goto error3;
+               keyring_ref = lookup_user_key(rka->context, ringid, 1, 0,
+                                             KEY_WRITE);
+               if (IS_ERR(keyring_ref)) {
+                       ret = PTR_ERR(keyring_ref);
+                       goto error2;
                }
        }
 
        /* instantiate the key and link it into a keyring */
        ret = key_instantiate_and_link(rka->target_key, payload, plen,
-                                      keyring, instkey);
+                                      key_ref_to_ptr(keyring_ref), instkey);
 
-       key_put(keyring);
- error3:
-       key_put(instkey);
- error2:
+       key_ref_put(keyring_ref);
+
+       /* discard the assumed authority if it's just been disabled by
+        * instantiation of the key */
+       if (ret == 0) {
+               key_put(current->request_key_auth);
+               current->request_key_auth = NULL;
+       }
+
+error2:
        kfree(payload);
- error:
+error:
        return ret;
 
 } /* end keyctl_instantiate_key() */
@@ -889,36 +900,46 @@ long keyctl_instantiate_key(key_serial_t id,
 long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 {
        struct request_key_auth *rka;
-       struct key *instkey, *keyring;
+       struct key *instkey;
+       key_ref_t keyring_ref;
        long ret;
 
-       /* find the instantiation authorisation key */
-       instkey = key_get_instantiation_authkey(id);
-       if (IS_ERR(instkey)) {
-               ret = PTR_ERR(instkey);
+       /* the appropriate instantiation authorisation key must have been
+        * assumed before calling this */
+       ret = -EPERM;
+       instkey = current->request_key_auth;
+       if (!instkey)
                goto error;
-       }
 
        rka = instkey->payload.data;
+       if (rka->target_key->serial != id)
+               goto error;
 
        /* find the destination keyring if present (which must also be
         * writable) */
-       keyring = NULL;
+       keyring_ref = NULL;
        if (ringid) {
-               keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
-               if (IS_ERR(keyring)) {
-                       ret = PTR_ERR(keyring);
-                       goto error2;
+               keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
+               if (IS_ERR(keyring_ref)) {
+                       ret = PTR_ERR(keyring_ref);
+                       goto error;
                }
        }
 
        /* instantiate the key and link it into a keyring */
-       ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
+       ret = key_negate_and_link(rka->target_key, timeout,
+                                 key_ref_to_ptr(keyring_ref), instkey);
 
-       key_put(keyring);
- error2:
-       key_put(instkey);
- error:
+       key_ref_put(keyring_ref);
+
+       /* discard the assumed authority if it's just been disabled by
+        * instantiation of the key */
+       if (ret == 0) {
+               key_put(current->request_key_auth);
+               current->request_key_auth = NULL;
+       }
+
+error:
        return ret;
 
 } /* end keyctl_negate_key() */
@@ -961,6 +982,88 @@ long keyctl_set_reqkey_keyring(int reqkey_defl)
 
 } /* end keyctl_set_reqkey_keyring() */
 
+/*****************************************************************************/
+/*
+ * set or clear the timeout for a key
+ */
+long keyctl_set_timeout(key_serial_t id, unsigned timeout)
+{
+       struct timespec now;
+       struct key *key;
+       key_ref_t key_ref;
+       time_t expiry;
+       long ret;
+
+       key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR);
+       if (IS_ERR(key_ref)) {
+               ret = PTR_ERR(key_ref);
+               goto error;
+       }
+
+       key = key_ref_to_ptr(key_ref);
+
+       /* make the changes with the locks held to prevent races */
+       down_write(&key->sem);
+
+       expiry = 0;
+       if (timeout > 0) {
+               now = current_kernel_time();
+               expiry = now.tv_sec + timeout;
+       }
+
+       key->expiry = expiry;
+
+       up_write(&key->sem);
+       key_put(key);
+
+       ret = 0;
+error:
+       return ret;
+
+} /* end keyctl_set_timeout() */
+
+/*****************************************************************************/
+/*
+ * assume the authority to instantiate the specified key
+ */
+long keyctl_assume_authority(key_serial_t id)
+{
+       struct key *authkey;
+       long ret;
+
+       /* special key IDs aren't permitted */
+       ret = -EINVAL;
+       if (id < 0)
+               goto error;
+
+       /* we divest ourselves of authority if given an ID of 0 */
+       if (id == 0) {
+               key_put(current->request_key_auth);
+               current->request_key_auth = NULL;
+               ret = 0;
+               goto error;
+       }
+
+       /* attempt to assume the authority temporarily granted to us whilst we
+        * instantiate the specified key
+        * - the authorisation key must be in the current task's keyrings
+        *   somewhere
+        */
+       authkey = key_get_instantiation_authkey(id);
+       if (IS_ERR(authkey)) {
+               ret = PTR_ERR(authkey);
+               goto error;
+       }
+
+       key_put(current->request_key_auth);
+       current->request_key_auth = authkey;
+       ret = authkey->serial;
+
+error:
+       return ret;
+
+} /* end keyctl_assume_authority() */
+
 /*****************************************************************************/
 /*
  * the key control system call
@@ -1034,6 +1137,13 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
        case KEYCTL_SET_REQKEY_KEYRING:
                return keyctl_set_reqkey_keyring(arg2);
 
+       case KEYCTL_SET_TIMEOUT:
+               return keyctl_set_timeout((key_serial_t) arg2,
+                                         (unsigned) arg3);
+
+       case KEYCTL_ASSUME_AUTHORITY:
+               return keyctl_assume_authority((key_serial_t) arg2);
+
        default:
                return -EOPNOTSUPP;
        }