[Bluetooth] Read local version information on device init
[pandora-kernel.git] / security / keys / request_key.c
index 5cc4bba..f573ac1 100644 (file)
@@ -1,6 +1,6 @@
 /* request_key.c: request a key from userspace
  *
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -29,28 +29,38 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
 /*****************************************************************************/
 /*
  * request userspace finish the construction of a key
- * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
+ * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
  */
-static int call_request_key(struct key *key,
-                           const char *op,
-                           const char *callout_info)
+static int call_sbin_request_key(struct key *key,
+                                struct key *authkey,
+                                const char *op,
+                                void *aux)
 {
        struct task_struct *tsk = current;
        key_serial_t prkey, sskey;
-       struct key *session_keyring, *rkakey;
-       char *argv[10], *envp[3], uid_str[12], gid_str[12];
+       struct key *keyring;
+       char *argv[9], *envp[3], uid_str[12], gid_str[12];
        char key_str[12], keyring_str[3][12];
+       char desc[20];
        int ret, i;
 
-       kenter("{%d},%s,%s", key->serial, op, callout_info);
+       kenter("{%d},{%d},%s", key->serial, authkey->serial, op);
 
-       /* 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;
+       /* allocate a new session keyring */
+       sprintf(desc, "_req.%u", key->serial);
+
+       keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
+                               KEY_ALLOC_QUOTA_OVERRUN, NULL);
+       if (IS_ERR(keyring)) {
+               ret = PTR_ERR(keyring);
+               goto error_alloc;
        }
 
+       /* attach the auth key to the session keyring */
+       ret = __key_link(keyring, authkey);
+       if (ret < 0)
+               goto error_link;
+
        /* record the UID and GID */
        sprintf(uid_str, "%d", current->fsuid);
        sprintf(gid_str, "%d", current->fsgid);
@@ -95,22 +105,19 @@ static int call_request_key(struct key *key,
        argv[i++] = keyring_str[0];
        argv[i++] = keyring_str[1];
        argv[i++] = keyring_str[2];
-       argv[i++] = (char *) callout_info;
        argv[i] = NULL;
 
        /* do it */
-       ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1);
+       ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1);
 
-       /* dispose of the special keys */
-       key_revoke(rkakey);
-       key_put(rkakey);
-       key_put(session_keyring);
+error_link:
+       key_put(keyring);
 
- error:
+error_alloc:
        kleave(" = %d", ret);
        return ret;
 
-} /* end call_request_key() */
+} /* end call_sbin_request_key() */
 
 /*****************************************************************************/
 /*
@@ -120,18 +127,22 @@ static int call_request_key(struct key *key,
  */
 static struct key *__request_key_construction(struct key_type *type,
                                              const char *description,
-                                             const char *callout_info)
+                                             const char *callout_info,
+                                             void *aux,
+                                             unsigned long flags)
 {
+       request_key_actor_t actor;
        struct key_construction cons;
        struct timespec now;
-       struct key *key;
+       struct key *key, *authkey;
        int ret, negated;
 
-       kenter("%s,%s,%s", type->name, description, callout_info);
+       kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags);
 
        /* create a key and add it to the queue */
        key = key_alloc(type, description,
-                       current->fsuid, current->fsgid, KEY_POS_ALL, 0);
+                       current->fsuid, current->fsgid, current, KEY_POS_ALL,
+                       flags);
        if (IS_ERR(key))
                goto alloc_failed;
 
@@ -143,8 +154,19 @@ static struct key *__request_key_construction(struct key_type *type,
        /* we drop the construction sem here on behalf of the caller */
        up_write(&key_construction_sem);
 
+       /* allocate an authorisation key */
+       authkey = request_key_auth_new(key, callout_info);
+       if (IS_ERR(authkey)) {
+               ret = PTR_ERR(authkey);
+               authkey = NULL;
+               goto alloc_authkey_failed;
+       }
+
        /* make the call */
-       ret = call_request_key(key, "create", callout_info);
+       actor = call_sbin_request_key;
+       if (type->request_key)
+               actor = type->request_key;
+       ret = actor(key, authkey, "create", aux);
        if (ret < 0)
                goto request_failed;
 
@@ -153,22 +175,29 @@ static struct key *__request_key_construction(struct key_type *type,
        if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
                goto request_failed;
 
+       key_revoke(authkey);
+       key_put(authkey);
+
        down_write(&key_construction_sem);
        list_del(&cons.link);
        up_write(&key_construction_sem);
 
        /* also give an error if the key was negatively instantiated */
- check_not_negative:
+check_not_negative:
        if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
                key_put(key);
                key = ERR_PTR(-ENOKEY);
        }
 
- out:
+out:
        kleave(" = %p", key);
        return key;
 
- request_failed:
+request_failed:
+       key_revoke(authkey);
+       key_put(authkey);
+
+alloc_authkey_failed:
        /* it wasn't instantiated
         * - remove from construction queue
         * - mark the key as dead
@@ -217,7 +246,7 @@ static struct key *__request_key_construction(struct key_type *type,
        key = ERR_PTR(ret);
        goto out;
 
- alloc_failed:
+alloc_failed:
        up_write(&key_construction_sem);
        goto out;
 
@@ -231,16 +260,18 @@ static struct key *__request_key_construction(struct key_type *type,
  */
 static struct key *request_key_construction(struct key_type *type,
                                            const char *description,
+                                           const char *callout_info,
+                                           void *aux,
                                            struct key_user *user,
-                                           const char *callout_info)
+                                           unsigned long flags)
 {
        struct key_construction *pcons;
        struct key *key, *ckey;
 
        DECLARE_WAITQUEUE(myself, current);
 
-       kenter("%s,%s,{%d},%s",
-              type->name, description, user->uid, callout_info);
+       kenter("%s,%s,{%d},%s,%lx",
+              type->name, description, user->uid, callout_info, flags);
 
        /* see if there's such a key under construction already */
        down_write(&key_construction_sem);
@@ -256,7 +287,8 @@ static struct key *request_key_construction(struct key_type *type,
        }
 
        /* see about getting userspace to construct the key */
-       key = __request_key_construction(type, description, callout_info);
+       key = __request_key_construction(type, description, callout_info, aux,
+                                        flags);
  error:
        kleave(" = %p", key);
        return key;
@@ -363,14 +395,17 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
 struct key *request_key_and_link(struct key_type *type,
                                 const char *description,
                                 const char *callout_info,
-                                struct key *dest_keyring)
+                                void *aux,
+                                struct key *dest_keyring,
+                                unsigned long flags)
 {
        struct key_user *user;
        struct key *key;
        key_ref_t key_ref;
 
-       kenter("%s,%s,%s,%p",
-              type->name, description, callout_info, dest_keyring);
+       kenter("%s,%s,%s,%p,%p,%lx",
+              type->name, description, callout_info, aux,
+              dest_keyring, flags);
 
        /* search all the process keyrings for a key */
        key_ref = search_process_keyrings(type, description, type->match,
@@ -403,7 +438,8 @@ struct key *request_key_and_link(struct key_type *type,
                        /* ask userspace (returns NULL if it waited on a key
                         * being constructed) */
                        key = request_key_construction(type, description,
-                                                      user, callout_info);
+                                                      callout_info, aux,
+                                                      user, flags);
                        if (key)
                                break;
 
@@ -459,7 +495,8 @@ 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);
+       return request_key_and_link(type, description, callout_info, NULL,
+                                   NULL, KEY_ALLOC_IN_QUOTA);
 
 } /* end request_key() */
 
@@ -467,32 +504,19 @@ EXPORT_SYMBOL(request_key);
 
 /*****************************************************************************/
 /*
- * validate a key
+ * request a key with auxiliary data for the upcaller
+ * - 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
  */
-int key_validate(struct key *key)
+struct key *request_key_with_auxdata(struct key_type *type,
+                                    const char *description,
+                                    const char *callout_info,
+                                    void *aux)
 {
-       struct timespec now;
-       int ret = 0;
-
-       if (key) {
-               /* check it's still accessible */
-               ret = -EKEYREVOKED;
-               if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
-                   test_bit(KEY_FLAG_DEAD, &key->flags))
-                       goto error;
-
-               /* check it hasn't expired */
-               ret = 0;
-               if (key->expiry) {
-                       now = current_kernel_time();
-                       if (now.tv_sec >= key->expiry)
-                               ret = -EKEYEXPIRED;
-               }
-       }
-
- error:
-       return ret;
+       return request_key_and_link(type, description, callout_info, aux,
+                                   NULL, KEY_ALLOC_IN_QUOTA);
 
-} /* end key_validate() */
+} /* end request_key_with_auxdata() */
 
-EXPORT_SYMBOL(key_validate);
+EXPORT_SYMBOL(request_key_with_auxdata);