linux/fs/nfs/nfs4namespace.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * linux/fs/nfs/nfs4namespace.c
   4 *
   5 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
   6 * - Modified by David Howells <dhowells@redhat.com>
   7 *
   8 * NFSv4 namespace
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/dcache.h>
  13#include <linux/mount.h>
  14#include <linux/namei.h>
  15#include <linux/nfs_fs.h>
  16#include <linux/nfs_mount.h>
  17#include <linux/slab.h>
  18#include <linux/string.h>
  19#include <linux/sunrpc/clnt.h>
  20#include <linux/sunrpc/addr.h>
  21#include <linux/vfs.h>
  22#include <linux/inet.h>
  23#include "internal.h"
  24#include "nfs4_fs.h"
  25#include "nfs.h"
  26#include "dns_resolve.h"
  27
  28#define NFSDBG_FACILITY         NFSDBG_VFS
  29
  30/*
  31 * Work out the length that an NFSv4 path would render to as a standard posix
  32 * path, with a leading slash but no terminating slash.
  33 */
  34static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname)
  35{
  36        ssize_t len = 0;
  37        int i;
  38
  39        for (i = 0; i < pathname->ncomponents; i++) {
  40                const struct nfs4_string *component = &pathname->components[i];
  41
  42                if (component->len > NAME_MAX)
  43                        goto too_long;
  44                len += 1 + component->len; /* Adding "/foo" */
  45                if (len > PATH_MAX)
  46                        goto too_long;
  47        }
  48        return len;
  49
  50too_long:
  51        return -ENAMETOOLONG;
  52}
  53
  54/*
  55 * Convert the NFSv4 pathname components into a standard posix path.
  56 */
  57static char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
  58                                  unsigned short *_len)
  59{
  60        ssize_t len;
  61        char *buf, *p;
  62        int i;
  63
  64        len = nfs4_pathname_len(pathname);
  65        if (len < 0)
  66                return ERR_PTR(len);
  67        *_len = len;
  68
  69        p = buf = kmalloc(len + 1, GFP_KERNEL);
  70        if (!buf)
  71                return ERR_PTR(-ENOMEM);
  72
  73        for (i = 0; i < pathname->ncomponents; i++) {
  74                const struct nfs4_string *component = &pathname->components[i];
  75
  76                *p++ = '/';
  77                memcpy(p, component->data, component->len);
  78                p += component->len;
  79        }
  80
  81        *p = 0;
  82        return buf;
  83}
  84
  85/*
  86 * return the path component of "<server>:<path>"
  87 *  nfspath - the "<server>:<path>" string
  88 *  end - one past the last char that could contain "<server>:"
  89 * returns NULL on failure
  90 */
  91static char *nfs_path_component(const char *nfspath, const char *end)
  92{
  93        char *p;
  94
  95        if (*nfspath == '[') {
  96                /* parse [] escaped IPv6 addrs */
  97                p = strchr(nfspath, ']');
  98                if (p != NULL && ++p < end && *p == ':')
  99                        return p + 1;
 100        } else {
 101                /* otherwise split on first colon */
 102                p = strchr(nfspath, ':');
 103                if (p != NULL && p < end)
 104                        return p + 1;
 105        }
 106        return NULL;
 107}
 108
 109/*
 110 * Determine the mount path as a string
 111 */
 112static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
 113{
 114        char *limit;
 115        char *path = nfs_path(&limit, dentry, buffer, buflen,
 116                              NFS_PATH_CANONICAL);
 117        if (!IS_ERR(path)) {
 118                char *path_component = nfs_path_component(path, limit);
 119                if (path_component)
 120                        return path_component;
 121        }
 122        return path;
 123}
 124
 125/*
 126 * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
 127 * believe to be the server path to this dentry
 128 */
 129static int nfs4_validate_fspath(struct dentry *dentry,
 130                                const struct nfs4_fs_locations *locations,
 131                                struct nfs_fs_context *ctx)
 132{
 133        const char *path;
 134        char *fs_path;
 135        unsigned short len;
 136        char *buf;
 137        int n;
 138
 139        buf = kmalloc(4096, GFP_KERNEL);
 140        path = nfs4_path(dentry, buf, 4096);
 141        if (IS_ERR(path)) {
 142                kfree(buf);
 143                return PTR_ERR(path);
 144        }
 145
 146        fs_path = nfs4_pathname_string(&locations->fs_path, &len);
 147        if (IS_ERR(fs_path)) {
 148                kfree(buf);
 149                return PTR_ERR(fs_path);
 150        }
 151
 152        n = strncmp(path, fs_path, len);
 153        kfree(buf);
 154        kfree(fs_path);
 155        if (n != 0) {
 156                dprintk("%s: path %s does not begin with fsroot %s\n",
 157                        __func__, path, ctx->nfs_server.export_path);
 158                return -ENOENT;
 159        }
 160
 161        return 0;
 162}
 163
 164static size_t nfs_parse_server_name(char *string, size_t len,
 165                struct sockaddr *sa, size_t salen, struct net *net)
 166{
 167        ssize_t ret;
 168
 169        ret = rpc_pton(net, string, len, sa, salen);
 170        if (ret == 0) {
 171                ret = nfs_dns_resolve_name(net, string, len, sa, salen);
 172                if (ret < 0)
 173                        ret = 0;
 174        }
 175        return ret;
 176}
 177
 178/**
 179 * nfs_find_best_sec - Find a security mechanism supported locally
 180 * @clnt: pointer to rpc_clnt
 181 * @server: NFS server struct
 182 * @flavors: List of security tuples returned by SECINFO procedure
 183 *
 184 * Return an rpc client that uses the first security mechanism in
 185 * "flavors" that is locally supported.  The "flavors" array
 186 * is searched in the order returned from the server, per RFC 3530
 187 * recommendation and each flavor is checked for membership in the
 188 * sec= mount option list if it exists.
 189 *
 190 * Return -EPERM if no matching flavor is found in the array.
 191 *
 192 * Please call rpc_shutdown_client() when you are done with this rpc client.
 193 *
 194 */
 195static struct rpc_clnt *nfs_find_best_sec(struct rpc_clnt *clnt,
 196                                          struct nfs_server *server,
 197                                          struct nfs4_secinfo_flavors *flavors)
 198{
 199        rpc_authflavor_t pflavor;
 200        struct nfs4_secinfo4 *secinfo;
 201        unsigned int i;
 202
 203        for (i = 0; i < flavors->num_flavors; i++) {
 204                secinfo = &flavors->flavors[i];
 205
 206                switch (secinfo->flavor) {
 207                case RPC_AUTH_NULL:
 208                case RPC_AUTH_UNIX:
 209                case RPC_AUTH_GSS:
 210                        pflavor = rpcauth_get_pseudoflavor(secinfo->flavor,
 211                                                        &secinfo->flavor_info);
 212                        /* does the pseudoflavor match a sec= mount opt? */
 213                        if (pflavor != RPC_AUTH_MAXFLAVOR &&
 214                            nfs_auth_info_match(&server->auth_info, pflavor)) {
 215                                struct rpc_clnt *new;
 216                                struct rpc_cred *cred;
 217
 218                                /* Cloning creates an rpc_auth for the flavor */
 219                                new = rpc_clone_client_set_auth(clnt, pflavor);
 220                                if (IS_ERR(new))
 221                                        continue;
 222                                /**
 223                                * Check that the user actually can use the
 224                                * flavor. This is mostly for RPC_AUTH_GSS
 225                                * where cr_init obtains a gss context
 226                                */
 227                                cred = rpcauth_lookupcred(new->cl_auth, 0);
 228                                if (IS_ERR(cred)) {
 229                                        rpc_shutdown_client(new);
 230                                        continue;
 231                                }
 232                                put_rpccred(cred);
 233                                return new;
 234                        }
 235                }
 236        }
 237        return ERR_PTR(-EPERM);
 238}
 239
 240/**
 241 * nfs4_negotiate_security - in response to an NFS4ERR_WRONGSEC on lookup,
 242 * return an rpc_clnt that uses the best available security flavor with
 243 * respect to the secinfo flavor list and the sec= mount options.
 244 *
 245 * @clnt: RPC client to clone
 246 * @inode: directory inode
 247 * @name: lookup name
 248 *
 249 * Please call rpc_shutdown_client() when you are done with this rpc client.
 250 */
 251struct rpc_clnt *
 252nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode,
 253                                        const struct qstr *name)
 254{
 255        struct page *page;
 256        struct nfs4_secinfo_flavors *flavors;
 257        struct rpc_clnt *new;
 258        int err;
 259
 260        page = alloc_page(GFP_KERNEL);
 261        if (!page)
 262                return ERR_PTR(-ENOMEM);
 263
 264        flavors = page_address(page);
 265
 266        err = nfs4_proc_secinfo(inode, name, flavors);
 267        if (err < 0) {
 268                new = ERR_PTR(err);
 269                goto out;
 270        }
 271
 272        new = nfs_find_best_sec(clnt, NFS_SERVER(inode), flavors);
 273
 274out:
 275        put_page(page);
 276        return new;
 277}
 278
 279static int try_location(struct fs_context *fc,
 280                        const struct nfs4_fs_location *location)
 281{
 282        struct nfs_fs_context *ctx = nfs_fc2context(fc);
 283        unsigned int len, s;
 284        char *export_path, *source, *p;
 285        int ret = -ENOENT;
 286
 287        /* Allocate a buffer big enough to hold any of the hostnames plus a
 288         * terminating char and also a buffer big enough to hold the hostname
 289         * plus a colon plus the path.
 290         */
 291        len = 0;
 292        for (s = 0; s < location->nservers; s++) {
 293                const struct nfs4_string *buf = &location->servers[s];
 294                if (buf->len > len)
 295                        len = buf->len;
 296        }
 297
 298        kfree(ctx->nfs_server.hostname);
 299        ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL);
 300        if (!ctx->nfs_server.hostname)
 301                return -ENOMEM;
 302
 303        export_path = nfs4_pathname_string(&location->rootpath,
 304                                           &ctx->nfs_server.export_path_len);
 305        if (IS_ERR(export_path))
 306                return PTR_ERR(export_path);
 307
 308        kfree(ctx->nfs_server.export_path);
 309        ctx->nfs_server.export_path = export_path;
 310
 311        source = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1,
 312                         GFP_KERNEL);
 313        if (!source)
 314                return -ENOMEM;
 315
 316        kfree(fc->source);
 317        fc->source = source;
 318        for (s = 0; s < location->nservers; s++) {
 319                const struct nfs4_string *buf = &location->servers[s];
 320
 321                if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
 322                        continue;
 323
 324                ctx->nfs_server.addrlen =
 325                        nfs_parse_server_name(buf->data, buf->len,
 326                                              &ctx->nfs_server.address,
 327                                              sizeof(ctx->nfs_server._address),
 328                                              fc->net_ns);
 329                if (ctx->nfs_server.addrlen == 0)
 330                        continue;
 331
 332                rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
 333
 334                memcpy(ctx->nfs_server.hostname, buf->data, buf->len);
 335                ctx->nfs_server.hostname[buf->len] = '\0';
 336
 337                p = source;
 338                memcpy(p, buf->data, buf->len);
 339                p += buf->len;
 340                *p++ = ':';
 341                memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len);
 342                p += ctx->nfs_server.export_path_len;
 343                *p = 0;
 344
 345                ret = nfs4_get_referral_tree(fc);
 346                if (ret == 0)
 347                        return 0;
 348        }
 349
 350        return ret;
 351}
 352
 353/**
 354 * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
 355 * @fc: pointer to struct nfs_fs_context
 356 * @locations: array of NFSv4 server location information
 357 *
 358 */
 359static int nfs_follow_referral(struct fs_context *fc,
 360                               const struct nfs4_fs_locations *locations)
 361{
 362        struct nfs_fs_context *ctx = nfs_fc2context(fc);
 363        int loc, error;
 364
 365        if (locations == NULL || locations->nlocations <= 0)
 366                return -ENOENT;
 367
 368        dprintk("%s: referral at %pd2\n", __func__, ctx->clone_data.dentry);
 369
 370        /* Ensure fs path is a prefix of current dentry path */
 371        error = nfs4_validate_fspath(ctx->clone_data.dentry, locations, ctx);
 372        if (error < 0)
 373                return error;
 374
 375        error = -ENOENT;
 376        for (loc = 0; loc < locations->nlocations; loc++) {
 377                const struct nfs4_fs_location *location = &locations->locations[loc];
 378
 379                if (location == NULL || location->nservers <= 0 ||
 380                    location->rootpath.ncomponents == 0)
 381                        continue;
 382
 383                error = try_location(fc, location);
 384                if (error == 0)
 385                        return 0;
 386        }
 387
 388        return error;
 389}
 390
 391/*
 392 * nfs_do_refmount - handle crossing a referral on server
 393 * @dentry - dentry of referral
 394 *
 395 */
 396static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
 397{
 398        struct nfs_fs_context *ctx = nfs_fc2context(fc);
 399        struct dentry *dentry, *parent;
 400        struct nfs4_fs_locations *fs_locations = NULL;
 401        struct page *page;
 402        int err = -ENOMEM;
 403
 404        /* BUG_ON(IS_ROOT(dentry)); */
 405        page = alloc_page(GFP_KERNEL);
 406        if (!page)
 407                return -ENOMEM;
 408
 409        fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
 410        if (!fs_locations)
 411                goto out_free;
 412
 413        /* Get locations */
 414        dentry = ctx->clone_data.dentry;
 415        parent = dget_parent(dentry);
 416        dprintk("%s: getting locations for %pd2\n",
 417                __func__, dentry);
 418
 419        err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page);
 420        dput(parent);
 421        if (err != 0)
 422                goto out_free_2;
 423
 424        err = -ENOENT;
 425        if (fs_locations->nlocations <= 0 ||
 426            fs_locations->fs_path.ncomponents <= 0)
 427                goto out_free_2;
 428
 429        err = nfs_follow_referral(fc, fs_locations);
 430out_free_2:
 431        kfree(fs_locations);
 432out_free:
 433        __free_page(page);
 434        return err;
 435}
 436
 437int nfs4_submount(struct fs_context *fc, struct nfs_server *server)
 438{
 439        struct nfs_fs_context *ctx = nfs_fc2context(fc);
 440        struct dentry *dentry = ctx->clone_data.dentry;
 441        struct dentry *parent = dget_parent(dentry);
 442        struct inode *dir = d_inode(parent);
 443        struct rpc_clnt *client;
 444        int ret;
 445
 446        /* Look it up again to get its attributes and sec flavor */
 447        client = nfs4_proc_lookup_mountpoint(dir, dentry, ctx->mntfh,
 448                                             ctx->clone_data.fattr);
 449        dput(parent);
 450        if (IS_ERR(client))
 451                return PTR_ERR(client);
 452
 453        ctx->selected_flavor = client->cl_auth->au_flavor;
 454        if (ctx->clone_data.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
 455                ret = nfs_do_refmount(fc, client);
 456        } else {
 457                ret = nfs_do_submount(fc);
 458        }
 459
 460        rpc_shutdown_client(client);
 461        return ret;
 462}
 463
 464/*
 465 * Try one location from the fs_locations array.
 466 *
 467 * Returns zero on success, or a negative errno value.
 468 */
 469static int nfs4_try_replacing_one_location(struct nfs_server *server,
 470                char *page, char *page2,
 471                const struct nfs4_fs_location *location)
 472{
 473        const size_t addr_bufsize = sizeof(struct sockaddr_storage);
 474        struct net *net = rpc_net_ns(server->client);
 475        struct sockaddr *sap;
 476        unsigned int s;
 477        size_t salen;
 478        int error;
 479
 480        sap = kmalloc(addr_bufsize, GFP_KERNEL);
 481        if (sap == NULL)
 482                return -ENOMEM;
 483
 484        error = -ENOENT;
 485        for (s = 0; s < location->nservers; s++) {
 486                const struct nfs4_string *buf = &location->servers[s];
 487                char *hostname;
 488
 489                if (buf->len <= 0 || buf->len > PAGE_SIZE)
 490                        continue;
 491
 492                if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len) != NULL)
 493                        continue;
 494
 495                salen = nfs_parse_server_name(buf->data, buf->len,
 496                                                sap, addr_bufsize, net);
 497                if (salen == 0)
 498                        continue;
 499                rpc_set_port(sap, NFS_PORT);
 500
 501                error = -ENOMEM;
 502                hostname = kmemdup_nul(buf->data, buf->len, GFP_KERNEL);
 503                if (hostname == NULL)
 504                        break;
 505
 506                error = nfs4_update_server(server, hostname, sap, salen, net);
 507                kfree(hostname);
 508                if (error == 0)
 509                        break;
 510        }
 511
 512        kfree(sap);
 513        return error;
 514}
 515
 516/**
 517 * nfs4_replace_transport - set up transport to destination server
 518 *
 519 * @server: export being migrated
 520 * @locations: fs_locations array
 521 *
 522 * Returns zero on success, or a negative errno value.
 523 *
 524 * The client tries all the entries in the "locations" array, in the
 525 * order returned by the server, until one works or the end of the
 526 * array is reached.
 527 */
 528int nfs4_replace_transport(struct nfs_server *server,
 529                           const struct nfs4_fs_locations *locations)
 530{
 531        char *page = NULL, *page2 = NULL;
 532        int loc, error;
 533
 534        error = -ENOENT;
 535        if (locations == NULL || locations->nlocations <= 0)
 536                goto out;
 537
 538        error = -ENOMEM;
 539        page = (char *) __get_free_page(GFP_USER);
 540        if (!page)
 541                goto out;
 542        page2 = (char *) __get_free_page(GFP_USER);
 543        if (!page2)
 544                goto out;
 545
 546        for (loc = 0; loc < locations->nlocations; loc++) {
 547                const struct nfs4_fs_location *location =
 548                                                &locations->locations[loc];
 549
 550                if (location == NULL || location->nservers <= 0 ||
 551                    location->rootpath.ncomponents == 0)
 552                        continue;
 553
 554                error = nfs4_try_replacing_one_location(server, page,
 555                                                        page2, location);
 556                if (error == 0)
 557                        break;
 558        }
 559
 560out:
 561        free_page((unsigned long)page);
 562        free_page((unsigned long)page2);
 563        return error;
 564}
 565