]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - security/keys/key.c
[SCSI] lpfc 8.1.2: Correct use of the hostdata field in scsi_host
[linux-2.6-omap-h63xx.git] / security / keys / key.c
index 2182be9e93093d87596ea965c301812de88484ba..99781b798312f0da18bd7063aa9b7856f7fe48fa 100644 (file)
@@ -1,6 +1,6 @@
 /* key.c: basic authentication token and access key management
  *
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
+#include <linux/security.h>
 #include <linux/workqueue.h>
 #include <linux/err.h>
 #include "internal.h"
@@ -35,7 +36,7 @@ static DECLARE_WORK(key_cleanup_task, key_cleanup, NULL);
 DECLARE_RWSEM(key_construction_sem);
 
 /* any key who's type gets unegistered will be re-typed to this */
-struct key_type key_type_dead = {
+static struct key_type key_type_dead = {
        .name           = "dead",
 };
 
@@ -114,8 +115,7 @@ struct key_user *key_user_lookup(uid_t uid)
  found:
        atomic_inc(&user->usage);
        spin_unlock(&key_user_lock);
-       if (candidate)
-               kfree(candidate);
+       kfree(candidate);
  out:
        return user;
 
@@ -240,9 +240,9 @@ static inline void key_alloc_serial(struct key *key)
 /*
  * allocate a key of the specified type
  * - update the user's quota to reflect the existence of the key
- * - called from a key-type operation with key_types_sem read-locked by either
- *   key_create_or_update() or by key_duplicate(); this prevents unregistration
- *   of the key type
+ * - called from a key-type operation with key_types_sem read-locked by
+ *   key_create_or_update()
+ *   - this prevents unregistration of the key type
  * - upon return the key is as yet uninstantiated; the caller needs to either
  *   instantiate the key or discard it before returning
  */
@@ -253,6 +253,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        struct key_user *user = NULL;
        struct key *key;
        size_t desclen, quotalen;
+       int ret;
 
        key = ERR_PTR(-EINVAL);
        if (!desc || !*desc)
@@ -305,6 +306,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        key->flags = 0;
        key->expiry = 0;
        key->payload.data = NULL;
+       key->security = NULL;
 
        if (!not_in_quota)
                key->flags |= 1 << KEY_FLAG_IN_QUOTA;
@@ -315,16 +317,21 @@ struct key *key_alloc(struct key_type *type, const char *desc,
        key->magic = KEY_DEBUG_MAGIC;
 #endif
 
+       /* let the security module know about the key */
+       ret = security_key_alloc(key);
+       if (ret < 0)
+               goto security_error;
+
        /* publish the key by giving it a serial number */
        atomic_inc(&user->nkeys);
        key_alloc_serial(key);
 
- error:
+error:
        return key;
 
- no_memory_3:
+security_error:
+       kfree(key->description);
        kmem_cache_free(key_jar, key);
- no_memory_2:
        if (!not_in_quota) {
                spin_lock(&user->lock);
                user->qnkeys--;
@@ -332,11 +339,24 @@ struct key *key_alloc(struct key_type *type, const char *desc,
                spin_unlock(&user->lock);
        }
        key_user_put(user);
- no_memory_1:
+       key = ERR_PTR(ret);
+       goto error;
+
+no_memory_3:
+       kmem_cache_free(key_jar, key);
+no_memory_2:
+       if (!not_in_quota) {
+               spin_lock(&user->lock);
+               user->qnkeys--;
+               user->qnbytes -= quotalen;
+               spin_unlock(&user->lock);
+       }
+       key_user_put(user);
+no_memory_1:
        key = ERR_PTR(-ENOMEM);
        goto error;
 
- no_quota:
+no_quota:
        spin_unlock(&user->lock);
        key_user_put(user);
        key = ERR_PTR(-EDQUOT);
@@ -556,6 +576,8 @@ static void key_cleanup(void *data)
 
        key_check(key);
 
+       security_key_free(key);
+
        /* deal with the user's key tracking and quota */
        if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
                spin_lock(&key->user->lock);
@@ -700,8 +722,8 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
        int ret;
 
        /* need write permission on the key to update it */
-       ret = -EACCES;
-       if (!key_permission(key_ref, KEY_WRITE))
+       ret = key_permission(key_ref, KEY_WRITE);
+       if (ret < 0)
                goto error;
 
        ret = -EEXIST;
@@ -711,7 +733,6 @@ static inline key_ref_t __key_update(key_ref_t key_ref,
        down_write(&key->sem);
 
        ret = key->type->update(key, payload, plen);
-
        if (ret == 0)
                /* updating a negative key instantiates it */
                clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
@@ -768,9 +789,11 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
 
        /* if we're going to allocate a new key, we're going to have
         * to modify the keyring */
-       key_ref = ERR_PTR(-EACCES);
-       if (!key_permission(keyring_ref, KEY_WRITE))
+       ret = key_permission(keyring_ref, KEY_WRITE);
+       if (ret < 0) {
+               key_ref = ERR_PTR(ret);
                goto error_3;
+       }
 
        /* search for an existing key of the same type and description in the
         * destination keyring
@@ -780,8 +803,8 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
                goto found_matching_key;
 
        /* decide on the permissions we want */
-       perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK;
-       perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK;
+       perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
+       perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR;
 
        if (ktype->read)
                perm |= KEY_POS_READ | KEY_USR_READ;
@@ -840,16 +863,16 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
        key_check(key);
 
        /* the key must be writable */
-       ret = -EACCES;
-       if (!key_permission(key_ref, KEY_WRITE))
+       ret = key_permission(key_ref, KEY_WRITE);
+       if (ret < 0)
                goto error;
 
        /* attempt to update it if supported */
        ret = -EOPNOTSUPP;
        if (key->type->update) {
                down_write(&key->sem);
-               ret = key->type->update(key, payload, plen);
 
+               ret = key->type->update(key, payload, plen);
                if (ret == 0)
                        /* updating a negative key instantiates it */
                        clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
@@ -864,56 +887,6 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
 
 EXPORT_SYMBOL(key_update);
 
-/*****************************************************************************/
-/*
- * duplicate a key, potentially with a revised description
- * - must be supported by the keytype (keyrings for instance can be duplicated)
- */
-struct key *key_duplicate(struct key *source, const char *desc)
-{
-       struct key *key;
-       int ret;
-
-       key_check(source);
-
-       if (!desc)
-               desc = source->description;
-
-       down_read(&key_types_sem);
-
-       ret = -EINVAL;
-       if (!source->type->duplicate)
-               goto error;
-
-       /* allocate and instantiate a key */
-       key = key_alloc(source->type, desc, current->fsuid, current->fsgid,
-                       source->perm, 0);
-       if (IS_ERR(key))
-               goto error_k;
-
-       down_read(&source->sem);
-       ret = key->type->duplicate(key, source);
-       up_read(&source->sem);
-       if (ret < 0)
-               goto error2;
-
-       atomic_inc(&key->user->nikeys);
-       set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
-
- error_k:
-       up_read(&key_types_sem);
- out:
-       return key;
-
- error2:
-       key_put(key);
- error:
-       up_read(&key_types_sem);
-       key = ERR_PTR(ret);
-       goto out;
-
-} /* end key_duplicate() */
-
 /*****************************************************************************/
 /*
  * revoke a key