linux/fs/nfsd/export.c
<<
>>
Prefs
   1/*
   2 * NFS exporting and validation.
   3 *
   4 * We maintain a list of clients, each of which has a list of
   5 * exports. To export an fs to a given client, you first have
   6 * to create the client entry with NFSCTL_ADDCLIENT, which
   7 * creates a client control block and adds it to the hash
   8 * table. Then, you call NFSCTL_EXPORT for each fs.
   9 *
  10 *
  11 * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
  12 */
  13
  14#include <linux/slab.h>
  15#include <linux/namei.h>
  16#include <linux/module.h>
  17#include <linux/exportfs.h>
  18#include <linux/sunrpc/svc_xprt.h>
  19
  20#include <net/ipv6.h>
  21
  22#include "nfsd.h"
  23#include "nfsfh.h"
  24#include "netns.h"
  25
  26#define NFSDDBG_FACILITY        NFSDDBG_EXPORT
  27
  28typedef struct auth_domain      svc_client;
  29typedef struct svc_export       svc_export;
  30
  31/*
  32 * We have two caches.
  33 * One maps client+vfsmnt+dentry to export options - the export map
  34 * The other maps client+filehandle-fragment to export options. - the expkey map
  35 *
  36 * The export options are actually stored in the first map, and the
  37 * second map contains a reference to the entry in the first map.
  38 */
  39
  40#define EXPKEY_HASHBITS         8
  41#define EXPKEY_HASHMAX          (1 << EXPKEY_HASHBITS)
  42#define EXPKEY_HASHMASK         (EXPKEY_HASHMAX -1)
  43
  44static void expkey_put(struct kref *ref)
  45{
  46        struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
  47
  48        if (test_bit(CACHE_VALID, &key->h.flags) &&
  49            !test_bit(CACHE_NEGATIVE, &key->h.flags))
  50                path_put(&key->ek_path);
  51        auth_domain_put(key->ek_client);
  52        kfree(key);
  53}
  54
  55static void expkey_request(struct cache_detail *cd,
  56                           struct cache_head *h,
  57                           char **bpp, int *blen)
  58{
  59        /* client fsidtype \xfsid */
  60        struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
  61        char type[5];
  62
  63        qword_add(bpp, blen, ek->ek_client->name);
  64        snprintf(type, 5, "%d", ek->ek_fsidtype);
  65        qword_add(bpp, blen, type);
  66        qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
  67        (*bpp)[-1] = '\n';
  68}
  69
  70static struct svc_expkey *svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
  71                                            struct svc_expkey *old);
  72static struct svc_expkey *svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *);
  73
  74static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
  75{
  76        /* client fsidtype fsid [path] */
  77        char *buf;
  78        int len;
  79        struct auth_domain *dom = NULL;
  80        int err;
  81        int fsidtype;
  82        char *ep;
  83        struct svc_expkey key;
  84        struct svc_expkey *ek = NULL;
  85
  86        if (mesg[mlen - 1] != '\n')
  87                return -EINVAL;
  88        mesg[mlen-1] = 0;
  89
  90        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  91        err = -ENOMEM;
  92        if (!buf)
  93                goto out;
  94
  95        err = -EINVAL;
  96        if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
  97                goto out;
  98
  99        err = -ENOENT;
 100        dom = auth_domain_find(buf);
 101        if (!dom)
 102                goto out;
 103        dprintk("found domain %s\n", buf);
 104
 105        err = -EINVAL;
 106        if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 107                goto out;
 108        fsidtype = simple_strtoul(buf, &ep, 10);
 109        if (*ep)
 110                goto out;
 111        dprintk("found fsidtype %d\n", fsidtype);
 112        if (key_len(fsidtype)==0) /* invalid type */
 113                goto out;
 114        if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 115                goto out;
 116        dprintk("found fsid length %d\n", len);
 117        if (len != key_len(fsidtype))
 118                goto out;
 119
 120        /* OK, we seem to have a valid key */
 121        key.h.flags = 0;
 122        key.h.expiry_time = get_expiry(&mesg);
 123        if (key.h.expiry_time == 0)
 124                goto out;
 125
 126        key.ek_client = dom;    
 127        key.ek_fsidtype = fsidtype;
 128        memcpy(key.ek_fsid, buf, len);
 129
 130        ek = svc_expkey_lookup(cd, &key);
 131        err = -ENOMEM;
 132        if (!ek)
 133                goto out;
 134
 135        /* now we want a pathname, or empty meaning NEGATIVE  */
 136        err = -EINVAL;
 137        len = qword_get(&mesg, buf, PAGE_SIZE);
 138        if (len < 0)
 139                goto out;
 140        dprintk("Path seems to be <%s>\n", buf);
 141        err = 0;
 142        if (len == 0) {
 143                set_bit(CACHE_NEGATIVE, &key.h.flags);
 144                ek = svc_expkey_update(cd, &key, ek);
 145                if (!ek)
 146                        err = -ENOMEM;
 147        } else {
 148                err = kern_path(buf, 0, &key.ek_path);
 149                if (err)
 150                        goto out;
 151
 152                dprintk("Found the path %s\n", buf);
 153
 154                ek = svc_expkey_update(cd, &key, ek);
 155                if (!ek)
 156                        err = -ENOMEM;
 157                path_put(&key.ek_path);
 158        }
 159        cache_flush();
 160 out:
 161        if (ek)
 162                cache_put(&ek->h, cd);
 163        if (dom)
 164                auth_domain_put(dom);
 165        kfree(buf);
 166        return err;
 167}
 168
 169static int expkey_show(struct seq_file *m,
 170                       struct cache_detail *cd,
 171                       struct cache_head *h)
 172{
 173        struct svc_expkey *ek ;
 174        int i;
 175
 176        if (h ==NULL) {
 177                seq_puts(m, "#domain fsidtype fsid [path]\n");
 178                return 0;
 179        }
 180        ek = container_of(h, struct svc_expkey, h);
 181        seq_printf(m, "%s %d 0x", ek->ek_client->name,
 182                   ek->ek_fsidtype);
 183        for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
 184                seq_printf(m, "%08x", ek->ek_fsid[i]);
 185        if (test_bit(CACHE_VALID, &h->flags) && 
 186            !test_bit(CACHE_NEGATIVE, &h->flags)) {
 187                seq_printf(m, " ");
 188                seq_path(m, &ek->ek_path, "\\ \t\n");
 189        }
 190        seq_printf(m, "\n");
 191        return 0;
 192}
 193
 194static inline int expkey_match (struct cache_head *a, struct cache_head *b)
 195{
 196        struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
 197        struct svc_expkey *new = container_of(b, struct svc_expkey, h);
 198
 199        if (orig->ek_fsidtype != new->ek_fsidtype ||
 200            orig->ek_client != new->ek_client ||
 201            memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
 202                return 0;
 203        return 1;
 204}
 205
 206static inline void expkey_init(struct cache_head *cnew,
 207                                   struct cache_head *citem)
 208{
 209        struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
 210        struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
 211
 212        kref_get(&item->ek_client->ref);
 213        new->ek_client = item->ek_client;
 214        new->ek_fsidtype = item->ek_fsidtype;
 215
 216        memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
 217}
 218
 219static inline void expkey_update(struct cache_head *cnew,
 220                                   struct cache_head *citem)
 221{
 222        struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
 223        struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
 224
 225        new->ek_path = item->ek_path;
 226        path_get(&item->ek_path);
 227}
 228
 229static struct cache_head *expkey_alloc(void)
 230{
 231        struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
 232        if (i)
 233                return &i->h;
 234        else
 235                return NULL;
 236}
 237
 238static struct cache_detail svc_expkey_cache_template = {
 239        .owner          = THIS_MODULE,
 240        .hash_size      = EXPKEY_HASHMAX,
 241        .name           = "nfsd.fh",
 242        .cache_put      = expkey_put,
 243        .cache_request  = expkey_request,
 244        .cache_parse    = expkey_parse,
 245        .cache_show     = expkey_show,
 246        .match          = expkey_match,
 247        .init           = expkey_init,
 248        .update         = expkey_update,
 249        .alloc          = expkey_alloc,
 250};
 251
 252static int
 253svc_expkey_hash(struct svc_expkey *item)
 254{
 255        int hash = item->ek_fsidtype;
 256        char * cp = (char*)item->ek_fsid;
 257        int len = key_len(item->ek_fsidtype);
 258
 259        hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
 260        hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
 261        hash &= EXPKEY_HASHMASK;
 262        return hash;
 263}
 264
 265static struct svc_expkey *
 266svc_expkey_lookup(struct cache_detail *cd, struct svc_expkey *item)
 267{
 268        struct cache_head *ch;
 269        int hash = svc_expkey_hash(item);
 270
 271        ch = sunrpc_cache_lookup(cd, &item->h, hash);
 272        if (ch)
 273                return container_of(ch, struct svc_expkey, h);
 274        else
 275                return NULL;
 276}
 277
 278static struct svc_expkey *
 279svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
 280                  struct svc_expkey *old)
 281{
 282        struct cache_head *ch;
 283        int hash = svc_expkey_hash(new);
 284
 285        ch = sunrpc_cache_update(cd, &new->h, &old->h, hash);
 286        if (ch)
 287                return container_of(ch, struct svc_expkey, h);
 288        else
 289                return NULL;
 290}
 291
 292
 293#define EXPORT_HASHBITS         8
 294#define EXPORT_HASHMAX          (1<< EXPORT_HASHBITS)
 295
 296static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
 297{
 298        int i;
 299
 300        for (i = 0; i < fsloc->locations_count; i++) {
 301                kfree(fsloc->locations[i].path);
 302                kfree(fsloc->locations[i].hosts);
 303        }
 304        kfree(fsloc->locations);
 305}
 306
 307static void svc_export_put(struct kref *ref)
 308{
 309        struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
 310        path_put(&exp->ex_path);
 311        auth_domain_put(exp->ex_client);
 312        nfsd4_fslocs_free(&exp->ex_fslocs);
 313        kfree(exp->ex_uuid);
 314        kfree(exp);
 315}
 316
 317static void svc_export_request(struct cache_detail *cd,
 318                               struct cache_head *h,
 319                               char **bpp, int *blen)
 320{
 321        /*  client path */
 322        struct svc_export *exp = container_of(h, struct svc_export, h);
 323        char *pth;
 324
 325        qword_add(bpp, blen, exp->ex_client->name);
 326        pth = d_path(&exp->ex_path, *bpp, *blen);
 327        if (IS_ERR(pth)) {
 328                /* is this correct? */
 329                (*bpp)[0] = '\n';
 330                return;
 331        }
 332        qword_add(bpp, blen, pth);
 333        (*bpp)[-1] = '\n';
 334}
 335
 336static struct svc_export *svc_export_update(struct svc_export *new,
 337                                            struct svc_export *old);
 338static struct svc_export *svc_export_lookup(struct svc_export *);
 339
 340static int check_export(struct inode *inode, int *flags, unsigned char *uuid)
 341{
 342
 343        /*
 344         * We currently export only dirs, regular files, and (for v4
 345         * pseudoroot) symlinks.
 346         */
 347        if (!S_ISDIR(inode->i_mode) &&
 348            !S_ISLNK(inode->i_mode) &&
 349            !S_ISREG(inode->i_mode))
 350                return -ENOTDIR;
 351
 352        /*
 353         * Mountd should never pass down a writeable V4ROOT export, but,
 354         * just to make sure:
 355         */
 356        if (*flags & NFSEXP_V4ROOT)
 357                *flags |= NFSEXP_READONLY;
 358
 359        /* There are two requirements on a filesystem to be exportable.
 360         * 1:  We must be able to identify the filesystem from a number.
 361         *       either a device number (so FS_REQUIRES_DEV needed)
 362         *       or an FSID number (so NFSEXP_FSID or ->uuid is needed).
 363         * 2:  We must be able to find an inode from a filehandle.
 364         *       This means that s_export_op must be set.
 365         */
 366        if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
 367            !(*flags & NFSEXP_FSID) &&
 368            uuid == NULL) {
 369                dprintk("exp_export: export of non-dev fs without fsid\n");
 370                return -EINVAL;
 371        }
 372
 373        if (!inode->i_sb->s_export_op ||
 374            !inode->i_sb->s_export_op->fh_to_dentry) {
 375                dprintk("exp_export: export of invalid fs type.\n");
 376                return -EINVAL;
 377        }
 378
 379        return 0;
 380
 381}
 382
 383#ifdef CONFIG_NFSD_V4
 384
 385static int
 386fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
 387{
 388        int len;
 389        int migrated, i, err;
 390
 391        /* listsize */
 392        err = get_uint(mesg, &fsloc->locations_count);
 393        if (err)
 394                return err;
 395        if (fsloc->locations_count > MAX_FS_LOCATIONS)
 396                return -EINVAL;
 397        if (fsloc->locations_count == 0)
 398                return 0;
 399
 400        fsloc->locations = kzalloc(fsloc->locations_count
 401                        * sizeof(struct nfsd4_fs_location), GFP_KERNEL);
 402        if (!fsloc->locations)
 403                return -ENOMEM;
 404        for (i=0; i < fsloc->locations_count; i++) {
 405                /* colon separated host list */
 406                err = -EINVAL;
 407                len = qword_get(mesg, buf, PAGE_SIZE);
 408                if (len <= 0)
 409                        goto out_free_all;
 410                err = -ENOMEM;
 411                fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
 412                if (!fsloc->locations[i].hosts)
 413                        goto out_free_all;
 414                err = -EINVAL;
 415                /* slash separated path component list */
 416                len = qword_get(mesg, buf, PAGE_SIZE);
 417                if (len <= 0)
 418                        goto out_free_all;
 419                err = -ENOMEM;
 420                fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
 421                if (!fsloc->locations[i].path)
 422                        goto out_free_all;
 423        }
 424        /* migrated */
 425        err = get_int(mesg, &migrated);
 426        if (err)
 427                goto out_free_all;
 428        err = -EINVAL;
 429        if (migrated < 0 || migrated > 1)
 430                goto out_free_all;
 431        fsloc->migrated = migrated;
 432        return 0;
 433out_free_all:
 434        nfsd4_fslocs_free(fsloc);
 435        return err;
 436}
 437
 438static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
 439{
 440        int listsize, err;
 441        struct exp_flavor_info *f;
 442
 443        err = get_int(mesg, &listsize);
 444        if (err)
 445                return err;
 446        if (listsize < 0 || listsize > MAX_SECINFO_LIST)
 447                return -EINVAL;
 448
 449        for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
 450                err = get_uint(mesg, &f->pseudoflavor);
 451                if (err)
 452                        return err;
 453                /*
 454                 * XXX: It would be nice to also check whether this
 455                 * pseudoflavor is supported, so we can discover the
 456                 * problem at export time instead of when a client fails
 457                 * to authenticate.
 458                 */
 459                err = get_uint(mesg, &f->flags);
 460                if (err)
 461                        return err;
 462                /* Only some flags are allowed to differ between flavors: */
 463                if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
 464                        return -EINVAL;
 465        }
 466        exp->ex_nflavors = listsize;
 467        return 0;
 468}
 469
 470#else /* CONFIG_NFSD_V4 */
 471static inline int
 472fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
 473static inline int
 474secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
 475#endif
 476
 477static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
 478{
 479        /* client path expiry [flags anonuid anongid fsid] */
 480        char *buf;
 481        int len;
 482        int err;
 483        struct auth_domain *dom = NULL;
 484        struct svc_export exp = {}, *expp;
 485        int an_int;
 486
 487        if (mesg[mlen-1] != '\n')
 488                return -EINVAL;
 489        mesg[mlen-1] = 0;
 490
 491        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 492        if (!buf)
 493                return -ENOMEM;
 494
 495        /* client */
 496        err = -EINVAL;
 497        len = qword_get(&mesg, buf, PAGE_SIZE);
 498        if (len <= 0)
 499                goto out;
 500
 501        err = -ENOENT;
 502        dom = auth_domain_find(buf);
 503        if (!dom)
 504                goto out;
 505
 506        /* path */
 507        err = -EINVAL;
 508        if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 509                goto out1;
 510
 511        err = kern_path(buf, 0, &exp.ex_path);
 512        if (err)
 513                goto out1;
 514
 515        exp.ex_client = dom;
 516        exp.cd = cd;
 517
 518        /* expiry */
 519        err = -EINVAL;
 520        exp.h.expiry_time = get_expiry(&mesg);
 521        if (exp.h.expiry_time == 0)
 522                goto out3;
 523
 524        /* flags */
 525        err = get_int(&mesg, &an_int);
 526        if (err == -ENOENT) {
 527                err = 0;
 528                set_bit(CACHE_NEGATIVE, &exp.h.flags);
 529        } else {
 530                if (err || an_int < 0)
 531                        goto out3;
 532                exp.ex_flags= an_int;
 533        
 534                /* anon uid */
 535                err = get_int(&mesg, &an_int);
 536                if (err)
 537                        goto out3;
 538                exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
 539                if (!uid_valid(exp.ex_anon_uid))
 540                        goto out3;
 541
 542                /* anon gid */
 543                err = get_int(&mesg, &an_int);
 544                if (err)
 545                        goto out3;
 546                exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
 547                if (!gid_valid(exp.ex_anon_gid))
 548                        goto out3;
 549
 550                /* fsid */
 551                err = get_int(&mesg, &an_int);
 552                if (err)
 553                        goto out3;
 554                exp.ex_fsid = an_int;
 555
 556                while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
 557                        if (strcmp(buf, "fsloc") == 0)
 558                                err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
 559                        else if (strcmp(buf, "uuid") == 0) {
 560                                /* expect a 16 byte uuid encoded as \xXXXX... */
 561                                len = qword_get(&mesg, buf, PAGE_SIZE);
 562                                if (len != 16)
 563                                        err  = -EINVAL;
 564                                else {
 565                                        exp.ex_uuid =
 566                                                kmemdup(buf, 16, GFP_KERNEL);
 567                                        if (exp.ex_uuid == NULL)
 568                                                err = -ENOMEM;
 569                                }
 570                        } else if (strcmp(buf, "secinfo") == 0)
 571                                err = secinfo_parse(&mesg, buf, &exp);
 572                        else
 573                                /* quietly ignore unknown words and anything
 574                                 * following. Newer user-space can try to set
 575                                 * new values, then see what the result was.
 576                                 */
 577                                break;
 578                        if (err)
 579                                goto out4;
 580                }
 581
 582                err = check_export(exp.ex_path.dentry->d_inode, &exp.ex_flags,
 583                                   exp.ex_uuid);
 584                if (err)
 585                        goto out4;
 586        }
 587
 588        expp = svc_export_lookup(&exp);
 589        if (expp)
 590                expp = svc_export_update(&exp, expp);
 591        else
 592                err = -ENOMEM;
 593        cache_flush();
 594        if (expp == NULL)
 595                err = -ENOMEM;
 596        else
 597                exp_put(expp);
 598out4:
 599        nfsd4_fslocs_free(&exp.ex_fslocs);
 600        kfree(exp.ex_uuid);
 601out3:
 602        path_put(&exp.ex_path);
 603out1:
 604        auth_domain_put(dom);
 605out:
 606        kfree(buf);
 607        return err;
 608}
 609
 610static void exp_flags(struct seq_file *m, int flag, int fsid,
 611                kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fslocs);
 612static void show_secinfo(struct seq_file *m, struct svc_export *exp);
 613
 614static int svc_export_show(struct seq_file *m,
 615                           struct cache_detail *cd,
 616                           struct cache_head *h)
 617{
 618        struct svc_export *exp ;
 619
 620        if (h ==NULL) {
 621                seq_puts(m, "#path domain(flags)\n");
 622                return 0;
 623        }
 624        exp = container_of(h, struct svc_export, h);
 625        seq_path(m, &exp->ex_path, " \t\n\\");
 626        seq_putc(m, '\t');
 627        seq_escape(m, exp->ex_client->name, " \t\n\\");
 628        seq_putc(m, '(');
 629        if (test_bit(CACHE_VALID, &h->flags) && 
 630            !test_bit(CACHE_NEGATIVE, &h->flags)) {
 631                exp_flags(m, exp->ex_flags, exp->ex_fsid,
 632                          exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
 633                if (exp->ex_uuid) {
 634                        int i;
 635                        seq_puts(m, ",uuid=");
 636                        for (i=0; i<16; i++) {
 637                                if ((i&3) == 0 && i)
 638                                        seq_putc(m, ':');
 639                                seq_printf(m, "%02x", exp->ex_uuid[i]);
 640                        }
 641                }
 642                show_secinfo(m, exp);
 643        }
 644        seq_puts(m, ")\n");
 645        return 0;
 646}
 647static int svc_export_match(struct cache_head *a, struct cache_head *b)
 648{
 649        struct svc_export *orig = container_of(a, struct svc_export, h);
 650        struct svc_export *new = container_of(b, struct svc_export, h);
 651        return orig->ex_client == new->ex_client &&
 652                orig->ex_path.dentry == new->ex_path.dentry &&
 653                orig->ex_path.mnt == new->ex_path.mnt;
 654}
 655
 656static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
 657{
 658        struct svc_export *new = container_of(cnew, struct svc_export, h);
 659        struct svc_export *item = container_of(citem, struct svc_export, h);
 660
 661        kref_get(&item->ex_client->ref);
 662        new->ex_client = item->ex_client;
 663        new->ex_path.dentry = dget(item->ex_path.dentry);
 664        new->ex_path.mnt = mntget(item->ex_path.mnt);
 665        new->ex_fslocs.locations = NULL;
 666        new->ex_fslocs.locations_count = 0;
 667        new->ex_fslocs.migrated = 0;
 668        new->ex_uuid = NULL;
 669        new->cd = item->cd;
 670}
 671
 672static void export_update(struct cache_head *cnew, struct cache_head *citem)
 673{
 674        struct svc_export *new = container_of(cnew, struct svc_export, h);
 675        struct svc_export *item = container_of(citem, struct svc_export, h);
 676        int i;
 677
 678        new->ex_flags = item->ex_flags;
 679        new->ex_anon_uid = item->ex_anon_uid;
 680        new->ex_anon_gid = item->ex_anon_gid;
 681        new->ex_fsid = item->ex_fsid;
 682        new->ex_uuid = item->ex_uuid;
 683        item->ex_uuid = NULL;
 684        new->ex_fslocs.locations = item->ex_fslocs.locations;
 685        item->ex_fslocs.locations = NULL;
 686        new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
 687        item->ex_fslocs.locations_count = 0;
 688        new->ex_fslocs.migrated = item->ex_fslocs.migrated;
 689        item->ex_fslocs.migrated = 0;
 690        new->ex_nflavors = item->ex_nflavors;
 691        for (i = 0; i < MAX_SECINFO_LIST; i++) {
 692                new->ex_flavors[i] = item->ex_flavors[i];
 693        }
 694}
 695
 696static struct cache_head *svc_export_alloc(void)
 697{
 698        struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
 699        if (i)
 700                return &i->h;
 701        else
 702                return NULL;
 703}
 704
 705static struct cache_detail svc_export_cache_template = {
 706        .owner          = THIS_MODULE,
 707        .hash_size      = EXPORT_HASHMAX,
 708        .name           = "nfsd.export",
 709        .cache_put      = svc_export_put,
 710        .cache_request  = svc_export_request,
 711        .cache_parse    = svc_export_parse,
 712        .cache_show     = svc_export_show,
 713        .match          = svc_export_match,
 714        .init           = svc_export_init,
 715        .update         = export_update,
 716        .alloc          = svc_export_alloc,
 717};
 718
 719static int
 720svc_export_hash(struct svc_export *exp)
 721{
 722        int hash;
 723
 724        hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
 725        hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
 726        hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
 727        return hash;
 728}
 729
 730static struct svc_export *
 731svc_export_lookup(struct svc_export *exp)
 732{
 733        struct cache_head *ch;
 734        int hash = svc_export_hash(exp);
 735
 736        ch = sunrpc_cache_lookup(exp->cd, &exp->h, hash);
 737        if (ch)
 738                return container_of(ch, struct svc_export, h);
 739        else
 740                return NULL;
 741}
 742
 743static struct svc_export *
 744svc_export_update(struct svc_export *new, struct svc_export *old)
 745{
 746        struct cache_head *ch;
 747        int hash = svc_export_hash(old);
 748
 749        ch = sunrpc_cache_update(old->cd, &new->h, &old->h, hash);
 750        if (ch)
 751                return container_of(ch, struct svc_export, h);
 752        else
 753                return NULL;
 754}
 755
 756
 757static struct svc_expkey *
 758exp_find_key(struct cache_detail *cd, svc_client *clp, int fsid_type,
 759             u32 *fsidv, struct cache_req *reqp)
 760{
 761        struct svc_expkey key, *ek;
 762        int err;
 763        
 764        if (!clp)
 765                return ERR_PTR(-ENOENT);
 766
 767        key.ek_client = clp;
 768        key.ek_fsidtype = fsid_type;
 769        memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
 770
 771        ek = svc_expkey_lookup(cd, &key);
 772        if (ek == NULL)
 773                return ERR_PTR(-ENOMEM);
 774        err = cache_check(cd, &ek->h, reqp);
 775        if (err)
 776                return ERR_PTR(err);
 777        return ek;
 778}
 779
 780
 781static svc_export *exp_get_by_name(struct cache_detail *cd, svc_client *clp,
 782                                   const struct path *path, struct cache_req *reqp)
 783{
 784        struct svc_export *exp, key;
 785        int err;
 786
 787        if (!clp)
 788                return ERR_PTR(-ENOENT);
 789
 790        key.ex_client = clp;
 791        key.ex_path = *path;
 792        key.cd = cd;
 793
 794        exp = svc_export_lookup(&key);
 795        if (exp == NULL)
 796                return ERR_PTR(-ENOMEM);
 797        err = cache_check(cd, &exp->h, reqp);
 798        if (err)
 799                return ERR_PTR(err);
 800        return exp;
 801}
 802
 803/*
 804 * Find the export entry for a given dentry.
 805 */
 806static struct svc_export *exp_parent(struct cache_detail *cd, svc_client *clp,
 807                                     struct path *path)
 808{
 809        struct dentry *saved = dget(path->dentry);
 810        svc_export *exp = exp_get_by_name(cd, clp, path, NULL);
 811
 812        while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
 813                struct dentry *parent = dget_parent(path->dentry);
 814                dput(path->dentry);
 815                path->dentry = parent;
 816                exp = exp_get_by_name(cd, clp, path, NULL);
 817        }
 818        dput(path->dentry);
 819        path->dentry = saved;
 820        return exp;
 821}
 822
 823
 824
 825/*
 826 * Obtain the root fh on behalf of a client.
 827 * This could be done in user space, but I feel that it adds some safety
 828 * since its harder to fool a kernel module than a user space program.
 829 */
 830int
 831exp_rootfh(struct net *net, svc_client *clp, char *name,
 832           struct knfsd_fh *f, int maxsize)
 833{
 834        struct svc_export       *exp;
 835        struct path             path;
 836        struct inode            *inode;
 837        struct svc_fh           fh;
 838        int                     err;
 839        struct nfsd_net         *nn = net_generic(net, nfsd_net_id);
 840        struct cache_detail     *cd = nn->svc_export_cache;
 841
 842        err = -EPERM;
 843        /* NB: we probably ought to check that it's NUL-terminated */
 844        if (kern_path(name, 0, &path)) {
 845                printk("nfsd: exp_rootfh path not found %s", name);
 846                return err;
 847        }
 848        inode = path.dentry->d_inode;
 849
 850        dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
 851                 name, path.dentry, clp->name,
 852                 inode->i_sb->s_id, inode->i_ino);
 853        exp = exp_parent(cd, clp, &path);
 854        if (IS_ERR(exp)) {
 855                err = PTR_ERR(exp);
 856                goto out;
 857        }
 858
 859        /*
 860         * fh must be initialized before calling fh_compose
 861         */
 862        fh_init(&fh, maxsize);
 863        if (fh_compose(&fh, exp, path.dentry, NULL))
 864                err = -EINVAL;
 865        else
 866                err = 0;
 867        memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
 868        fh_put(&fh);
 869        exp_put(exp);
 870out:
 871        path_put(&path);
 872        return err;
 873}
 874
 875static struct svc_export *exp_find(struct cache_detail *cd,
 876                                   struct auth_domain *clp, int fsid_type,
 877                                   u32 *fsidv, struct cache_req *reqp)
 878{
 879        struct svc_export *exp;
 880        struct nfsd_net *nn = net_generic(cd->net, nfsd_net_id);
 881        struct svc_expkey *ek = exp_find_key(nn->svc_expkey_cache, clp, fsid_type, fsidv, reqp);
 882        if (IS_ERR(ek))
 883                return ERR_CAST(ek);
 884
 885        exp = exp_get_by_name(cd, clp, &ek->ek_path, reqp);
 886        cache_put(&ek->h, nn->svc_expkey_cache);
 887
 888        if (IS_ERR(exp))
 889                return ERR_CAST(exp);
 890        return exp;
 891}
 892
 893__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
 894{
 895        struct exp_flavor_info *f;
 896        struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
 897
 898        /* legacy gss-only clients are always OK: */
 899        if (exp->ex_client == rqstp->rq_gssclient)
 900                return 0;
 901        /* ip-address based client; check sec= export option: */
 902        for (f = exp->ex_flavors; f < end; f++) {
 903                if (f->pseudoflavor == rqstp->rq_cred.cr_flavor)
 904                        return 0;
 905        }
 906        /* defaults in absence of sec= options: */
 907        if (exp->ex_nflavors == 0) {
 908                if (rqstp->rq_cred.cr_flavor == RPC_AUTH_NULL ||
 909                    rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)
 910                        return 0;
 911        }
 912        return nfserr_wrongsec;
 913}
 914
 915/*
 916 * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
 917 * auth_unix client) if it's available and has secinfo information;
 918 * otherwise, will try to use rq_gssclient.
 919 *
 920 * Called from functions that handle requests; functions that do work on
 921 * behalf of mountd are passed a single client name to use, and should
 922 * use exp_get_by_name() or exp_find().
 923 */
 924struct svc_export *
 925rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
 926{
 927        struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
 928        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 929        struct cache_detail *cd = nn->svc_export_cache;
 930
 931        if (rqstp->rq_client == NULL)
 932                goto gss;
 933
 934        /* First try the auth_unix client: */
 935        exp = exp_get_by_name(cd, rqstp->rq_client, path, &rqstp->rq_chandle);
 936        if (PTR_ERR(exp) == -ENOENT)
 937                goto gss;
 938        if (IS_ERR(exp))
 939                return exp;
 940        /* If it has secinfo, assume there are no gss/... clients */
 941        if (exp->ex_nflavors > 0)
 942                return exp;
 943gss:
 944        /* Otherwise, try falling back on gss client */
 945        if (rqstp->rq_gssclient == NULL)
 946                return exp;
 947        gssexp = exp_get_by_name(cd, rqstp->rq_gssclient, path, &rqstp->rq_chandle);
 948        if (PTR_ERR(gssexp) == -ENOENT)
 949                return exp;
 950        if (!IS_ERR(exp))
 951                exp_put(exp);
 952        return gssexp;
 953}
 954
 955struct svc_export *
 956rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
 957{
 958        struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
 959        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 960        struct cache_detail *cd = nn->svc_export_cache;
 961
 962        if (rqstp->rq_client == NULL)
 963                goto gss;
 964
 965        /* First try the auth_unix client: */
 966        exp = exp_find(cd, rqstp->rq_client, fsid_type,
 967                       fsidv, &rqstp->rq_chandle);
 968        if (PTR_ERR(exp) == -ENOENT)
 969                goto gss;
 970        if (IS_ERR(exp))
 971                return exp;
 972        /* If it has secinfo, assume there are no gss/... clients */
 973        if (exp->ex_nflavors > 0)
 974                return exp;
 975gss:
 976        /* Otherwise, try falling back on gss client */
 977        if (rqstp->rq_gssclient == NULL)
 978                return exp;
 979        gssexp = exp_find(cd, rqstp->rq_gssclient, fsid_type, fsidv,
 980                                                &rqstp->rq_chandle);
 981        if (PTR_ERR(gssexp) == -ENOENT)
 982                return exp;
 983        if (!IS_ERR(exp))
 984                exp_put(exp);
 985        return gssexp;
 986}
 987
 988struct svc_export *
 989rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
 990{
 991        struct dentry *saved = dget(path->dentry);
 992        struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
 993
 994        while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
 995                struct dentry *parent = dget_parent(path->dentry);
 996                dput(path->dentry);
 997                path->dentry = parent;
 998                exp = rqst_exp_get_by_name(rqstp, path);
 999        }
1000        dput(path->dentry);
1001        path->dentry = saved;
1002        return exp;
1003}
1004
1005struct svc_export *rqst_find_fsidzero_export(struct svc_rqst *rqstp)
1006{
1007        u32 fsidv[2];
1008
1009        mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1010
1011        return rqst_exp_find(rqstp, FSID_NUM, fsidv);
1012}
1013
1014/*
1015 * Called when we need the filehandle for the root of the pseudofs,
1016 * for a given NFSv4 client.   The root is defined to be the
1017 * export point with fsid==0
1018 */
1019__be32
1020exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1021{
1022        struct svc_export *exp;
1023        __be32 rv;
1024
1025        exp = rqst_find_fsidzero_export(rqstp);
1026        if (IS_ERR(exp))
1027                return nfserrno(PTR_ERR(exp));
1028        rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
1029        exp_put(exp);
1030        return rv;
1031}
1032
1033/* Iterator */
1034
1035static void *e_start(struct seq_file *m, loff_t *pos)
1036        __acquires(((struct cache_detail *)m->private)->hash_lock)
1037{
1038        loff_t n = *pos;
1039        unsigned hash, export;
1040        struct cache_head *ch;
1041        struct cache_detail *cd = m->private;
1042        struct cache_head **export_table = cd->hash_table;
1043
1044        read_lock(&cd->hash_lock);
1045        if (!n--)
1046                return SEQ_START_TOKEN;
1047        hash = n >> 32;
1048        export = n & ((1LL<<32) - 1);
1049
1050        
1051        for (ch=export_table[hash]; ch; ch=ch->next)
1052                if (!export--)
1053                        return ch;
1054        n &= ~((1LL<<32) - 1);
1055        do {
1056                hash++;
1057                n += 1LL<<32;
1058        } while(hash < EXPORT_HASHMAX && export_table[hash]==NULL);
1059        if (hash >= EXPORT_HASHMAX)
1060                return NULL;
1061        *pos = n+1;
1062        return export_table[hash];
1063}
1064
1065static void *e_next(struct seq_file *m, void *p, loff_t *pos)
1066{
1067        struct cache_head *ch = p;
1068        int hash = (*pos >> 32);
1069        struct cache_detail *cd = m->private;
1070        struct cache_head **export_table = cd->hash_table;
1071
1072        if (p == SEQ_START_TOKEN)
1073                hash = 0;
1074        else if (ch->next == NULL) {
1075                hash++;
1076                *pos += 1LL<<32;
1077        } else {
1078                ++*pos;
1079                return ch->next;
1080        }
1081        *pos &= ~((1LL<<32) - 1);
1082        while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) {
1083                hash++;
1084                *pos += 1LL<<32;
1085        }
1086        if (hash >= EXPORT_HASHMAX)
1087                return NULL;
1088        ++*pos;
1089        return export_table[hash];
1090}
1091
1092static void e_stop(struct seq_file *m, void *p)
1093        __releases(((struct cache_detail *)m->private)->hash_lock)
1094{
1095        struct cache_detail *cd = m->private;
1096
1097        read_unlock(&cd->hash_lock);
1098}
1099
1100static struct flags {
1101        int flag;
1102        char *name[2];
1103} expflags[] = {
1104        { NFSEXP_READONLY, {"ro", "rw"}},
1105        { NFSEXP_INSECURE_PORT, {"insecure", ""}},
1106        { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
1107        { NFSEXP_ALLSQUASH, {"all_squash", ""}},
1108        { NFSEXP_ASYNC, {"async", "sync"}},
1109        { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
1110        { NFSEXP_NOHIDE, {"nohide", ""}},
1111        { NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
1112        { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
1113        { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
1114        { NFSEXP_V4ROOT, {"v4root", ""}},
1115        { 0, {"", ""}}
1116};
1117
1118static void show_expflags(struct seq_file *m, int flags, int mask)
1119{
1120        struct flags *flg;
1121        int state, first = 0;
1122
1123        for (flg = expflags; flg->flag; flg++) {
1124                if (flg->flag & ~mask)
1125                        continue;
1126                state = (flg->flag & flags) ? 0 : 1;
1127                if (*flg->name[state])
1128                        seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
1129        }
1130}
1131
1132static void show_secinfo_flags(struct seq_file *m, int flags)
1133{
1134        seq_printf(m, ",");
1135        show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
1136}
1137
1138static bool secinfo_flags_equal(int f, int g)
1139{
1140        f &= NFSEXP_SECINFO_FLAGS;
1141        g &= NFSEXP_SECINFO_FLAGS;
1142        return f == g;
1143}
1144
1145static int show_secinfo_run(struct seq_file *m, struct exp_flavor_info **fp, struct exp_flavor_info *end)
1146{
1147        int flags;
1148
1149        flags = (*fp)->flags;
1150        seq_printf(m, ",sec=%d", (*fp)->pseudoflavor);
1151        (*fp)++;
1152        while (*fp != end && secinfo_flags_equal(flags, (*fp)->flags)) {
1153                seq_printf(m, ":%d", (*fp)->pseudoflavor);
1154                (*fp)++;
1155        }
1156        return flags;
1157}
1158
1159static void show_secinfo(struct seq_file *m, struct svc_export *exp)
1160{
1161        struct exp_flavor_info *f;
1162        struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1163        int flags;
1164
1165        if (exp->ex_nflavors == 0)
1166                return;
1167        f = exp->ex_flavors;
1168        flags = show_secinfo_run(m, &f, end);
1169        if (!secinfo_flags_equal(flags, exp->ex_flags))
1170                show_secinfo_flags(m, flags);
1171        while (f != end) {
1172                flags = show_secinfo_run(m, &f, end);
1173                show_secinfo_flags(m, flags);
1174        }
1175}
1176
1177static void exp_flags(struct seq_file *m, int flag, int fsid,
1178                kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fsloc)
1179{
1180        show_expflags(m, flag, NFSEXP_ALLFLAGS);
1181        if (flag & NFSEXP_FSID)
1182                seq_printf(m, ",fsid=%d", fsid);
1183        if (!uid_eq(anonu, make_kuid(&init_user_ns, (uid_t)-2)) &&
1184            !uid_eq(anonu, make_kuid(&init_user_ns, 0x10000-2)))
1185                seq_printf(m, ",anonuid=%u", from_kuid(&init_user_ns, anonu));
1186        if (!gid_eq(anong, make_kgid(&init_user_ns, (gid_t)-2)) &&
1187            !gid_eq(anong, make_kgid(&init_user_ns, 0x10000-2)))
1188                seq_printf(m, ",anongid=%u", from_kgid(&init_user_ns, anong));
1189        if (fsloc && fsloc->locations_count > 0) {
1190                char *loctype = (fsloc->migrated) ? "refer" : "replicas";
1191                int i;
1192
1193                seq_printf(m, ",%s=", loctype);
1194                seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
1195                seq_putc(m, '@');
1196                seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
1197                for (i = 1; i < fsloc->locations_count; i++) {
1198                        seq_putc(m, ';');
1199                        seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
1200                        seq_putc(m, '@');
1201                        seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
1202                }
1203        }
1204}
1205
1206static int e_show(struct seq_file *m, void *p)
1207{
1208        struct cache_head *cp = p;
1209        struct svc_export *exp = container_of(cp, struct svc_export, h);
1210        struct cache_detail *cd = m->private;
1211
1212        if (p == SEQ_START_TOKEN) {
1213                seq_puts(m, "# Version 1.1\n");
1214                seq_puts(m, "# Path Client(Flags) # IPs\n");
1215                return 0;
1216        }
1217
1218        cache_get(&exp->h);
1219        if (cache_check(cd, &exp->h, NULL))
1220                return 0;
1221        exp_put(exp);
1222        return svc_export_show(m, cd, cp);
1223}
1224
1225const struct seq_operations nfs_exports_op = {
1226        .start  = e_start,
1227        .next   = e_next,
1228        .stop   = e_stop,
1229        .show   = e_show,
1230};
1231
1232/*
1233 * Initialize the exports module.
1234 */
1235int
1236nfsd_export_init(struct net *net)
1237{
1238        int rv;
1239        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1240
1241        dprintk("nfsd: initializing export module (net: %p).\n", net);
1242
1243        nn->svc_export_cache = cache_create_net(&svc_export_cache_template, net);
1244        if (IS_ERR(nn->svc_export_cache))
1245                return PTR_ERR(nn->svc_export_cache);
1246        rv = cache_register_net(nn->svc_export_cache, net);
1247        if (rv)
1248                goto destroy_export_cache;
1249
1250        nn->svc_expkey_cache = cache_create_net(&svc_expkey_cache_template, net);
1251        if (IS_ERR(nn->svc_expkey_cache)) {
1252                rv = PTR_ERR(nn->svc_expkey_cache);
1253                goto unregister_export_cache;
1254        }
1255        rv = cache_register_net(nn->svc_expkey_cache, net);
1256        if (rv)
1257                goto destroy_expkey_cache;
1258        return 0;
1259
1260destroy_expkey_cache:
1261        cache_destroy_net(nn->svc_expkey_cache, net);
1262unregister_export_cache:
1263        cache_unregister_net(nn->svc_export_cache, net);
1264destroy_export_cache:
1265        cache_destroy_net(nn->svc_export_cache, net);
1266        return rv;
1267}
1268
1269/*
1270 * Flush exports table - called when last nfsd thread is killed
1271 */
1272void
1273nfsd_export_flush(struct net *net)
1274{
1275        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1276
1277        cache_purge(nn->svc_expkey_cache);
1278        cache_purge(nn->svc_export_cache);
1279}
1280
1281/*
1282 * Shutdown the exports module.
1283 */
1284void
1285nfsd_export_shutdown(struct net *net)
1286{
1287        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
1288
1289        dprintk("nfsd: shutting down export module (net: %p).\n", net);
1290
1291        cache_unregister_net(nn->svc_expkey_cache, net);
1292        cache_unregister_net(nn->svc_export_cache, net);
1293        cache_destroy_net(nn->svc_expkey_cache, net);
1294        cache_destroy_net(nn->svc_export_cache, net);
1295        svcauth_unix_purge(net);
1296
1297        dprintk("nfsd: export shutdown complete (net: %p).\n", net);
1298}
1299
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.