this case too.
 
 
+ (*) Set the default request-key destination keyring.
+
+       long keyctl(KEYCTL_SET_REQKEY_KEYRING, int reqkey_defl);
+
+     This sets the default keyring to which implicitly requested keys will be
+     attached for this thread. reqkey_defl should be one of these constants:
+
+       CONSTANT                                VALUE   NEW DEFAULT KEYRING
+       ======================================  ======  =======================
+       KEY_REQKEY_DEFL_NO_CHANGE               -1      No change
+       KEY_REQKEY_DEFL_DEFAULT                 0       Default[1]
+       KEY_REQKEY_DEFL_THREAD_KEYRING          1       Thread keyring
+       KEY_REQKEY_DEFL_PROCESS_KEYRING         2       Process keyring
+       KEY_REQKEY_DEFL_SESSION_KEYRING         3       Session keyring
+       KEY_REQKEY_DEFL_USER_KEYRING            4       User keyring
+       KEY_REQKEY_DEFL_USER_SESSION_KEYRING    5       User session keyring
+       KEY_REQKEY_DEFL_GROUP_KEYRING           6       Group keyring
+
+     The old default will be returned if successful and error EINVAL will be
+     returned if reqkey_defl is not one of the above values.
+
+     The default keyring can be overridden by the keyring indicated to the
+     request_key() system call.
+
+     Note that this setting is inherited across fork/exec.
+
+     [1] The default default is: the thread keyring if there is one, otherwise
+     the process keyring if there is one, otherwise the session keyring if
+     there is one, otherwise the user default session keyring.
+
+
 ===============
 KERNEL SERVICES
 ===============
     Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
     returned.
 
+    If successful, the key will have been attached to the default keyring for
+    implicitly obtained request-key keys, as set by KEYCTL_SET_REQKEY_KEYRING.
+
 
 (*) When it is no longer required, the key should be released using:
 
 
-/* key-ui.h: key userspace interface stuff for use by keyfs
+/* key-ui.h: key userspace interface stuff
  *
  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
        return kperm != 0;
 }
 
+static inline int key_task_groups_search(struct task_struct *tsk, gid_t gid)
+{
+       int ret;
+
+       task_lock(tsk);
+       ret = groups_search(tsk->group_info, gid);
+       task_unlock(tsk);
+       return ret;
+}
+
+static inline int key_task_permission(const struct key *key,
+                                     struct task_struct *context,
+                                     key_perm_t perm)
+{
+       key_perm_t kperm;
+
+       if (key->uid == context->fsuid) {
+               kperm = key->perm >> 16;
+       }
+       else if (key->gid != -1 &&
+                key->perm & KEY_GRP_ALL && (
+                        key->gid == context->fsgid ||
+                        key_task_groups_search(context, key->gid)
+                        )
+                ) {
+               kperm = key->perm >> 8;
+       }
+       else {
+               kperm = key->perm;
+       }
+
+       kperm = kperm & perm & KEY_ALL;
+
+       return kperm == perm;
+
+}
 
-extern struct key *lookup_user_key(key_serial_t id, int create, int part,
+extern struct key *lookup_user_key(struct task_struct *context,
+                                  key_serial_t id, int create, int partial,
                                   key_perm_t perm);
 
 extern long join_session_keyring(const char *name);
 
 extern int key_instantiate_and_link(struct key *key,
                                    const void *data,
                                    size_t datalen,
-                                   struct key *keyring);
+                                   struct key *keyring,
+                                   struct key *instkey);
 extern int key_negate_and_link(struct key *key,
                               unsigned timeout,
-                              struct key *keyring);
+                              struct key *keyring,
+                              struct key *instkey);
 extern void key_revoke(struct key *key);
 extern void key_put(struct key *key);
 
                                  struct key_type *type,
                                  const char *description);
 
-extern struct key *search_process_keyrings(struct key_type *type,
-                                          const char *description);
-
 extern int keyring_add_key(struct key *keyring,
                           struct key *key);
 
 
 #define KEY_SPEC_USER_SESSION_KEYRING  -5      /* - key ID for UID-session keyring */
 #define KEY_SPEC_GROUP_KEYRING         -6      /* - key ID for GID-specific keyring */
 
+/* request-key default keyrings */
+#define KEY_REQKEY_DEFL_NO_CHANGE              -1
+#define KEY_REQKEY_DEFL_DEFAULT                        0
+#define KEY_REQKEY_DEFL_THREAD_KEYRING         1
+#define KEY_REQKEY_DEFL_PROCESS_KEYRING                2
+#define KEY_REQKEY_DEFL_SESSION_KEYRING                3
+#define KEY_REQKEY_DEFL_USER_KEYRING           4
+#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING   5
+#define KEY_REQKEY_DEFL_GROUP_KEYRING          6
+
 /* keyctl commands */
 #define KEYCTL_GET_KEYRING_ID          0       /* ask for a keyring's ID */
 #define KEYCTL_JOIN_SESSION_KEYRING    1       /* join or start named session keyring */
 #define KEYCTL_READ                    11      /* read a key or keyring's contents */
 #define KEYCTL_INSTANTIATE             12      /* instantiate a partially constructed key */
 #define KEYCTL_NEGATE                  13      /* negate a partially constructed key */
+#define KEYCTL_SET_REQKEY_KEYRING      14      /* set default request-key keyring */
 
 #endif /*  _LINUX_KEYCTL_H */
 
                groups_free(group_info); \
 } while (0)
 
-struct group_info *groups_alloc(int gidsetsize);
-void groups_free(struct group_info *group_info);
-int set_current_groups(struct group_info *group_info);
+extern struct group_info *groups_alloc(int gidsetsize);
+extern void groups_free(struct group_info *group_info);
+extern int set_current_groups(struct group_info *group_info);
+extern int groups_search(struct group_info *group_info, gid_t grp);
 /* access the groups "array" with this macro */
 #define GROUP_AT(gi, i) \
     ((gi)->blocks[(i)/NGROUPS_PER_BLOCK][(i)%NGROUPS_PER_BLOCK])
        struct user_struct *user;
 #ifdef CONFIG_KEYS
        struct key *thread_keyring;     /* keyring private to this thread */
+       unsigned char jit_keyring;      /* default keyring to attach requested keys to */
 #endif
        int oomkilladj; /* OOM kill score adjustment (bit shift). */
        char comm[TASK_COMM_LEN]; /* executable name excluding path
 
 }
 
 /* a simple bsearch */
-static int groups_search(struct group_info *group_info, gid_t grp)
+int groups_search(struct group_info *group_info, gid_t grp)
 {
        int left, right;
 
 
        keyring.o \
        keyctl.o \
        process_keys.o \
-       user_defined.o \
-       request_key.o
+       request_key.o \
+       request_key_auth.o \
+       user_defined.o
 
 obj-$(CONFIG_KEYS_COMPAT) += compat.o
 obj-$(CONFIG_PROC_FS) += proc.o
 
 /* compat.c: 32-bit compatibility syscall for 64-bit systems
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
  * - if you can, you should call sys_keyctl directly
  */
 asmlinkage long compat_sys_keyctl(u32 option,
-                             u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+                                 u32 arg2, u32 arg3, u32 arg4, u32 arg5)
 {
        switch (option) {
        case KEYCTL_GET_KEYRING_ID:
        case KEYCTL_NEGATE:
                return keyctl_negate_key(arg2, arg3, arg4);
 
+       case KEYCTL_SET_REQKEY_KEYRING:
+               return keyctl_set_reqkey_keyring(arg2);
+
        default:
                return -EOPNOTSUPP;
        }
 
 /* internal.h: authentication token and access key management internal defs
  *
- * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
 #include <linux/key.h>
 #include <linux/key-ui.h>
 
+#if 0
+#define kenter(FMT, a...)      printk("==> %s("FMT")\n",__FUNCTION__ , ## a)
+#define kleave(FMT, a...)      printk("<== %s()"FMT"\n",__FUNCTION__ , ## a)
+#define kdebug(FMT, a...)      printk(FMT"\n" , ## a)
+#else
+#define kenter(FMT, a...)      do {} while(0)
+#define kleave(FMT, a...)      do {} while(0)
+#define kdebug(FMT, a...)      do {} while(0)
+#endif
+
 extern struct key_type key_type_dead;
 extern struct key_type key_type_user;
 
                                        const char *description,
                                        key_perm_t perm);
 
+extern struct key *keyring_search_instkey(struct key *keyring,
+                                         key_serial_t target_id);
+
 typedef int (*key_match_func_t)(const struct key *, const void *);
 
 extern struct key *keyring_search_aux(struct key *keyring,
+                                     struct task_struct *tsk,
                                      struct key_type *type,
                                      const void *description,
                                      key_match_func_t match);
 
-extern struct key *search_process_keyrings_aux(struct key_type *type,
-                                              const void *description,
-                                              key_match_func_t match);
+extern struct key *search_process_keyrings(struct key_type *type,
+                                          const void *description,
+                                          key_match_func_t match,
+                                          struct task_struct *tsk);
 
 extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
 
 extern int install_thread_keyring(struct task_struct *tsk);
+extern int install_process_keyring(struct task_struct *tsk);
+
+extern struct key *request_key_and_link(struct key_type *type,
+                                       const char *description,
+                                       const char *callout_info,
+                                       struct key *dest_keyring);
+
+/*
+ * request_key authorisation
+ */
+struct request_key_auth {
+       struct key              *target_key;
+       struct task_struct      *context;
+       pid_t                   pid;
+};
+
+extern struct key_type key_type_request_key_auth;
+extern struct key *request_key_auth_new(struct key *target,
+                                       struct key **_rkakey);
+
+extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
 
 /*
  * keyctl functions
 extern long keyctl_instantiate_key(key_serial_t, const void __user *,
                                   size_t, key_serial_t);
 extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t);
+extern long keyctl_set_reqkey_keyring(int);
 
 
 /*
 
 /* key.c: basic authentication token and access key management
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
 static int __key_instantiate_and_link(struct key *key,
                                      const void *data,
                                      size_t datalen,
-                                     struct key *keyring)
+                                     struct key *keyring,
+                                     struct key *instkey)
 {
        int ret, awaken;
 
                        /* and link it into the destination keyring */
                        if (keyring)
                                ret = __key_link(keyring, key);
+
+                       /* disable the authorisation key */
+                       if (instkey)
+                               key_revoke(instkey);
                }
        }
 
 int key_instantiate_and_link(struct key *key,
                             const void *data,
                             size_t datalen,
-                            struct key *keyring)
+                            struct key *keyring,
+                            struct key *instkey)
 {
        int ret;
 
        if (keyring)
                down_write(&keyring->sem);
 
-       ret = __key_instantiate_and_link(key, data, datalen, keyring);
+       ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey);
 
        if (keyring)
                up_write(&keyring->sem);
 
        return ret;
+
 } /* end key_instantiate_and_link() */
 
 EXPORT_SYMBOL(key_instantiate_and_link);
  */
 int key_negate_and_link(struct key *key,
                        unsigned timeout,
-                       struct key *keyring)
+                       struct key *keyring,
+                       struct key *instkey)
 {
        struct timespec now;
        int ret, awaken;
                /* and link it into the destination keyring */
                if (keyring)
                        ret = __key_link(keyring, key);
+
+               /* disable the authorisation key */
+               if (instkey)
+                       key_revoke(instkey);
        }
 
        up_write(&key_construction_sem);
        }
 
        /* instantiate it and link it into the target keyring */
-       ret = __key_instantiate_and_link(key, payload, plen, keyring);
+       ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
        if (ret < 0) {
                key_put(key);
                key = ERR_PTR(ret);
 
 /* keyctl.c: userspace keyctl operations
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
                goto error;
        type[31] = '\0';
 
+       if (!type[0])
+               goto error;
+
+       ret = -EPERM;
+       if (type[0] == '.')
+               goto error;
+
        ret = -EFAULT;
        dlen = strnlen_user(_description, PAGE_SIZE - 1);
        if (dlen <= 0)
        }
 
        /* find the target keyring (which must be writable) */
-       keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error3;
        /* get the destination keyring if specified */
        dest = NULL;
        if (destringid) {
-               dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+               dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
                if (IS_ERR(dest)) {
                        ret = PTR_ERR(dest);
                        goto error3;
        }
 
        /* do the search */
-       key = request_key(ktype, description, callout_info);
+       key = request_key_and_link(ktype, description, callout_info, dest);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error5;
        }
 
-       /* link the resulting key to the destination keyring */
-       if (dest) {
-               ret = key_link(dest, key);
-               if (ret < 0)
-                       goto error6;
-       }
-
        ret = key->serial;
 
- error6:
-       key_put(key);
+       key_put(key);
  error5:
        key_type_put(ktype);
  error4:
        struct key *key;
        long ret;
 
-       key = lookup_user_key(id, create, 0, KEY_SEARCH);
+       key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error;
        }
 
        /* find the target key (which must be writable) */
-       key = lookup_user_key(id, 0, 0, KEY_WRITE);
+       key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error2;
        struct key *key;
        long ret;
 
-       key = lookup_user_key(id, 0, 0, KEY_WRITE);
+       key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error;
        struct key *keyring;
        long ret;
 
-       keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
        struct key *keyring, *key;
        long ret;
 
-       keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+       keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
        }
 
-       key = lookup_user_key(id, 1, 0, KEY_LINK);
+       key = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error2;
        struct key *keyring, *key;
        long ret;
 
-       keyring = lookup_user_key(ringid, 0, 0, KEY_WRITE);
+       keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error;
        }
 
-       key = lookup_user_key(id, 0, 0, 0);
+       key = lookup_user_key(NULL, id, 0, 0, 0);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error2;
                         char __user *buffer,
                         size_t buflen)
 {
-       struct key *key;
+       struct key *key, *instkey;
        char *tmpbuf;
        long ret;
 
-       key = lookup_user_key(keyid, 0, 1, KEY_VIEW);
+       key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
        if (IS_ERR(key)) {
+               /* viewing a key under construction is permitted if we have the
+                * authorisation token handy */
+               if (PTR_ERR(key) == -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))
+                                       goto okay;
+                       }
+               }
+
                ret = PTR_ERR(key);
                goto error;
        }
 
+okay:
        /* calculate how much description we're going to return */
        ret = -ENOMEM;
        tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
                goto error2;
 
        /* get the keyring at which to begin the search */
-       keyring = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
+       keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
        if (IS_ERR(keyring)) {
                ret = PTR_ERR(keyring);
                goto error2;
        /* get the destination keyring if specified */
        dest = NULL;
        if (destringid) {
-               dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+               dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
                if (IS_ERR(dest)) {
                        ret = PTR_ERR(dest);
                        goto error3;
        long ret;
 
        /* find the key first */
-       key = lookup_user_key(keyid, 0, 0, 0);
+       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;
 
-               /* can't; see if it's searchable from this process's
-                * keyrings */
-               ret = -ENOKEY;
-               if (key_permission(key, KEY_SEARCH)) {
-                       /* okay - we do have search permission on the key
-                        * itself, but do we have the key? */
-                       skey = search_process_keyrings_aux(key->type, key,
-                                                          keyctl_read_key_same);
-                       if (!IS_ERR(skey))
-                               goto can_read_key2;
-               }
-
+               /* 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);
                goto error2;
        }
 
        if (uid == (uid_t) -1 && gid == (gid_t) -1)
                goto error;
 
-       key = lookup_user_key(id, 1, 1, 0);
+       key = lookup_user_key(NULL, id, 1, 1, 0);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error;
        if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
                goto error;
 
-       key = lookup_user_key(id, 1, 1, 0);
+       key = lookup_user_key(NULL, id, 1, 1, 0);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
                goto error;
                            size_t plen,
                            key_serial_t ringid)
 {
-       struct key *key, *keyring;
+       struct request_key_auth *rka;
+       struct key *instkey, *keyring;
        void *payload;
        long ret;
 
                        goto error2;
        }
 
-       /* find the target key (which must be writable) */
-       key = lookup_user_key(id, 0, 1, KEY_WRITE);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       /* find the instantiation authorisation key */
+       instkey = key_get_instantiation_authkey(id);
+       if (IS_ERR(instkey)) {
+               ret = PTR_ERR(instkey);
                goto error2;
        }
 
-       /* find the destination keyring if present (which must also be
-        * writable) */
+       rka = instkey->payload.data;
+
+       /* find the destination keyring amongst those belonging to the
+        * requesting task */
        keyring = NULL;
        if (ringid) {
-               keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+               keyring = lookup_user_key(rka->context, ringid, 1, 0,
+                                         KEY_WRITE);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error3;
        }
 
        /* instantiate the key and link it into a keyring */
-       ret = key_instantiate_and_link(key, payload, plen, keyring);
+       ret = key_instantiate_and_link(rka->target_key, payload, plen,
+                                      keyring, instkey);
 
        key_put(keyring);
  error3:
-       key_put(key);
+       key_put(instkey);
  error2:
        kfree(payload);
  error:
  */
 long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
 {
-       struct key *key, *keyring;
+       struct request_key_auth *rka;
+       struct key *instkey, *keyring;
        long ret;
 
-       /* find the target key (which must be writable) */
-       key = lookup_user_key(id, 0, 1, KEY_WRITE);
-       if (IS_ERR(key)) {
-               ret = PTR_ERR(key);
+       /* find the instantiation authorisation key */
+       instkey = key_get_instantiation_authkey(id);
+       if (IS_ERR(instkey)) {
+               ret = PTR_ERR(instkey);
                goto error;
        }
 
+       rka = instkey->payload.data;
+
        /* find the destination keyring if present (which must also be
         * writable) */
        keyring = NULL;
        if (ringid) {
-               keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+               keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
                if (IS_ERR(keyring)) {
                        ret = PTR_ERR(keyring);
                        goto error2;
        }
 
        /* instantiate the key and link it into a keyring */
-       ret = key_negate_and_link(key, timeout, keyring);
+       ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
 
        key_put(keyring);
  error2:
-       key_put(key);
+       key_put(instkey);
  error:
        return ret;
 
 } /* end keyctl_negate_key() */
 
+/*****************************************************************************/
+/*
+ * set the default keyring in which request_key() will cache keys
+ * - return the old setting
+ */
+long keyctl_set_reqkey_keyring(int reqkey_defl)
+{
+       int ret;
+
+       switch (reqkey_defl) {
+       case KEY_REQKEY_DEFL_THREAD_KEYRING:
+               ret = install_thread_keyring(current);
+               if (ret < 0)
+                       return ret;
+               goto set;
+
+       case KEY_REQKEY_DEFL_PROCESS_KEYRING:
+               ret = install_process_keyring(current);
+               if (ret < 0)
+                       return ret;
+
+       case KEY_REQKEY_DEFL_DEFAULT:
+       case KEY_REQKEY_DEFL_SESSION_KEYRING:
+       case KEY_REQKEY_DEFL_USER_KEYRING:
+       case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
+       set:
+               current->jit_keyring = reqkey_defl;
+
+       case KEY_REQKEY_DEFL_NO_CHANGE:
+               return current->jit_keyring;
+
+       case KEY_REQKEY_DEFL_GROUP_KEYRING:
+       default:
+               return -EINVAL;
+       }
+
+} /* end keyctl_set_reqkey_keyring() */
+
 /*****************************************************************************/
 /*
  * the key control system call
                                         (unsigned) arg3,
                                         (key_serial_t) arg4);
 
+       case KEYCTL_SET_REQKEY_KEYRING:
+               return keyctl_set_reqkey_keyring(arg2);
+
        default:
                return -EOPNOTSUPP;
        }
 
 /* keyring.c: keyring handling
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
                            uid, gid, KEY_USR_ALL, not_in_quota);
 
        if (!IS_ERR(keyring)) {
-               ret = key_instantiate_and_link(keyring, NULL, 0, dest);
+               ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
                if (ret < 0) {
                        key_put(keyring);
                        keyring = ERR_PTR(ret);
  * - we only find keys on which we have search permission
  * - we use the supplied match function to see if the description (or other
  *   feature of interest) matches
- * - we readlock the keyrings as we search down the tree
+ * - we rely on RCU to prevent the keyring lists from disappearing on us
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we only found negative matching keys
  */
 struct key *keyring_search_aux(struct key *keyring,
+                              struct task_struct *context,
                               struct key_type *type,
                               const void *description,
                               key_match_func_t match)
 
        /* top keyring must have search permission to begin the search */
        key = ERR_PTR(-EACCES);
-       if (!key_permission(keyring, KEY_SEARCH))
+       if (!key_task_permission(keyring, context, KEY_SEARCH))
                goto error;
 
        key = ERR_PTR(-ENOTDIR);
                        continue;
 
                /* key must have search permissions */
-               if (!key_permission(key, KEY_SEARCH))
+               if (!key_task_permission(key, context, KEY_SEARCH))
                        continue;
 
                /* we set a different error code if we find a negative key */
                if (sp >= KEYRING_SEARCH_MAX_DEPTH)
                        continue;
 
-               if (!key_permission(key, KEY_SEARCH))
+               if (!key_task_permission(key, context, KEY_SEARCH))
                        continue;
 
                /* stack the current position */
                           struct key_type *type,
                           const char *description)
 {
-       return keyring_search_aux(keyring, type, description, type->match);
+       if (!type->match)
+               return ERR_PTR(-ENOKEY);
+
+       return keyring_search_aux(keyring, current,
+                                 type, description, type->match);
 
 } /* end keyring_search() */
 
                        key = klist->keys[loop];
 
                        if (key->type == ktype &&
-                           key->type->match(key, description) &&
+                           (!key->type->match ||
+                            key->type->match(key, description)) &&
                            key_permission(key, perm) &&
                            !test_bit(KEY_FLAG_REVOKED, &key->flags)
                            )
 
 } /* end __keyring_search_one() */
 
+/*****************************************************************************/
+/*
+ * search for an instantiation authorisation key matching a target key
+ * - the RCU read lock must be held by the caller
+ * - a target_id of zero specifies any valid token
+ */
+struct key *keyring_search_instkey(struct key *keyring,
+                                  key_serial_t target_id)
+{
+       struct request_key_auth *rka;
+       struct keyring_list *klist;
+       struct key *instkey;
+       int loop;
+
+       klist = rcu_dereference(keyring->payload.subscriptions);
+       if (klist) {
+               for (loop = 0; loop < klist->nkeys; loop++) {
+                       instkey = klist->keys[loop];
+
+                       if (instkey->type != &key_type_request_key_auth)
+                               continue;
+
+                       rka = instkey->payload.data;
+                       if (target_id && rka->target_key->serial != target_id)
+                               continue;
+
+                       /* the auth key is revoked during instantiation */
+                       if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags))
+                               goto found;
+
+                       instkey = ERR_PTR(-EKEYREVOKED);
+                       goto error;
+               }
+       }
+
+       instkey = ERR_PTR(-EACCES);
+       goto error;
+
+found:
+       atomic_inc(&instkey->usage);
+error:
+       return instkey;
+
+} /* end keyring_search_instkey() */
+
 /*****************************************************************************/
 /*
  * find a keyring with the specified name
 
 /*
  * make sure a process keyring is installed
  */
-static int install_process_keyring(struct task_struct *tsk)
+int install_process_keyring(struct task_struct *tsk)
 {
        unsigned long flags;
        struct key *keyring;
  * - we return -EAGAIN if we didn't find any matching key
  * - we return -ENOKEY if we found only negative matching keys
  */
-struct key *search_process_keyrings_aux(struct key_type *type,
-                                       const void *description,
-                                       key_match_func_t match)
+struct key *search_process_keyrings(struct key_type *type,
+                                   const void *description,
+                                   key_match_func_t match,
+                                   struct task_struct *context)
 {
-       struct task_struct *tsk = current;
-       struct key *key, *ret, *err;
+       struct request_key_auth *rka;
+       struct key *key, *ret, *err, *instkey;
 
        /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
         * searchable, but we failed to find a key or we found a negative key;
        err = ERR_PTR(-EAGAIN);
 
        /* search the thread keyring first */
-       if (tsk->thread_keyring) {
-               key = keyring_search_aux(tsk->thread_keyring, type,
-                                        description, match);
+       if (context->thread_keyring) {
+               key = keyring_search_aux(context->thread_keyring,
+                                        context, type, description, match);
                if (!IS_ERR(key))
                        goto found;
 
        }
 
        /* search the process keyring second */
-       if (tsk->signal->process_keyring) {
-               key = keyring_search_aux(tsk->signal->process_keyring,
-                                        type, description, match);
+       if (context->signal->process_keyring) {
+               key = keyring_search_aux(context->signal->process_keyring,
+                                        context, type, description, match);
                if (!IS_ERR(key))
                        goto found;
 
                }
        }
 
-       /* search the session keyring last */
-       if (tsk->signal->session_keyring) {
+       /* search the session keyring */
+       if (context->signal->session_keyring) {
                rcu_read_lock();
                key = keyring_search_aux(
-                       rcu_dereference(tsk->signal->session_keyring),
-                       type, description, match);
+                       rcu_dereference(context->signal->session_keyring),
+                       context, type, description, match);
                rcu_read_unlock();
+
+               if (!IS_ERR(key))
+                       goto found;
+
+               switch (PTR_ERR(key)) {
+               case -EAGAIN: /* no key */
+                       if (ret)
+                               break;
+               case -ENOKEY: /* negative key */
+                       ret = key;
+                       break;
+               default:
+                       err = key;
+                       break;
+               }
+
+               /* if this process has a session keyring and that has an
+                * instantiation authorisation key in the bottom level, then we
+                * also search the keyrings of the process mentioned there */
+               if (context != current)
+                       goto no_key;
+
+               rcu_read_lock();
+               instkey = __keyring_search_one(
+                       rcu_dereference(context->signal->session_keyring),
+                       &key_type_request_key_auth, NULL, 0);
+               rcu_read_unlock();
+
+               if (IS_ERR(instkey))
+                       goto no_key;
+
+               rka = instkey->payload.data;
+
+               key = search_process_keyrings(type, description, match,
+                                             rka->context);
+               key_put(instkey);
+
+               if (!IS_ERR(key))
+                       goto found;
+
+               switch (PTR_ERR(key)) {
+               case -EAGAIN: /* no key */
+                       if (ret)
+                               break;
+               case -ENOKEY: /* negative key */
+                       ret = key;
+                       break;
+               default:
+                       err = key;
+                       break;
+               }
        }
+       /* or search the user-session keyring */
        else {
-               key = keyring_search_aux(tsk->user->session_keyring,
-                                        type, description, match);
-       }
-
-       if (!IS_ERR(key))
-               goto found;
+               key = keyring_search_aux(context->user->session_keyring,
+                                        context, type, description, match);
+               if (!IS_ERR(key))
+                       goto found;
 
-       switch (PTR_ERR(key)) {
-       case -EAGAIN: /* no key */
-               if (ret)
+               switch (PTR_ERR(key)) {
+               case -EAGAIN: /* no key */
+                       if (ret)
+                               break;
+               case -ENOKEY: /* negative key */
+                       ret = key;
                        break;
-       case -ENOKEY: /* negative key */
-               ret = key;
-               break;
-       default:
-               err = key;
-               break;
+               default:
+                       err = key;
+                       break;
+               }
        }
 
+
+no_key:
        /* no key - decide on the error we're going to go for */
        key = ret ? ret : err;
 
- found:
+found:
        return key;
 
-} /* end search_process_keyrings_aux() */
-
-/*****************************************************************************/
-/*
- * search the process keyrings for the first matching key
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we found only negative matching keys
- */
-struct key *search_process_keyrings(struct key_type *type,
-                                   const char *description)
-{
-       return search_process_keyrings_aux(type, description, type->match);
-
 } /* end search_process_keyrings() */
 
 /*****************************************************************************/
  * - don't create special keyrings unless so requested
  * - partially constructed keys aren't found unless requested
  */
-struct key *lookup_user_key(key_serial_t id, int create, int partial,
-                           key_perm_t perm)
+struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
+                           int create, int partial, key_perm_t perm)
 {
-       struct task_struct *tsk = current;
-       unsigned long flags;
        struct key *key;
        int ret;
 
+       if (!context)
+               context = current;
+
        key = ERR_PTR(-ENOKEY);
 
        switch (id) {
        case KEY_SPEC_THREAD_KEYRING:
-               if (!tsk->thread_keyring) {
+               if (!context->thread_keyring) {
                        if (!create)
                                goto error;
 
-                       ret = install_thread_keyring(tsk);
+                       ret = install_thread_keyring(context);
                        if (ret < 0) {
                                key = ERR_PTR(ret);
                                goto error;
                        }
                }
 
-               key = tsk->thread_keyring;
+               key = context->thread_keyring;
                atomic_inc(&key->usage);
                break;
 
        case KEY_SPEC_PROCESS_KEYRING:
-               if (!tsk->signal->process_keyring) {
+               if (!context->signal->process_keyring) {
                        if (!create)
                                goto error;
 
-                       ret = install_process_keyring(tsk);
+                       ret = install_process_keyring(context);
                        if (ret < 0) {
                                key = ERR_PTR(ret);
                                goto error;
                        }
                }
 
-               key = tsk->signal->process_keyring;
+               key = context->signal->process_keyring;
                atomic_inc(&key->usage);
                break;
 
        case KEY_SPEC_SESSION_KEYRING:
-               if (!tsk->signal->session_keyring) {
+               if (!context->signal->session_keyring) {
                        /* always install a session keyring upon access if one
                         * doesn't exist yet */
                        ret = install_session_keyring(
-                              tsk, tsk->user->session_keyring);
+                              context, context->user->session_keyring);
                        if (ret < 0)
                                goto error;
                }
 
-               spin_lock_irqsave(&tsk->sighand->siglock, flags);
-               key = tsk->signal->session_keyring;
+               rcu_read_lock();
+               key = rcu_dereference(context->signal->session_keyring);
                atomic_inc(&key->usage);
-               spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+               rcu_read_unlock();
                break;
 
        case KEY_SPEC_USER_KEYRING:
-               key = tsk->user->uid_keyring;
+               key = context->user->uid_keyring;
                atomic_inc(&key->usage);
                break;
 
        case KEY_SPEC_USER_SESSION_KEYRING:
-               key = tsk->user->session_keyring;
+               key = context->user->session_keyring;
                atomic_inc(&key->usage);
                break;
 
                break;
        }
 
-       /* check the status and permissions */
+       /* check the status */
        if (perm) {
                ret = key_validate(key);
                if (ret < 0)
        if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                goto invalid_key;
 
+       /* check the permissions */
        ret = -EACCES;
-       if (!key_permission(key, perm))
+
+       if (!key_task_permission(key, context, perm))
                goto invalid_key;
 
  error:
 long join_session_keyring(const char *name)
 {
        struct task_struct *tsk = current;
-       unsigned long flags;
        struct key *keyring;
        long ret;
 
                if (ret < 0)
                        goto error;
 
-               spin_lock_irqsave(&tsk->sighand->siglock, flags);
-               ret = tsk->signal->session_keyring->serial;
-               spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+               rcu_read_lock();
+               ret = rcu_dereference(tsk->signal->session_keyring)->serial;
+               rcu_read_unlock();
                goto error;
        }
 
 
 /* request_key.c: request a key from userspace
  *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
 #include <linux/sched.h>
 #include <linux/kmod.h>
 #include <linux/err.h>
+#include <linux/keyctl.h>
 #include "internal.h"
 
 struct key_construction {
 /*
  * request userspace finish the construction of a key
  * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
- * - if callout_info is an empty string, it'll be rendered as a "-" instead
  */
 static int call_request_key(struct key *key,
                            const char *op,
                            const char *callout_info)
 {
        struct task_struct *tsk = current;
-       unsigned long flags;
        key_serial_t prkey, sskey;
+       struct key *session_keyring, *rkakey;
        char *argv[10], *envp[3], uid_str[12], gid_str[12];
        char key_str[12], keyring_str[3][12];
-       int i;
+       int ret, i;
+
+       kenter("{%d},%s,%s", key->serial, op, callout_info);
+
+       /* generate a new session keyring with an auth key in it */
+       session_keyring = request_key_auth_new(key, &rkakey);
+       if (IS_ERR(session_keyring)) {
+               ret = PTR_ERR(session_keyring);
+               goto error;
+       }
 
        /* record the UID and GID */
        sprintf(uid_str, "%d", current->fsuid);
        if (tsk->signal->process_keyring)
                prkey = tsk->signal->process_keyring->serial;
 
-       sskey = 0;
-       spin_lock_irqsave(&tsk->sighand->siglock, flags);
-       if (tsk->signal->session_keyring)
-               sskey = tsk->signal->session_keyring->serial;
-       spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
-
+       sprintf(keyring_str[1], "%d", prkey);
 
-       if (!sskey)
+       if (tsk->signal->session_keyring) {
+               rcu_read_lock();
+               sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
+               rcu_read_unlock();
+       }
+       else {
                sskey = tsk->user->session_keyring->serial;
+       }
 
-       sprintf(keyring_str[1], "%d", prkey);
        sprintf(keyring_str[2], "%d", sskey);
 
        /* set up a minimal environment */
        argv[i++] = keyring_str[0];
        argv[i++] = keyring_str[1];
        argv[i++] = keyring_str[2];
-       argv[i++] = callout_info[0] ? (char *) callout_info : "-";
+       argv[i++] = (char *) callout_info;
        argv[i] = NULL;
 
        /* do it */
-       return call_usermodehelper_keys(argv[0], argv, envp, NULL, 1);
+       ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1);
+
+       /* dispose of the special keys */
+       key_revoke(rkakey);
+       key_put(rkakey);
+       key_put(session_keyring);
+
+ error:
+       kleave(" = %d", ret);
+       return ret;
 
 } /* end call_request_key() */
 
        struct key *key;
        int ret, negated;
 
+       kenter("%s,%s,%s", type->name, description, callout_info);
+
        /* create a key and add it to the queue */
        key = key_alloc(type, description,
                        current->fsuid, current->fsgid, KEY_USR_ALL, 0);
        }
 
  out:
+       kleave(" = %p", key);
        return key;
 
  request_failed:
 
        DECLARE_WAITQUEUE(myself, current);
 
+       kenter("%s,%s,{%d},%s",
+              type->name, description, user->uid, callout_info);
+
        /* see if there's such a key under construction already */
        down_write(&key_construction_sem);
 
        /* see about getting userspace to construct the key */
        key = __request_key_construction(type, description, callout_info);
  error:
+       kleave(" = %p", key);
        return key;
 
        /* someone else has the same key under construction
        add_wait_queue(&request_key_conswq, &myself);
 
        for (;;) {
-               set_current_state(TASK_UNINTERRUPTIBLE);
+               set_current_state(TASK_INTERRUPTIBLE);
                if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags))
                        break;
+               if (signal_pending(current))
+                       break;
                schedule();
        }
 
 
 } /* end request_key_construction() */
 
+/*****************************************************************************/
+/*
+ * link a freshly minted key to an appropriate destination keyring
+ */
+static void request_key_link(struct key *key, struct key *dest_keyring)
+{
+       struct task_struct *tsk = current;
+       struct key *drop = NULL;
+
+       kenter("{%d},%p", key->serial, dest_keyring);
+
+       /* find the appropriate keyring */
+       if (!dest_keyring) {
+               switch (tsk->jit_keyring) {
+               case KEY_REQKEY_DEFL_DEFAULT:
+               case KEY_REQKEY_DEFL_THREAD_KEYRING:
+                       dest_keyring = tsk->thread_keyring;
+                       if (dest_keyring)
+                               break;
+
+               case KEY_REQKEY_DEFL_PROCESS_KEYRING:
+                       dest_keyring = tsk->signal->process_keyring;
+                       if (dest_keyring)
+                               break;
+
+               case KEY_REQKEY_DEFL_SESSION_KEYRING:
+                       rcu_read_lock();
+                       dest_keyring = key_get(
+                               rcu_dereference(tsk->signal->session_keyring));
+                       rcu_read_unlock();
+                       drop = dest_keyring;
+
+                       if (dest_keyring)
+                               break;
+
+               case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
+                       dest_keyring = current->user->session_keyring;
+                       break;
+
+               case KEY_REQKEY_DEFL_USER_KEYRING:
+                       dest_keyring = current->user->uid_keyring;
+                       break;
+
+               case KEY_REQKEY_DEFL_GROUP_KEYRING:
+               default:
+                       BUG();
+               }
+       }
+
+       /* and attach the key to it */
+       key_link(dest_keyring, key);
+
+       key_put(drop);
+
+       kleave("");
+
+} /* end request_key_link() */
+
 /*****************************************************************************/
 /*
  * request a key
  * - search the process's keyrings
  * - check the list of keys being created or updated
- * - call out to userspace for a key if requested (supplementary info can be
- *   passed)
+ * - call out to userspace for a key if supplementary info was provided
+ * - cache the key in an appropriate keyring
  */
-struct key *request_key(struct key_type *type,
-                       const char *description,
-                       const char *callout_info)
+struct key *request_key_and_link(struct key_type *type,
+                                const char *description,
+                                const char *callout_info,
+                                struct key *dest_keyring)
 {
        struct key_user *user;
        struct key *key;
 
+       kenter("%s,%s,%s,%p",
+              type->name, description, callout_info, dest_keyring);
+
        /* search all the process keyrings for a key */
-       key = search_process_keyrings_aux(type, description, type->match);
+       key = search_process_keyrings(type, description, type->match, current);
 
        if (PTR_ERR(key) == -EAGAIN) {
                /* the search failed, but the keyrings were searchable, so we
 
                /* - get hold of the user's construction queue */
                user = key_user_lookup(current->fsuid);
-               if (!user) {
-                       key = ERR_PTR(-ENOMEM);
-                       goto error;
-               }
+               if (!user)
+                       goto nomem;
+
+               do {
+                       if (signal_pending(current))
+                               goto interrupted;
 
-               for (;;) {
                        /* ask userspace (returns NULL if it waited on a key
                         * being constructed) */
                        key = request_key_construction(type, description,
 
                        /* someone else made the key we want, so we need to
                         * search again as it might now be available to us */
-                       key = search_process_keyrings_aux(type, description,
-                                                         type->match);
-                       if (PTR_ERR(key) != -EAGAIN)
-                               break;
-               }
+                       key = search_process_keyrings(type, description,
+                                                     type->match, current);
+
+               } while (PTR_ERR(key) == -EAGAIN);
 
                key_user_put(user);
+
+               /* link the new key into the appropriate keyring */
+               if (!PTR_ERR(key))
+                       request_key_link(key, dest_keyring);
        }
 
- error:
+error:
+       kleave(" = %p", key);
        return key;
 
+nomem:
+       key = ERR_PTR(-ENOMEM);
+       goto error;
+
+interrupted:
+       key_user_put(user);
+       key = ERR_PTR(-EINTR);
+       goto error;
+
+} /* end request_key_and_link() */
+
+/*****************************************************************************/
+/*
+ * request a key
+ * - search the process's keyrings
+ * - check the list of keys being created or updated
+ * - call out to userspace for a key if supplementary info was provided
+ */
+struct key *request_key(struct key_type *type,
+                       const char *description,
+                       const char *callout_info)
+{
+       return request_key_and_link(type, description, callout_info, NULL);
+
 } /* end request_key() */
 
 EXPORT_SYMBOL(request_key);
 
--- /dev/null
+/* request_key_auth.c: request key authorisation controlling key def
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * 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/sched.h>
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include "internal.h"
+
+static int request_key_auth_instantiate(struct key *, const void *, size_t);
+static void request_key_auth_describe(const struct key *, struct seq_file *);
+static void request_key_auth_destroy(struct key *);
+
+/*
+ * the request-key authorisation key type definition
+ */
+struct key_type key_type_request_key_auth = {
+       .name           = ".request_key_auth",
+       .def_datalen    = sizeof(struct request_key_auth),
+       .instantiate    = request_key_auth_instantiate,
+       .describe       = request_key_auth_describe,
+       .destroy        = request_key_auth_destroy,
+};
+
+/*****************************************************************************/
+/*
+ * instantiate a request-key authorisation record
+ */
+static int request_key_auth_instantiate(struct key *key,
+                                       const void *data,
+                                       size_t datalen)
+{
+       struct request_key_auth *rka, *irka;
+       struct key *instkey;
+       int ret;
+
+       ret = -ENOMEM;
+       rka = kmalloc(sizeof(*rka), GFP_KERNEL);
+       if (rka) {
+               /* see if the calling process is already servicing the key
+                * request of another process */
+               instkey = key_get_instantiation_authkey(0);
+               if (!IS_ERR(instkey)) {
+                       /* it is - use that instantiation context here too */
+                       irka = instkey->payload.data;
+                       rka->context = irka->context;
+                       rka->pid = irka->pid;
+                       key_put(instkey);
+               }
+               else {
+                       /* it isn't - use this process as the context */
+                       rka->context = current;
+                       rka->pid = current->pid;
+               }
+
+               rka->target_key = key_get((struct key *) data);
+               key->payload.data = rka;
+               ret = 0;
+       }
+
+       return ret;
+
+} /* end request_key_auth_instantiate() */
+
+/*****************************************************************************/
+/*
+ *
+ */
+static void request_key_auth_describe(const struct key *key,
+                                     struct seq_file *m)
+{
+       struct request_key_auth *rka = key->payload.data;
+
+       seq_puts(m, "key:");
+       seq_puts(m, key->description);
+       seq_printf(m, " pid:%d", rka->pid);
+
+} /* end request_key_auth_describe() */
+
+/*****************************************************************************/
+/*
+ * destroy an instantiation authorisation token key
+ */
+static void request_key_auth_destroy(struct key *key)
+{
+       struct request_key_auth *rka = key->payload.data;
+
+       kenter("{%d}", key->serial);
+
+       key_put(rka->target_key);
+
+} /* end request_key_auth_destroy() */
+
+/*****************************************************************************/
+/*
+ * create a session keyring to be for the invokation of /sbin/request-key and
+ * stick an authorisation token in it
+ */
+struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
+{
+       struct key *keyring, *rkakey = NULL;
+       char desc[20];
+       int ret;
+
+       kenter("%d,", target->serial);
+
+       /* allocate a new session keyring */
+       sprintf(desc, "_req.%u", target->serial);
+
+       keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
+       if (IS_ERR(keyring)) {
+               kleave("= %ld", PTR_ERR(keyring));
+               return keyring;
+       }
+
+       /* allocate the auth key */
+       sprintf(desc, "%x", target->serial);
+
+       rkakey = key_alloc(&key_type_request_key_auth, desc,
+                          current->fsuid, current->fsgid,
+                          KEY_USR_VIEW, 1);
+       if (IS_ERR(rkakey)) {
+               key_put(keyring);
+               kleave("= %ld", PTR_ERR(rkakey));
+               return rkakey;
+       }
+
+       /* construct and attach to the keyring */
+       ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL);
+       if (ret < 0) {
+               key_revoke(rkakey);
+               key_put(rkakey);
+               key_put(keyring);
+               kleave("= %d", ret);
+               return ERR_PTR(ret);
+       }
+
+       *_rkakey = rkakey;
+       kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial);
+       return keyring;
+
+} /* end request_key_auth_new() */
+
+/*****************************************************************************/
+/*
+ * get the authorisation key for instantiation of a specific key if attached to
+ * the current process's keyrings
+ * - this key is inserted into a keyring and that is set as /sbin/request-key's
+ *   session keyring
+ * - a target_id of zero specifies any valid token
+ */
+struct key *key_get_instantiation_authkey(key_serial_t target_id)
+{
+       struct task_struct *tsk = current;
+       struct key *instkey;
+
+       /* we must have our own personal session keyring */
+       if (!tsk->signal->session_keyring)
+               return ERR_PTR(-EACCES);
+
+       /* and it must contain a suitable request authorisation key
+        * - lock RCU against session keyring changing
+        */
+       rcu_read_lock();
+
+       instkey = keyring_search_instkey(
+               rcu_dereference(tsk->signal->session_keyring), target_id);
+
+       rcu_read_unlock();
+       return instkey;
+
+} /* end key_get_instantiation_authkey() */