linux/fs/nfs/idmap.c
<<
>>
Prefs
   1/*
   2 * fs/nfs/idmap.c
   3 *
   4 *  UID and GID to name mapping for clients.
   5 *
   6 *  Copyright (c) 2002 The Regents of the University of Michigan.
   7 *  All rights reserved.
   8 *
   9 *  Marius Aamodt Eriksen <marius@umich.edu>
  10 *
  11 *  Redistribution and use in source and binary forms, with or without
  12 *  modification, are permitted provided that the following conditions
  13 *  are met:
  14 *
  15 *  1. Redistributions of source code must retain the above copyright
  16 *     notice, this list of conditions and the following disclaimer.
  17 *  2. Redistributions in binary form must reproduce the above copyright
  18 *     notice, this list of conditions and the following disclaimer in the
  19 *     documentation and/or other materials provided with the distribution.
  20 *  3. Neither the name of the University nor the names of its
  21 *     contributors may be used to endorse or promote products derived
  22 *     from this software without specific prior written permission.
  23 *
  24 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  25 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  26 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  27 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  30 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  31 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  32 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  33 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  34 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35 */
  36
  37#include <linux/module.h>
  38#include <linux/mutex.h>
  39#include <linux/init.h>
  40#include <linux/types.h>
  41#include <linux/slab.h>
  42#include <linux/socket.h>
  43#include <linux/in.h>
  44#include <linux/sched.h>
  45
  46#include <linux/sunrpc/clnt.h>
  47#include <linux/workqueue.h>
  48#include <linux/sunrpc/rpc_pipe_fs.h>
  49
  50#include <linux/nfs_fs.h>
  51
  52#include <linux/nfs_idmap.h>
  53#include "nfs4_fs.h"
  54
  55#define IDMAP_HASH_SZ          128
  56
  57/* Default cache timeout is 10 minutes */
  58unsigned int nfs_idmap_cache_timeout = 600 * HZ;
  59
  60static int param_set_idmap_timeout(const char *val, struct kernel_param *kp)
  61{
  62        char *endp;
  63        int num = simple_strtol(val, &endp, 0);
  64        int jif = num * HZ;
  65        if (endp == val || *endp || num < 0 || jif < num)
  66                return -EINVAL;
  67        *((int *)kp->arg) = jif;
  68        return 0;
  69}
  70
  71module_param_call(idmap_cache_timeout, param_set_idmap_timeout, param_get_int,
  72                 &nfs_idmap_cache_timeout, 0644);
  73
  74struct idmap_hashent {
  75        unsigned long           ih_expires;
  76        __u32                   ih_id;
  77        size_t                  ih_namelen;
  78        char                    ih_name[IDMAP_NAMESZ];
  79};
  80
  81struct idmap_hashtable {
  82        __u8                    h_type;
  83        struct idmap_hashent    h_entries[IDMAP_HASH_SZ];
  84};
  85
  86struct idmap {
  87        struct dentry           *idmap_dentry;
  88        wait_queue_head_t       idmap_wq;
  89        struct idmap_msg        idmap_im;
  90        struct mutex            idmap_lock;     /* Serializes upcalls */
  91        struct mutex            idmap_im_lock;  /* Protects the hashtable */
  92        struct idmap_hashtable  idmap_user_hash;
  93        struct idmap_hashtable  idmap_group_hash;
  94};
  95
  96static ssize_t idmap_pipe_upcall(struct file *, struct rpc_pipe_msg *,
  97                                 char __user *, size_t);
  98static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
  99                                   size_t);
 100static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
 101
 102static unsigned int fnvhash32(const void *, size_t);
 103
 104static const struct rpc_pipe_ops idmap_upcall_ops = {
 105        .upcall         = idmap_pipe_upcall,
 106        .downcall       = idmap_pipe_downcall,
 107        .destroy_msg    = idmap_pipe_destroy_msg,
 108};
 109
 110int
 111nfs_idmap_new(struct nfs_client *clp)
 112{
 113        struct idmap *idmap;
 114        int error;
 115
 116        BUG_ON(clp->cl_idmap != NULL);
 117
 118        idmap = kzalloc(sizeof(*idmap), GFP_KERNEL);
 119        if (idmap == NULL)
 120                return -ENOMEM;
 121
 122        idmap->idmap_dentry = rpc_mkpipe(clp->cl_rpcclient->cl_path.dentry,
 123                        "idmap", idmap, &idmap_upcall_ops, 0);
 124        if (IS_ERR(idmap->idmap_dentry)) {
 125                error = PTR_ERR(idmap->idmap_dentry);
 126                kfree(idmap);
 127                return error;
 128        }
 129
 130        mutex_init(&idmap->idmap_lock);
 131        mutex_init(&idmap->idmap_im_lock);
 132        init_waitqueue_head(&idmap->idmap_wq);
 133        idmap->idmap_user_hash.h_type = IDMAP_TYPE_USER;
 134        idmap->idmap_group_hash.h_type = IDMAP_TYPE_GROUP;
 135
 136        clp->cl_idmap = idmap;
 137        return 0;
 138}
 139
 140void
 141nfs_idmap_delete(struct nfs_client *clp)
 142{
 143        struct idmap *idmap = clp->cl_idmap;
 144
 145        if (!idmap)
 146                return;
 147        rpc_unlink(idmap->idmap_dentry);
 148        clp->cl_idmap = NULL;
 149        kfree(idmap);
 150}
 151
 152/*
 153 * Helper routines for manipulating the hashtable
 154 */
 155static inline struct idmap_hashent *
 156idmap_name_hash(struct idmap_hashtable* h, const char *name, size_t len)
 157{
 158        return &h->h_entries[fnvhash32(name, len) % IDMAP_HASH_SZ];
 159}
 160
 161static struct idmap_hashent *
 162idmap_lookup_name(struct idmap_hashtable *h, const char *name, size_t len)
 163{
 164        struct idmap_hashent *he = idmap_name_hash(h, name, len);
 165
 166        if (he->ih_namelen != len || memcmp(he->ih_name, name, len) != 0)
 167                return NULL;
 168        if (time_after(jiffies, he->ih_expires))
 169                return NULL;
 170        return he;
 171}
 172
 173static inline struct idmap_hashent *
 174idmap_id_hash(struct idmap_hashtable* h, __u32 id)
 175{
 176        return &h->h_entries[fnvhash32(&id, sizeof(id)) % IDMAP_HASH_SZ];
 177}
 178
 179static struct idmap_hashent *
 180idmap_lookup_id(struct idmap_hashtable *h, __u32 id)
 181{
 182        struct idmap_hashent *he = idmap_id_hash(h, id);
 183        if (he->ih_id != id || he->ih_namelen == 0)
 184                return NULL;
 185        if (time_after(jiffies, he->ih_expires))
 186                return NULL;
 187        return he;
 188}
 189
 190/*
 191 * Routines for allocating new entries in the hashtable.
 192 * For now, we just have 1 entry per bucket, so it's all
 193 * pretty trivial.
 194 */
 195static inline struct idmap_hashent *
 196idmap_alloc_name(struct idmap_hashtable *h, char *name, size_t len)
 197{
 198        return idmap_name_hash(h, name, len);
 199}
 200
 201static inline struct idmap_hashent *
 202idmap_alloc_id(struct idmap_hashtable *h, __u32 id)
 203{
 204        return idmap_id_hash(h, id);
 205}
 206
 207static void
 208idmap_update_entry(struct idmap_hashent *he, const char *name,
 209                size_t namelen, __u32 id)
 210{
 211        he->ih_id = id;
 212        memcpy(he->ih_name, name, namelen);
 213        he->ih_name[namelen] = '\0';
 214        he->ih_namelen = namelen;
 215        he->ih_expires = jiffies + nfs_idmap_cache_timeout;
 216}
 217
 218/*
 219 * Name -> ID
 220 */
 221static int
 222nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h,
 223                const char *name, size_t namelen, __u32 *id)
 224{
 225        struct rpc_pipe_msg msg;
 226        struct idmap_msg *im;
 227        struct idmap_hashent *he;
 228        DECLARE_WAITQUEUE(wq, current);
 229        int ret = -EIO;
 230
 231        im = &idmap->idmap_im;
 232
 233        /*
 234         * String sanity checks
 235         * Note that the userland daemon expects NUL terminated strings
 236         */
 237        for (;;) {
 238                if (namelen == 0)
 239                        return -EINVAL;
 240                if (name[namelen-1] != '\0')
 241                        break;
 242                namelen--;
 243        }
 244        if (namelen >= IDMAP_NAMESZ)
 245                return -EINVAL;
 246
 247        mutex_lock(&idmap->idmap_lock);
 248        mutex_lock(&idmap->idmap_im_lock);
 249
 250        he = idmap_lookup_name(h, name, namelen);
 251        if (he != NULL) {
 252                *id = he->ih_id;
 253                ret = 0;
 254                goto out;
 255        }
 256
 257        memset(im, 0, sizeof(*im));
 258        memcpy(im->im_name, name, namelen);
 259
 260        im->im_type = h->h_type;
 261        im->im_conv = IDMAP_CONV_NAMETOID;
 262
 263        memset(&msg, 0, sizeof(msg));
 264        msg.data = im;
 265        msg.len = sizeof(*im);
 266
 267        add_wait_queue(&idmap->idmap_wq, &wq);
 268        if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
 269                remove_wait_queue(&idmap->idmap_wq, &wq);
 270                goto out;
 271        }
 272
 273        set_current_state(TASK_UNINTERRUPTIBLE);
 274        mutex_unlock(&idmap->idmap_im_lock);
 275        schedule();
 276        __set_current_state(TASK_RUNNING);
 277        remove_wait_queue(&idmap->idmap_wq, &wq);
 278        mutex_lock(&idmap->idmap_im_lock);
 279
 280        if (im->im_status & IDMAP_STATUS_SUCCESS) {
 281                *id = im->im_id;
 282                ret = 0;
 283        }
 284
 285 out:
 286        memset(im, 0, sizeof(*im));
 287        mutex_unlock(&idmap->idmap_im_lock);
 288        mutex_unlock(&idmap->idmap_lock);
 289        return ret;
 290}
 291
 292/*
 293 * ID -> Name
 294 */
 295static int
 296nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h,
 297                __u32 id, char *name)
 298{
 299        struct rpc_pipe_msg msg;
 300        struct idmap_msg *im;
 301        struct idmap_hashent *he;
 302        DECLARE_WAITQUEUE(wq, current);
 303        int ret = -EIO;
 304        unsigned int len;
 305
 306        im = &idmap->idmap_im;
 307
 308        mutex_lock(&idmap->idmap_lock);
 309        mutex_lock(&idmap->idmap_im_lock);
 310
 311        he = idmap_lookup_id(h, id);
 312        if (he) {
 313                memcpy(name, he->ih_name, he->ih_namelen);
 314                ret = he->ih_namelen;
 315                goto out;
 316        }
 317
 318        memset(im, 0, sizeof(*im));
 319        im->im_type = h->h_type;
 320        im->im_conv = IDMAP_CONV_IDTONAME;
 321        im->im_id = id;
 322
 323        memset(&msg, 0, sizeof(msg));
 324        msg.data = im;
 325        msg.len = sizeof(*im);
 326
 327        add_wait_queue(&idmap->idmap_wq, &wq);
 328
 329        if (rpc_queue_upcall(idmap->idmap_dentry->d_inode, &msg) < 0) {
 330                remove_wait_queue(&idmap->idmap_wq, &wq);
 331                goto out;
 332        }
 333
 334        set_current_state(TASK_UNINTERRUPTIBLE);
 335        mutex_unlock(&idmap->idmap_im_lock);
 336        schedule();
 337        __set_current_state(TASK_RUNNING);
 338        remove_wait_queue(&idmap->idmap_wq, &wq);
 339        mutex_lock(&idmap->idmap_im_lock);
 340
 341        if (im->im_status & IDMAP_STATUS_SUCCESS) {
 342                if ((len = strnlen(im->im_name, IDMAP_NAMESZ)) == 0)
 343                        goto out;
 344                memcpy(name, im->im_name, len);
 345                ret = len;
 346        }
 347
 348 out:
 349        memset(im, 0, sizeof(*im));
 350        mutex_unlock(&idmap->idmap_im_lock);
 351        mutex_unlock(&idmap->idmap_lock);
 352        return ret;
 353}
 354
 355/* RPC pipefs upcall/downcall routines */
 356static ssize_t
 357idmap_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg,
 358                  char __user *dst, size_t buflen)
 359{
 360        char *data = (char *)msg->data + msg->copied;
 361        size_t mlen = min(msg->len, buflen);
 362        unsigned long left;
 363
 364        left = copy_to_user(dst, data, mlen);
 365        if (left == mlen) {
 366                msg->errno = -EFAULT;
 367                return -EFAULT;
 368        }
 369
 370        mlen -= left;
 371        msg->copied += mlen;
 372        msg->errno = 0;
 373        return mlen;
 374}
 375
 376static ssize_t
 377idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 378{
 379        struct rpc_inode *rpci = RPC_I(filp->f_path.dentry->d_inode);
 380        struct idmap *idmap = (struct idmap *)rpci->private;
 381        struct idmap_msg im_in, *im = &idmap->idmap_im;
 382        struct idmap_hashtable *h;
 383        struct idmap_hashent *he = NULL;
 384        size_t namelen_in;
 385        int ret;
 386
 387        if (mlen != sizeof(im_in))
 388                return -ENOSPC;
 389
 390        if (copy_from_user(&im_in, src, mlen) != 0)
 391                return -EFAULT;
 392
 393        mutex_lock(&idmap->idmap_im_lock);
 394
 395        ret = mlen;
 396        im->im_status = im_in.im_status;
 397        /* If we got an error, terminate now, and wake up pending upcalls */
 398        if (!(im_in.im_status & IDMAP_STATUS_SUCCESS)) {
 399                wake_up(&idmap->idmap_wq);
 400                goto out;
 401        }
 402
 403        /* Sanity checking of strings */
 404        ret = -EINVAL;
 405        namelen_in = strnlen(im_in.im_name, IDMAP_NAMESZ);
 406        if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ)
 407                goto out;
 408
 409        switch (im_in.im_type) {
 410                case IDMAP_TYPE_USER:
 411                        h = &idmap->idmap_user_hash;
 412                        break;
 413                case IDMAP_TYPE_GROUP:
 414                        h = &idmap->idmap_group_hash;
 415                        break;
 416                default:
 417                        goto out;
 418        }
 419
 420        switch (im_in.im_conv) {
 421        case IDMAP_CONV_IDTONAME:
 422                /* Did we match the current upcall? */
 423                if (im->im_conv == IDMAP_CONV_IDTONAME
 424                                && im->im_type == im_in.im_type
 425                                && im->im_id == im_in.im_id) {
 426                        /* Yes: copy string, including the terminating '\0'  */
 427                        memcpy(im->im_name, im_in.im_name, namelen_in);
 428                        im->im_name[namelen_in] = '\0';
 429                        wake_up(&idmap->idmap_wq);
 430                }
 431                he = idmap_alloc_id(h, im_in.im_id);
 432                break;
 433        case IDMAP_CONV_NAMETOID:
 434                /* Did we match the current upcall? */
 435                if (im->im_conv == IDMAP_CONV_NAMETOID
 436                                && im->im_type == im_in.im_type
 437                                && strnlen(im->im_name, IDMAP_NAMESZ) == namelen_in
 438                                && memcmp(im->im_name, im_in.im_name, namelen_in) == 0) {
 439                        im->im_id = im_in.im_id;
 440                        wake_up(&idmap->idmap_wq);
 441                }
 442                he = idmap_alloc_name(h, im_in.im_name, namelen_in);
 443                break;
 444        default:
 445                goto out;
 446        }
 447
 448        /* If the entry is valid, also copy it to the cache */
 449        if (he != NULL)
 450                idmap_update_entry(he, im_in.im_name, namelen_in, im_in.im_id);
 451        ret = mlen;
 452out:
 453        mutex_unlock(&idmap->idmap_im_lock);
 454        return ret;
 455}
 456
 457static void
 458idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 459{
 460        struct idmap_msg *im = msg->data;
 461        struct idmap *idmap = container_of(im, struct idmap, idmap_im); 
 462
 463        if (msg->errno >= 0)
 464                return;
 465        mutex_lock(&idmap->idmap_im_lock);
 466        im->im_status = IDMAP_STATUS_LOOKUPFAIL;
 467        wake_up(&idmap->idmap_wq);
 468        mutex_unlock(&idmap->idmap_im_lock);
 469}
 470
 471/* 
 472 * Fowler/Noll/Vo hash
 473 *    http://www.isthe.com/chongo/tech/comp/fnv/
 474 */
 475
 476#define FNV_P_32 ((unsigned int)0x01000193) /* 16777619 */
 477#define FNV_1_32 ((unsigned int)0x811c9dc5) /* 2166136261 */
 478
 479static unsigned int fnvhash32(const void *buf, size_t buflen)
 480{
 481        const unsigned char *p, *end = (const unsigned char *)buf + buflen;
 482        unsigned int hash = FNV_1_32;
 483
 484        for (p = buf; p < end; p++) {
 485                hash *= FNV_P_32;
 486                hash ^= (unsigned int)*p;
 487        }
 488
 489        return hash;
 490}
 491
 492int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
 493{
 494        struct idmap *idmap = clp->cl_idmap;
 495
 496        return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
 497}
 498
 499int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid)
 500{
 501        struct idmap *idmap = clp->cl_idmap;
 502
 503        return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
 504}
 505
 506int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf)
 507{
 508        struct idmap *idmap = clp->cl_idmap;
 509
 510        return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
 511}
 512int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf)
 513{
 514        struct idmap *idmap = clp->cl_idmap;
 515
 516        return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
 517}
 518
 519