linux/security/keys/user_defined.c
<<
>>
Prefs
   1/* user_defined.c: user defined key type
   2 *
   3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/init.h>
  14#include <linux/slab.h>
  15#include <linux/seq_file.h>
  16#include <linux/err.h>
  17#include <keys/user-type.h>
  18#include <asm/uaccess.h>
  19#include "internal.h"
  20
  21/*
  22 * user defined keys take an arbitrary string as the description and an
  23 * arbitrary blob of data as the payload
  24 */
  25struct key_type key_type_user = {
  26        .name           = "user",
  27        .instantiate    = user_instantiate,
  28        .update         = user_update,
  29        .match          = user_match,
  30        .revoke         = user_revoke,
  31        .destroy        = user_destroy,
  32        .describe       = user_describe,
  33        .read           = user_read,
  34};
  35
  36EXPORT_SYMBOL_GPL(key_type_user);
  37
  38/*****************************************************************************/
  39/*
  40 * instantiate a user defined key
  41 */
  42int user_instantiate(struct key *key, const void *data, size_t datalen)
  43{
  44        struct user_key_payload *upayload;
  45        int ret;
  46
  47        ret = -EINVAL;
  48        if (datalen <= 0 || datalen > 32767 || !data)
  49                goto error;
  50
  51        ret = key_payload_reserve(key, datalen);
  52        if (ret < 0)
  53                goto error;
  54
  55        ret = -ENOMEM;
  56        upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
  57        if (!upayload)
  58                goto error;
  59
  60        /* attach the data */
  61        upayload->datalen = datalen;
  62        memcpy(upayload->data, data, datalen);
  63        rcu_assign_pointer(key->payload.data, upayload);
  64        ret = 0;
  65
  66error:
  67        return ret;
  68
  69} /* end user_instantiate() */
  70
  71EXPORT_SYMBOL_GPL(user_instantiate);
  72
  73/*****************************************************************************/
  74/*
  75 * dispose of the old data from an updated user defined key
  76 */
  77static void user_update_rcu_disposal(struct rcu_head *rcu)
  78{
  79        struct user_key_payload *upayload;
  80
  81        upayload = container_of(rcu, struct user_key_payload, rcu);
  82
  83        kfree(upayload);
  84
  85} /* end user_update_rcu_disposal() */
  86
  87/*****************************************************************************/
  88/*
  89 * update a user defined key
  90 * - the key's semaphore is write-locked
  91 */
  92int user_update(struct key *key, const void *data, size_t datalen)
  93{
  94        struct user_key_payload *upayload, *zap;
  95        int ret;
  96
  97        ret = -EINVAL;
  98        if (datalen <= 0 || datalen > 32767 || !data)
  99                goto error;
 100
 101        /* construct a replacement payload */
 102        ret = -ENOMEM;
 103        upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
 104        if (!upayload)
 105                goto error;
 106
 107        upayload->datalen = datalen;
 108        memcpy(upayload->data, data, datalen);
 109
 110        /* check the quota and attach the new data */
 111        zap = upayload;
 112
 113        ret = key_payload_reserve(key, datalen);
 114
 115        if (ret == 0) {
 116                /* attach the new data, displacing the old */
 117                zap = key->payload.data;
 118                rcu_assign_pointer(key->payload.data, upayload);
 119                key->expiry = 0;
 120        }
 121
 122        call_rcu(&zap->rcu, user_update_rcu_disposal);
 123
 124error:
 125        return ret;
 126
 127} /* end user_update() */
 128
 129EXPORT_SYMBOL_GPL(user_update);
 130
 131/*****************************************************************************/
 132/*
 133 * match users on their name
 134 */
 135int user_match(const struct key *key, const void *description)
 136{
 137        return strcmp(key->description, description) == 0;
 138
 139} /* end user_match() */
 140
 141EXPORT_SYMBOL_GPL(user_match);
 142
 143/*****************************************************************************/
 144/*
 145 * dispose of the links from a revoked keyring
 146 * - called with the key sem write-locked
 147 */
 148void user_revoke(struct key *key)
 149{
 150        struct user_key_payload *upayload = key->payload.data;
 151
 152        /* clear the quota */
 153        key_payload_reserve(key, 0);
 154
 155        if (upayload) {
 156                rcu_assign_pointer(key->payload.data, NULL);
 157                call_rcu(&upayload->rcu, user_update_rcu_disposal);
 158        }
 159
 160} /* end user_revoke() */
 161
 162EXPORT_SYMBOL(user_revoke);
 163
 164/*****************************************************************************/
 165/*
 166 * dispose of the data dangling from the corpse of a user key
 167 */
 168void user_destroy(struct key *key)
 169{
 170        struct user_key_payload *upayload = key->payload.data;
 171
 172        kfree(upayload);
 173
 174} /* end user_destroy() */
 175
 176EXPORT_SYMBOL_GPL(user_destroy);
 177
 178/*****************************************************************************/
 179/*
 180 * describe the user key
 181 */
 182void user_describe(const struct key *key, struct seq_file *m)
 183{
 184        seq_puts(m, key->description);
 185
 186        seq_printf(m, ": %u", key->datalen);
 187
 188} /* end user_describe() */
 189
 190EXPORT_SYMBOL_GPL(user_describe);
 191
 192/*****************************************************************************/
 193/*
 194 * read the key data
 195 * - the key's semaphore is read-locked
 196 */
 197long user_read(const struct key *key, char __user *buffer, size_t buflen)
 198{
 199        struct user_key_payload *upayload;
 200        long ret;
 201
 202        upayload = rcu_dereference(key->payload.data);
 203        ret = upayload->datalen;
 204
 205        /* we can return the data as is */
 206        if (buffer && buflen > 0) {
 207                if (buflen > upayload->datalen)
 208                        buflen = upayload->datalen;
 209
 210                if (copy_to_user(buffer, upayload->data, buflen) != 0)
 211                        ret = -EFAULT;
 212        }
 213
 214        return ret;
 215
 216} /* end user_read() */
 217
 218EXPORT_SYMBOL_GPL(user_read);
 219