Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * In-kernel MOUNT protocol client
0004  *
0005  * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
0006  */
0007 
0008 #include <linux/types.h>
0009 #include <linux/socket.h>
0010 #include <linux/kernel.h>
0011 #include <linux/errno.h>
0012 #include <linux/uio.h>
0013 #include <linux/net.h>
0014 #include <linux/in.h>
0015 #include <linux/sunrpc/clnt.h>
0016 #include <linux/sunrpc/sched.h>
0017 #include <linux/nfs_fs.h>
0018 #include "internal.h"
0019 
0020 #define NFSDBG_FACILITY NFSDBG_MOUNT
0021 
0022 /*
0023  * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4
0024  */
0025 #define MNTPATHLEN      (1024)
0026 
0027 /*
0028  * XDR data type sizes
0029  */
0030 #define encode_dirpath_sz   (1 + XDR_QUADLEN(MNTPATHLEN))
0031 #define MNT_status_sz       (1)
0032 #define MNT_fhandle_sz      XDR_QUADLEN(NFS2_FHSIZE)
0033 #define MNT_fhandlev3_sz    XDR_QUADLEN(NFS3_FHSIZE)
0034 #define MNT_authflav3_sz    (1 + NFS_MAX_SECFLAVORS)
0035 
0036 /*
0037  * XDR argument and result sizes
0038  */
0039 #define MNT_enc_dirpath_sz  encode_dirpath_sz
0040 #define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz)
0041 #define MNT_dec_mountres3_sz    (MNT_status_sz + MNT_fhandlev3_sz + \
0042                  MNT_authflav3_sz)
0043 
0044 /*
0045  * Defined by RFC 1094, section A.5
0046  */
0047 enum {
0048     MOUNTPROC_NULL      = 0,
0049     MOUNTPROC_MNT       = 1,
0050     MOUNTPROC_DUMP      = 2,
0051     MOUNTPROC_UMNT      = 3,
0052     MOUNTPROC_UMNTALL   = 4,
0053     MOUNTPROC_EXPORT    = 5,
0054 };
0055 
0056 /*
0057  * Defined by RFC 1813, section 5.2
0058  */
0059 enum {
0060     MOUNTPROC3_NULL     = 0,
0061     MOUNTPROC3_MNT      = 1,
0062     MOUNTPROC3_DUMP     = 2,
0063     MOUNTPROC3_UMNT     = 3,
0064     MOUNTPROC3_UMNTALL  = 4,
0065     MOUNTPROC3_EXPORT   = 5,
0066 };
0067 
0068 static const struct rpc_program mnt_program;
0069 
0070 /*
0071  * Defined by OpenGroup XNFS Version 3W, chapter 8
0072  */
0073 enum mountstat {
0074     MNT_OK          = 0,
0075     MNT_EPERM       = 1,
0076     MNT_ENOENT      = 2,
0077     MNT_EACCES      = 13,
0078     MNT_EINVAL      = 22,
0079 };
0080 
0081 static struct {
0082     u32 status;
0083     int errno;
0084 } mnt_errtbl[] = {
0085     { .status = MNT_OK,         .errno = 0,     },
0086     { .status = MNT_EPERM,          .errno = -EPERM,    },
0087     { .status = MNT_ENOENT,         .errno = -ENOENT,   },
0088     { .status = MNT_EACCES,         .errno = -EACCES,   },
0089     { .status = MNT_EINVAL,         .errno = -EINVAL,   },
0090 };
0091 
0092 /*
0093  * Defined by RFC 1813, section 5.1.5
0094  */
0095 enum mountstat3 {
0096     MNT3_OK         = 0,        /* no error */
0097     MNT3ERR_PERM        = 1,        /* Not owner */
0098     MNT3ERR_NOENT       = 2,        /* No such file or directory */
0099     MNT3ERR_IO      = 5,        /* I/O error */
0100     MNT3ERR_ACCES       = 13,       /* Permission denied */
0101     MNT3ERR_NOTDIR      = 20,       /* Not a directory */
0102     MNT3ERR_INVAL       = 22,       /* Invalid argument */
0103     MNT3ERR_NAMETOOLONG = 63,       /* Filename too long */
0104     MNT3ERR_NOTSUPP     = 10004,    /* Operation not supported */
0105     MNT3ERR_SERVERFAULT = 10006,    /* A failure on the server */
0106 };
0107 
0108 static struct {
0109     u32 status;
0110     int errno;
0111 } mnt3_errtbl[] = {
0112     { .status = MNT3_OK,            .errno = 0,     },
0113     { .status = MNT3ERR_PERM,       .errno = -EPERM,    },
0114     { .status = MNT3ERR_NOENT,      .errno = -ENOENT,   },
0115     { .status = MNT3ERR_IO,         .errno = -EIO,      },
0116     { .status = MNT3ERR_ACCES,      .errno = -EACCES,   },
0117     { .status = MNT3ERR_NOTDIR,     .errno = -ENOTDIR,  },
0118     { .status = MNT3ERR_INVAL,      .errno = -EINVAL,   },
0119     { .status = MNT3ERR_NAMETOOLONG,    .errno = -ENAMETOOLONG, },
0120     { .status = MNT3ERR_NOTSUPP,        .errno = -ENOTSUPP, },
0121     { .status = MNT3ERR_SERVERFAULT,    .errno = -EREMOTEIO,    },
0122 };
0123 
0124 struct mountres {
0125     int errno;
0126     struct nfs_fh *fh;
0127     unsigned int *auth_count;
0128     rpc_authflavor_t *auth_flavors;
0129 };
0130 
0131 struct mnt_fhstatus {
0132     u32 status;
0133     struct nfs_fh *fh;
0134 };
0135 
0136 /**
0137  * nfs_mount - Obtain an NFS file handle for the given host and path
0138  * @info: pointer to mount request arguments
0139  * @timeo: deciseconds the mount waits for a response before it retries
0140  * @retrans: number of times the mount retries a request
0141  *
0142  * Uses timeout parameters specified by caller. On successful return, the
0143  * auth_flavs list and auth_flav_len will be populated with the list from the
0144  * server or a faked-up list if the server didn't provide one.
0145  */
0146 int nfs_mount(struct nfs_mount_request *info, int timeo, int retrans)
0147 {
0148     struct rpc_timeout mnt_timeout;
0149     struct mountres result = {
0150         .fh     = info->fh,
0151         .auth_count = info->auth_flav_len,
0152         .auth_flavors   = info->auth_flavs,
0153     };
0154     struct rpc_message msg  = {
0155         .rpc_argp   = info->dirpath,
0156         .rpc_resp   = &result,
0157     };
0158     struct rpc_create_args args = {
0159         .net        = info->net,
0160         .protocol   = info->protocol,
0161         .address    = info->sap,
0162         .addrsize   = info->salen,
0163         .timeout    = &mnt_timeout,
0164         .servername = info->hostname,
0165         .program    = &mnt_program,
0166         .version    = info->version,
0167         .authflavor = RPC_AUTH_UNIX,
0168         .cred       = current_cred(),
0169     };
0170     struct rpc_clnt     *mnt_clnt;
0171     int         status;
0172 
0173     dprintk("NFS: sending MNT request for %s:%s\n",
0174         (info->hostname ? info->hostname : "server"),
0175             info->dirpath);
0176 
0177     if (strlen(info->dirpath) > MNTPATHLEN)
0178         return -ENAMETOOLONG;
0179 
0180     if (info->noresvport)
0181         args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
0182 
0183     nfs_init_timeout_values(&mnt_timeout, info->protocol, timeo, retrans);
0184     mnt_clnt = rpc_create(&args);
0185     if (IS_ERR(mnt_clnt))
0186         goto out_clnt_err;
0187 
0188     if (info->version == NFS_MNT3_VERSION)
0189         msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
0190     else
0191         msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
0192 
0193     status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT);
0194     rpc_shutdown_client(mnt_clnt);
0195 
0196     if (status < 0)
0197         goto out_call_err;
0198     if (result.errno != 0)
0199         goto out_mnt_err;
0200 
0201     dprintk("NFS: MNT request succeeded\n");
0202     status = 0;
0203 
0204     /*
0205      * If the server didn't provide a flavor list, allow the
0206      * client to try any flavor.
0207      */
0208     if (info->version != NFS_MNT3_VERSION || *info->auth_flav_len == 0) {
0209         dprintk("NFS: Faking up auth_flavs list\n");
0210         info->auth_flavs[0] = RPC_AUTH_NULL;
0211         *info->auth_flav_len = 1;
0212     }
0213 out:
0214     return status;
0215 
0216 out_clnt_err:
0217     status = PTR_ERR(mnt_clnt);
0218     dprintk("NFS: failed to create MNT RPC client, status=%d\n", status);
0219     goto out;
0220 
0221 out_call_err:
0222     dprintk("NFS: MNT request failed, status=%d\n", status);
0223     goto out;
0224 
0225 out_mnt_err:
0226     dprintk("NFS: MNT server returned result %d\n", result.errno);
0227     status = result.errno;
0228     goto out;
0229 }
0230 
0231 /**
0232  * nfs_umount - Notify a server that we have unmounted this export
0233  * @info: pointer to umount request arguments
0234  *
0235  * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
0236  * use UDP.
0237  */
0238 void nfs_umount(const struct nfs_mount_request *info)
0239 {
0240     static const struct rpc_timeout nfs_umnt_timeout = {
0241         .to_initval = 1 * HZ,
0242         .to_maxval = 3 * HZ,
0243         .to_retries = 2,
0244     };
0245     struct rpc_create_args args = {
0246         .net        = info->net,
0247         .protocol   = IPPROTO_UDP,
0248         .address    = info->sap,
0249         .addrsize   = info->salen,
0250         .timeout    = &nfs_umnt_timeout,
0251         .servername = info->hostname,
0252         .program    = &mnt_program,
0253         .version    = info->version,
0254         .authflavor = RPC_AUTH_UNIX,
0255         .flags      = RPC_CLNT_CREATE_NOPING,
0256         .cred       = current_cred(),
0257     };
0258     struct rpc_message msg  = {
0259         .rpc_argp   = info->dirpath,
0260     };
0261     struct rpc_clnt *clnt;
0262     int status;
0263 
0264     if (strlen(info->dirpath) > MNTPATHLEN)
0265         return;
0266 
0267     if (info->noresvport)
0268         args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
0269 
0270     clnt = rpc_create(&args);
0271     if (IS_ERR(clnt))
0272         goto out_clnt_err;
0273 
0274     dprintk("NFS: sending UMNT request for %s:%s\n",
0275         (info->hostname ? info->hostname : "server"), info->dirpath);
0276 
0277     if (info->version == NFS_MNT3_VERSION)
0278         msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT];
0279     else
0280         msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT];
0281 
0282     status = rpc_call_sync(clnt, &msg, 0);
0283     rpc_shutdown_client(clnt);
0284 
0285     if (unlikely(status < 0))
0286         goto out_call_err;
0287 
0288     return;
0289 
0290 out_clnt_err:
0291     dprintk("NFS: failed to create UMNT RPC client, status=%ld\n",
0292             PTR_ERR(clnt));
0293     return;
0294 
0295 out_call_err:
0296     dprintk("NFS: UMNT request failed, status=%d\n", status);
0297 }
0298 
0299 /*
0300  * XDR encode/decode functions for MOUNT
0301  */
0302 
0303 static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
0304 {
0305     const u32 pathname_len = strlen(pathname);
0306     __be32 *p;
0307 
0308     p = xdr_reserve_space(xdr, 4 + pathname_len);
0309     xdr_encode_opaque(p, pathname, pathname_len);
0310 }
0311 
0312 static void mnt_xdr_enc_dirpath(struct rpc_rqst *req, struct xdr_stream *xdr,
0313                 const void *dirpath)
0314 {
0315     encode_mntdirpath(xdr, dirpath);
0316 }
0317 
0318 /*
0319  * RFC 1094: "A non-zero status indicates some sort of error.  In this
0320  * case, the status is a UNIX error number."  This can be problematic
0321  * if the server and client use different errno values for the same
0322  * error.
0323  *
0324  * However, the OpenGroup XNFS spec provides a simple mapping that is
0325  * independent of local errno values on the server and the client.
0326  */
0327 static int decode_status(struct xdr_stream *xdr, struct mountres *res)
0328 {
0329     unsigned int i;
0330     u32 status;
0331     __be32 *p;
0332 
0333     p = xdr_inline_decode(xdr, 4);
0334     if (unlikely(p == NULL))
0335         return -EIO;
0336     status = be32_to_cpup(p);
0337 
0338     for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) {
0339         if (mnt_errtbl[i].status == status) {
0340             res->errno = mnt_errtbl[i].errno;
0341             return 0;
0342         }
0343     }
0344 
0345     dprintk("NFS: unrecognized MNT status code: %u\n", status);
0346     res->errno = -EACCES;
0347     return 0;
0348 }
0349 
0350 static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
0351 {
0352     struct nfs_fh *fh = res->fh;
0353     __be32 *p;
0354 
0355     p = xdr_inline_decode(xdr, NFS2_FHSIZE);
0356     if (unlikely(p == NULL))
0357         return -EIO;
0358 
0359     fh->size = NFS2_FHSIZE;
0360     memcpy(fh->data, p, NFS2_FHSIZE);
0361     return 0;
0362 }
0363 
0364 static int mnt_xdr_dec_mountres(struct rpc_rqst *req,
0365                 struct xdr_stream *xdr,
0366                 void *data)
0367 {
0368     struct mountres *res = data;
0369     int status;
0370 
0371     status = decode_status(xdr, res);
0372     if (unlikely(status != 0 || res->errno != 0))
0373         return status;
0374     return decode_fhandle(xdr, res);
0375 }
0376 
0377 static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)
0378 {
0379     unsigned int i;
0380     u32 status;
0381     __be32 *p;
0382 
0383     p = xdr_inline_decode(xdr, 4);
0384     if (unlikely(p == NULL))
0385         return -EIO;
0386     status = be32_to_cpup(p);
0387 
0388     for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) {
0389         if (mnt3_errtbl[i].status == status) {
0390             res->errno = mnt3_errtbl[i].errno;
0391             return 0;
0392         }
0393     }
0394 
0395     dprintk("NFS: unrecognized MNT3 status code: %u\n", status);
0396     res->errno = -EACCES;
0397     return 0;
0398 }
0399 
0400 static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res)
0401 {
0402     struct nfs_fh *fh = res->fh;
0403     u32 size;
0404     __be32 *p;
0405 
0406     p = xdr_inline_decode(xdr, 4);
0407     if (unlikely(p == NULL))
0408         return -EIO;
0409 
0410     size = be32_to_cpup(p);
0411     if (size > NFS3_FHSIZE || size == 0)
0412         return -EIO;
0413 
0414     p = xdr_inline_decode(xdr, size);
0415     if (unlikely(p == NULL))
0416         return -EIO;
0417 
0418     fh->size = size;
0419     memcpy(fh->data, p, size);
0420     return 0;
0421 }
0422 
0423 static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
0424 {
0425     rpc_authflavor_t *flavors = res->auth_flavors;
0426     unsigned int *count = res->auth_count;
0427     u32 entries, i;
0428     __be32 *p;
0429 
0430     if (*count == 0)
0431         return 0;
0432 
0433     p = xdr_inline_decode(xdr, 4);
0434     if (unlikely(p == NULL))
0435         return -EIO;
0436     entries = be32_to_cpup(p);
0437     dprintk("NFS: received %u auth flavors\n", entries);
0438     if (entries > NFS_MAX_SECFLAVORS)
0439         entries = NFS_MAX_SECFLAVORS;
0440 
0441     p = xdr_inline_decode(xdr, 4 * entries);
0442     if (unlikely(p == NULL))
0443         return -EIO;
0444 
0445     if (entries > *count)
0446         entries = *count;
0447 
0448     for (i = 0; i < entries; i++) {
0449         flavors[i] = be32_to_cpup(p++);
0450         dprintk("NFS:   auth flavor[%u]: %d\n", i, flavors[i]);
0451     }
0452     *count = i;
0453 
0454     return 0;
0455 }
0456 
0457 static int mnt_xdr_dec_mountres3(struct rpc_rqst *req,
0458                  struct xdr_stream *xdr,
0459                  void *data)
0460 {
0461     struct mountres *res = data;
0462     int status;
0463 
0464     status = decode_fhs_status(xdr, res);
0465     if (unlikely(status != 0 || res->errno != 0))
0466         return status;
0467     status = decode_fhandle3(xdr, res);
0468     if (unlikely(status != 0)) {
0469         res->errno = -EBADHANDLE;
0470         return 0;
0471     }
0472     return decode_auth_flavors(xdr, res);
0473 }
0474 
0475 static const struct rpc_procinfo mnt_procedures[] = {
0476     [MOUNTPROC_MNT] = {
0477         .p_proc     = MOUNTPROC_MNT,
0478         .p_encode   = mnt_xdr_enc_dirpath,
0479         .p_decode   = mnt_xdr_dec_mountres,
0480         .p_arglen   = MNT_enc_dirpath_sz,
0481         .p_replen   = MNT_dec_mountres_sz,
0482         .p_statidx  = MOUNTPROC_MNT,
0483         .p_name     = "MOUNT",
0484     },
0485     [MOUNTPROC_UMNT] = {
0486         .p_proc     = MOUNTPROC_UMNT,
0487         .p_encode   = mnt_xdr_enc_dirpath,
0488         .p_arglen   = MNT_enc_dirpath_sz,
0489         .p_statidx  = MOUNTPROC_UMNT,
0490         .p_name     = "UMOUNT",
0491     },
0492 };
0493 
0494 static const struct rpc_procinfo mnt3_procedures[] = {
0495     [MOUNTPROC3_MNT] = {
0496         .p_proc     = MOUNTPROC3_MNT,
0497         .p_encode   = mnt_xdr_enc_dirpath,
0498         .p_decode   = mnt_xdr_dec_mountres3,
0499         .p_arglen   = MNT_enc_dirpath_sz,
0500         .p_replen   = MNT_dec_mountres3_sz,
0501         .p_statidx  = MOUNTPROC3_MNT,
0502         .p_name     = "MOUNT",
0503     },
0504     [MOUNTPROC3_UMNT] = {
0505         .p_proc     = MOUNTPROC3_UMNT,
0506         .p_encode   = mnt_xdr_enc_dirpath,
0507         .p_arglen   = MNT_enc_dirpath_sz,
0508         .p_statidx  = MOUNTPROC3_UMNT,
0509         .p_name     = "UMOUNT",
0510     },
0511 };
0512 
0513 static unsigned int mnt_counts[ARRAY_SIZE(mnt_procedures)];
0514 static const struct rpc_version mnt_version1 = {
0515     .number     = 1,
0516     .nrprocs    = ARRAY_SIZE(mnt_procedures),
0517     .procs      = mnt_procedures,
0518     .counts     = mnt_counts,
0519 };
0520 
0521 static unsigned int mnt3_counts[ARRAY_SIZE(mnt3_procedures)];
0522 static const struct rpc_version mnt_version3 = {
0523     .number     = 3,
0524     .nrprocs    = ARRAY_SIZE(mnt3_procedures),
0525     .procs      = mnt3_procedures,
0526     .counts     = mnt3_counts,
0527 };
0528 
0529 static const struct rpc_version *mnt_version[] = {
0530     NULL,
0531     &mnt_version1,
0532     NULL,
0533     &mnt_version3,
0534 };
0535 
0536 static struct rpc_stat mnt_stats;
0537 
0538 static const struct rpc_program mnt_program = {
0539     .name       = "mount",
0540     .number     = NFS_MNT_PROGRAM,
0541     .nrvers     = ARRAY_SIZE(mnt_version),
0542     .version    = mnt_version,
0543     .stats      = &mnt_stats,
0544 };