linux/fs/nfs/mount_clnt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * In-kernel MOUNT protocol client
   4 *
   5 * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
   6 */
   7
   8#include <linux/types.h>
   9#include <linux/socket.h>
  10#include <linux/kernel.h>
  11#include <linux/errno.h>
  12#include <linux/uio.h>
  13#include <linux/net.h>
  14#include <linux/in.h>
  15#include <linux/sunrpc/clnt.h>
  16#include <linux/sunrpc/sched.h>
  17#include <linux/nfs_fs.h>
  18#include "internal.h"
  19
  20#define NFSDBG_FACILITY NFSDBG_MOUNT
  21
  22/*
  23 * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4
  24 */
  25#define MNTPATHLEN              (1024)
  26
  27/*
  28 * XDR data type sizes
  29 */
  30#define encode_dirpath_sz       (1 + XDR_QUADLEN(MNTPATHLEN))
  31#define MNT_status_sz           (1)
  32#define MNT_fhs_status_sz       (1)
  33#define MNT_fhandle_sz          XDR_QUADLEN(NFS2_FHSIZE)
  34#define MNT_fhandle3_sz         (1 + XDR_QUADLEN(NFS3_FHSIZE))
  35#define MNT_authflav3_sz        (1 + NFS_MAX_SECFLAVORS)
  36
  37/*
  38 * XDR argument and result sizes
  39 */
  40#define MNT_enc_dirpath_sz      encode_dirpath_sz
  41#define MNT_dec_mountres_sz     (MNT_status_sz + MNT_fhandle_sz)
  42#define MNT_dec_mountres3_sz    (MNT_status_sz + MNT_fhandle_sz + \
  43                                 MNT_authflav3_sz)
  44
  45/*
  46 * Defined by RFC 1094, section A.5
  47 */
  48enum {
  49        MOUNTPROC_NULL          = 0,
  50        MOUNTPROC_MNT           = 1,
  51        MOUNTPROC_DUMP          = 2,
  52        MOUNTPROC_UMNT          = 3,
  53        MOUNTPROC_UMNTALL       = 4,
  54        MOUNTPROC_EXPORT        = 5,
  55};
  56
  57/*
  58 * Defined by RFC 1813, section 5.2
  59 */
  60enum {
  61        MOUNTPROC3_NULL         = 0,
  62        MOUNTPROC3_MNT          = 1,
  63        MOUNTPROC3_DUMP         = 2,
  64        MOUNTPROC3_UMNT         = 3,
  65        MOUNTPROC3_UMNTALL      = 4,
  66        MOUNTPROC3_EXPORT       = 5,
  67};
  68
  69static const struct rpc_program mnt_program;
  70
  71/*
  72 * Defined by OpenGroup XNFS Version 3W, chapter 8
  73 */
  74enum mountstat {
  75        MNT_OK                  = 0,
  76        MNT_EPERM               = 1,
  77        MNT_ENOENT              = 2,
  78        MNT_EACCES              = 13,
  79        MNT_EINVAL              = 22,
  80};
  81
  82static struct {
  83        u32 status;
  84        int errno;
  85} mnt_errtbl[] = {
  86        { .status = MNT_OK,                     .errno = 0,             },
  87        { .status = MNT_EPERM,                  .errno = -EPERM,        },
  88        { .status = MNT_ENOENT,                 .errno = -ENOENT,       },
  89        { .status = MNT_EACCES,                 .errno = -EACCES,       },
  90        { .status = MNT_EINVAL,                 .errno = -EINVAL,       },
  91};
  92
  93/*
  94 * Defined by RFC 1813, section 5.1.5
  95 */
  96enum mountstat3 {
  97        MNT3_OK                 = 0,            /* no error */
  98        MNT3ERR_PERM            = 1,            /* Not owner */
  99        MNT3ERR_NOENT           = 2,            /* No such file or directory */
 100        MNT3ERR_IO              = 5,            /* I/O error */
 101        MNT3ERR_ACCES           = 13,           /* Permission denied */
 102        MNT3ERR_NOTDIR          = 20,           /* Not a directory */
 103        MNT3ERR_INVAL           = 22,           /* Invalid argument */
 104        MNT3ERR_NAMETOOLONG     = 63,           /* Filename too long */
 105        MNT3ERR_NOTSUPP         = 10004,        /* Operation not supported */
 106        MNT3ERR_SERVERFAULT     = 10006,        /* A failure on the server */
 107};
 108
 109static struct {
 110        u32 status;
 111        int errno;
 112} mnt3_errtbl[] = {
 113        { .status = MNT3_OK,                    .errno = 0,             },
 114        { .status = MNT3ERR_PERM,               .errno = -EPERM,        },
 115        { .status = MNT3ERR_NOENT,              .errno = -ENOENT,       },
 116        { .status = MNT3ERR_IO,                 .errno = -EIO,          },
 117        { .status = MNT3ERR_ACCES,              .errno = -EACCES,       },
 118        { .status = MNT3ERR_NOTDIR,             .errno = -ENOTDIR,      },
 119        { .status = MNT3ERR_INVAL,              .errno = -EINVAL,       },
 120        { .status = MNT3ERR_NAMETOOLONG,        .errno = -ENAMETOOLONG, },
 121        { .status = MNT3ERR_NOTSUPP,            .errno = -ENOTSUPP,     },
 122        { .status = MNT3ERR_SERVERFAULT,        .errno = -EREMOTEIO,    },
 123};
 124
 125struct mountres {
 126        int errno;
 127        struct nfs_fh *fh;
 128        unsigned int *auth_count;
 129        rpc_authflavor_t *auth_flavors;
 130};
 131
 132struct mnt_fhstatus {
 133        u32 status;
 134        struct nfs_fh *fh;
 135};
 136
 137/**
 138 * nfs_mount - Obtain an NFS file handle for the given host and path
 139 * @info: pointer to mount request arguments
 140 *
 141 * Uses default timeout parameters specified by underlying transport. On
 142 * successful return, the auth_flavs list and auth_flav_len will be populated
 143 * with the list from the server or a faked-up list if the server didn't
 144 * provide one.
 145 */
 146int nfs_mount(struct nfs_mount_request *info)
 147{
 148        struct mountres result = {
 149                .fh             = info->fh,
 150                .auth_count     = info->auth_flav_len,
 151                .auth_flavors   = info->auth_flavs,
 152        };
 153        struct rpc_message msg  = {
 154                .rpc_argp       = info->dirpath,
 155                .rpc_resp       = &result,
 156        };
 157        struct rpc_create_args args = {
 158                .net            = info->net,
 159                .protocol       = info->protocol,
 160                .address        = info->sap,
 161                .addrsize       = info->salen,
 162                .servername     = info->hostname,
 163                .program        = &mnt_program,
 164                .version        = info->version,
 165                .authflavor     = RPC_AUTH_UNIX,
 166                .cred           = current_cred(),
 167        };
 168        struct rpc_clnt         *mnt_clnt;
 169        int                     status;
 170
 171        dprintk("NFS: sending MNT request for %s:%s\n",
 172                (info->hostname ? info->hostname : "server"),
 173                        info->dirpath);
 174
 175        if (strlen(info->dirpath) > MNTPATHLEN)
 176                return -ENAMETOOLONG;
 177
 178        if (info->noresvport)
 179                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 180
 181        mnt_clnt = rpc_create(&args);
 182        if (IS_ERR(mnt_clnt))
 183                goto out_clnt_err;
 184
 185        if (info->version == NFS_MNT3_VERSION)
 186                msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
 187        else
 188                msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
 189
 190        status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT);
 191        rpc_shutdown_client(mnt_clnt);
 192
 193        if (status < 0)
 194                goto out_call_err;
 195        if (result.errno != 0)
 196                goto out_mnt_err;
 197
 198        dprintk("NFS: MNT request succeeded\n");
 199        status = 0;
 200
 201        /*
 202         * If the server didn't provide a flavor list, allow the
 203         * client to try any flavor.
 204         */
 205        if (info->version != NFS_MNT3_VERSION || *info->auth_flav_len == 0) {
 206                dprintk("NFS: Faking up auth_flavs list\n");
 207                info->auth_flavs[0] = RPC_AUTH_NULL;
 208                *info->auth_flav_len = 1;
 209        }
 210out:
 211        return status;
 212
 213out_clnt_err:
 214        status = PTR_ERR(mnt_clnt);
 215        dprintk("NFS: failed to create MNT RPC client, status=%d\n", status);
 216        goto out;
 217
 218out_call_err:
 219        dprintk("NFS: MNT request failed, status=%d\n", status);
 220        goto out;
 221
 222out_mnt_err:
 223        dprintk("NFS: MNT server returned result %d\n", result.errno);
 224        status = result.errno;
 225        goto out;
 226}
 227
 228/**
 229 * nfs_umount - Notify a server that we have unmounted this export
 230 * @info: pointer to umount request arguments
 231 *
 232 * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
 233 * use UDP.
 234 */
 235void nfs_umount(const struct nfs_mount_request *info)
 236{
 237        static const struct rpc_timeout nfs_umnt_timeout = {
 238                .to_initval = 1 * HZ,
 239                .to_maxval = 3 * HZ,
 240                .to_retries = 2,
 241        };
 242        struct rpc_create_args args = {
 243                .net            = info->net,
 244                .protocol       = IPPROTO_UDP,
 245                .address        = info->sap,
 246                .addrsize       = info->salen,
 247                .timeout        = &nfs_umnt_timeout,
 248                .servername     = info->hostname,
 249                .program        = &mnt_program,
 250                .version        = info->version,
 251                .authflavor     = RPC_AUTH_UNIX,
 252                .flags          = RPC_CLNT_CREATE_NOPING,
 253                .cred           = current_cred(),
 254        };
 255        struct rpc_message msg  = {
 256                .rpc_argp       = info->dirpath,
 257        };
 258        struct rpc_clnt *clnt;
 259        int status;
 260
 261        if (strlen(info->dirpath) > MNTPATHLEN)
 262                return;
 263
 264        if (info->noresvport)
 265                args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
 266
 267        clnt = rpc_create(&args);
 268        if (IS_ERR(clnt))
 269                goto out_clnt_err;
 270
 271        dprintk("NFS: sending UMNT request for %s:%s\n",
 272                (info->hostname ? info->hostname : "server"), info->dirpath);
 273
 274        if (info->version == NFS_MNT3_VERSION)
 275                msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT];
 276        else
 277                msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT];
 278
 279        status = rpc_call_sync(clnt, &msg, 0);
 280        rpc_shutdown_client(clnt);
 281
 282        if (unlikely(status < 0))
 283                goto out_call_err;
 284
 285        return;
 286
 287out_clnt_err:
 288        dprintk("NFS: failed to create UMNT RPC client, status=%ld\n",
 289                        PTR_ERR(clnt));
 290        return;
 291
 292out_call_err:
 293        dprintk("NFS: UMNT request failed, status=%d\n", status);
 294}
 295
 296/*
 297 * XDR encode/decode functions for MOUNT
 298 */
 299
 300static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
 301{
 302        const u32 pathname_len = strlen(pathname);
 303        __be32 *p;
 304
 305        p = xdr_reserve_space(xdr, 4 + pathname_len);
 306        xdr_encode_opaque(p, pathname, pathname_len);
 307}
 308
 309static void mnt_xdr_enc_dirpath(struct rpc_rqst *req, struct xdr_stream *xdr,
 310                                const void *dirpath)
 311{
 312        encode_mntdirpath(xdr, dirpath);
 313}
 314
 315/*
 316 * RFC 1094: "A non-zero status indicates some sort of error.  In this
 317 * case, the status is a UNIX error number."  This can be problematic
 318 * if the server and client use different errno values for the same
 319 * error.
 320 *
 321 * However, the OpenGroup XNFS spec provides a simple mapping that is
 322 * independent of local errno values on the server and the client.
 323 */
 324static int decode_status(struct xdr_stream *xdr, struct mountres *res)
 325{
 326        unsigned int i;
 327        u32 status;
 328        __be32 *p;
 329
 330        p = xdr_inline_decode(xdr, 4);
 331        if (unlikely(p == NULL))
 332                return -EIO;
 333        status = be32_to_cpup(p);
 334
 335        for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) {
 336                if (mnt_errtbl[i].status == status) {
 337                        res->errno = mnt_errtbl[i].errno;
 338                        return 0;
 339                }
 340        }
 341
 342        dprintk("NFS: unrecognized MNT status code: %u\n", status);
 343        res->errno = -EACCES;
 344        return 0;
 345}
 346
 347static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
 348{
 349        struct nfs_fh *fh = res->fh;
 350        __be32 *p;
 351
 352        p = xdr_inline_decode(xdr, NFS2_FHSIZE);
 353        if (unlikely(p == NULL))
 354                return -EIO;
 355
 356        fh->size = NFS2_FHSIZE;
 357        memcpy(fh->data, p, NFS2_FHSIZE);
 358        return 0;
 359}
 360
 361static int mnt_xdr_dec_mountres(struct rpc_rqst *req,
 362                                struct xdr_stream *xdr,
 363                                void *data)
 364{
 365        struct mountres *res = data;
 366        int status;
 367
 368        status = decode_status(xdr, res);
 369        if (unlikely(status != 0 || res->errno != 0))
 370                return status;
 371        return decode_fhandle(xdr, res);
 372}
 373
 374static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)
 375{
 376        unsigned int i;
 377        u32 status;
 378        __be32 *p;
 379
 380        p = xdr_inline_decode(xdr, 4);
 381        if (unlikely(p == NULL))
 382                return -EIO;
 383        status = be32_to_cpup(p);
 384
 385        for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) {
 386                if (mnt3_errtbl[i].status == status) {
 387                        res->errno = mnt3_errtbl[i].errno;
 388                        return 0;
 389                }
 390        }
 391
 392        dprintk("NFS: unrecognized MNT3 status code: %u\n", status);
 393        res->errno = -EACCES;
 394        return 0;
 395}
 396
 397static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res)
 398{
 399        struct nfs_fh *fh = res->fh;
 400        u32 size;
 401        __be32 *p;
 402
 403        p = xdr_inline_decode(xdr, 4);
 404        if (unlikely(p == NULL))
 405                return -EIO;
 406
 407        size = be32_to_cpup(p);
 408        if (size > NFS3_FHSIZE || size == 0)
 409                return -EIO;
 410
 411        p = xdr_inline_decode(xdr, size);
 412        if (unlikely(p == NULL))
 413                return -EIO;
 414
 415        fh->size = size;
 416        memcpy(fh->data, p, size);
 417        return 0;
 418}
 419
 420static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
 421{
 422        rpc_authflavor_t *flavors = res->auth_flavors;
 423        unsigned int *count = res->auth_count;
 424        u32 entries, i;
 425        __be32 *p;
 426
 427        if (*count == 0)
 428                return 0;
 429
 430        p = xdr_inline_decode(xdr, 4);
 431        if (unlikely(p == NULL))
 432                return -EIO;
 433        entries = be32_to_cpup(p);
 434        dprintk("NFS: received %u auth flavors\n", entries);
 435        if (entries > NFS_MAX_SECFLAVORS)
 436                entries = NFS_MAX_SECFLAVORS;
 437
 438        p = xdr_inline_decode(xdr, 4 * entries);
 439        if (unlikely(p == NULL))
 440                return -EIO;
 441
 442        if (entries > *count)
 443                entries = *count;
 444
 445        for (i = 0; i < entries; i++) {
 446                flavors[i] = be32_to_cpup(p++);
 447                dprintk("NFS:   auth flavor[%u]: %d\n", i, flavors[i]);
 448        }
 449        *count = i;
 450
 451        return 0;
 452}
 453
 454static int mnt_xdr_dec_mountres3(struct rpc_rqst *req,
 455                                 struct xdr_stream *xdr,
 456                                 void *data)
 457{
 458        struct mountres *res = data;
 459        int status;
 460
 461        status = decode_fhs_status(xdr, res);
 462        if (unlikely(status != 0 || res->errno != 0))
 463                return status;
 464        status = decode_fhandle3(xdr, res);
 465        if (unlikely(status != 0)) {
 466                res->errno = -EBADHANDLE;
 467                return 0;
 468        }
 469        return decode_auth_flavors(xdr, res);
 470}
 471
 472static const struct rpc_procinfo mnt_procedures[] = {
 473        [MOUNTPROC_MNT] = {
 474                .p_proc         = MOUNTPROC_MNT,
 475                .p_encode       = mnt_xdr_enc_dirpath,
 476                .p_decode       = mnt_xdr_dec_mountres,
 477                .p_arglen       = MNT_enc_dirpath_sz,
 478                .p_replen       = MNT_dec_mountres_sz,
 479                .p_statidx      = MOUNTPROC_MNT,
 480                .p_name         = "MOUNT",
 481        },
 482        [MOUNTPROC_UMNT] = {
 483                .p_proc         = MOUNTPROC_UMNT,
 484                .p_encode       = mnt_xdr_enc_dirpath,
 485                .p_arglen       = MNT_enc_dirpath_sz,
 486                .p_statidx      = MOUNTPROC_UMNT,
 487                .p_name         = "UMOUNT",
 488        },
 489};
 490
 491static const struct rpc_procinfo mnt3_procedures[] = {
 492        [MOUNTPROC3_MNT] = {
 493                .p_proc         = MOUNTPROC3_MNT,
 494                .p_encode       = mnt_xdr_enc_dirpath,
 495                .p_decode       = mnt_xdr_dec_mountres3,
 496                .p_arglen       = MNT_enc_dirpath_sz,
 497                .p_replen       = MNT_dec_mountres3_sz,
 498                .p_statidx      = MOUNTPROC3_MNT,
 499                .p_name         = "MOUNT",
 500        },
 501        [MOUNTPROC3_UMNT] = {
 502                .p_proc         = MOUNTPROC3_UMNT,
 503                .p_encode       = mnt_xdr_enc_dirpath,
 504                .p_arglen       = MNT_enc_dirpath_sz,
 505                .p_statidx      = MOUNTPROC3_UMNT,
 506                .p_name         = "UMOUNT",
 507        },
 508};
 509
 510static unsigned int mnt_counts[ARRAY_SIZE(mnt_procedures)];
 511static const struct rpc_version mnt_version1 = {
 512        .number         = 1,
 513        .nrprocs        = ARRAY_SIZE(mnt_procedures),
 514        .procs          = mnt_procedures,
 515        .counts         = mnt_counts,
 516};
 517
 518static unsigned int mnt3_counts[ARRAY_SIZE(mnt3_procedures)];
 519static const struct rpc_version mnt_version3 = {
 520        .number         = 3,
 521        .nrprocs        = ARRAY_SIZE(mnt3_procedures),
 522        .procs          = mnt3_procedures,
 523        .counts         = mnt3_counts,
 524};
 525
 526static const struct rpc_version *mnt_version[] = {
 527        NULL,
 528        &mnt_version1,
 529        NULL,
 530        &mnt_version3,
 531};
 532
 533static struct rpc_stat mnt_stats;
 534
 535static const struct rpc_program mnt_program = {
 536        .name           = "mount",
 537        .number         = NFS_MNT_PROGRAM,
 538        .nrvers         = ARRAY_SIZE(mnt_version),
 539        .version        = mnt_version,
 540        .stats          = &mnt_stats,
 541};
 542