21ab4e
From ac610b87289530bccadb9e245912c4491c1affd5 Mon Sep 17 00:00:00 2001
21ab4e
From: Niels de Vos <ndevos@redhat.com>
21ab4e
Date: Thu, 6 Jul 2017 17:04:17 +0200
21ab4e
Subject: [PATCH 551/557] nfs: add permission checking for mounting over WebNFS
21ab4e
21ab4e
Solaris 10 uses WebNFS and not the MOUNT protocol. All permission checks
21ab4e
for allowing/denying clients to mount are done through the MNT handlers.
21ab4e
These handlers will not give out a filehandle to the NFS-client when
21ab4e
mounting is denied. This prevents clients from successful mounting.
21ab4e
However, over WebNFS a well known 'root-filehandle' is used directly
21ab4e
with the NFSv3 protocol.
21ab4e
21ab4e
When WebNFS was used, no permission checks (the "nfs.export-dir" option)
21ab4e
were applied. Now the WebNFS mount-handler in Gluster/NFS calls the
21ab4e
mnt3_parse_dir_exports() function that takes care of the permission
21ab4e
checking.
21ab4e
21ab4e
Cherry picked from commit e304f48fa262e5cdbe181fb3fee5dfb9c893108c:
21ab4e
> BUG: 1468291
21ab4e
> Change-Id: Ic9dfd092473ba9c1c7b5fa38401cf9c0aa8395bb
21ab4e
> Signed-off-by: Niels de Vos <ndevos@redhat.com>
21ab4e
> Reviewed-on: https://review.gluster.org/17718
21ab4e
> Smoke: Gluster Build System <jenkins@build.gluster.org>
21ab4e
> Reviewed-by: soumya k <skoduri@redhat.com>
21ab4e
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
21ab4e
> Reviewed-by: Kaleb KEITHLEY <kkeithle@redhat.com>
21ab4e
21ab4e
Change-Id: Ic9dfd092473ba9c1c7b5fa38401cf9c0aa8395bb
21ab4e
BUG: 1451224
21ab4e
Signed-off-by: Niels de Vos <ndevos@redhat.com>
21ab4e
Reviewed-on: https://code.engineering.redhat.com/gerrit/111770
21ab4e
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
21ab4e
---
21ab4e
 xlators/nfs/server/src/mount3.c     | 60 ++++++++++++++++++++-----------
21ab4e
 xlators/nfs/server/src/mount3.h     |  7 ++++
21ab4e
 xlators/nfs/server/src/nfs-common.c | 25 +++++++------
21ab4e
 xlators/nfs/server/src/nfs3.c       | 71 +++++++++++++++++++++----------------
21ab4e
 4 files changed, 100 insertions(+), 63 deletions(-)
21ab4e
21ab4e
diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c
21ab4e
index b735038..a5b081b 100644
21ab4e
--- a/xlators/nfs/server/src/mount3.c
21ab4e
+++ b/xlators/nfs/server/src/mount3.c
21ab4e
@@ -945,7 +945,7 @@ err:
21ab4e
  * we need to strip out the volume name first.
21ab4e
  */
21ab4e
 char *
21ab4e
-__volume_subdir (char *dirpath, char **volname)
21ab4e
+mnt3_get_volume_subdir (char *dirpath, char **volname)
21ab4e
 {
21ab4e
         char    *subdir = NULL;
21ab4e
         int     volname_len = 0;
21ab4e
@@ -1024,10 +1024,6 @@ mnt3_resolve_subdir_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
                          struct iatt *buf, dict_t *xattr,
21ab4e
                          struct iatt *postparent);
21ab4e
 
21ab4e
-int
21ab4e
-mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms,
21ab4e
-                        char *subdir);
21ab4e
-
21ab4e
 int32_t
21ab4e
 mnt3_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
                    int32_t op_ret, int32_t op_errno, const char *path,
21ab4e
@@ -1310,7 +1306,8 @@ mnt3_readlink_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
21ab4e
         /* After the resolving the symlink , parsing should be done
21ab4e
          * for the populated mount path
21ab4e
          */
21ab4e
-        ret = mnt3_parse_dir_exports (mres->req, mres->mstate, real_loc);
21ab4e
+        ret = mnt3_parse_dir_exports (mres->req, mres->mstate, real_loc,
21ab4e
+                                      _gf_true);
21ab4e
 
21ab4e
         if (ret) {
21ab4e
                 gf_msg (GF_MNT, GF_LOG_ERROR, 0, NFS_MSG_RESOLVE_ERROR,
21ab4e
@@ -1518,7 +1515,8 @@ mnt3_verify_auth (struct sockaddr_in *client_addr, struct mnt3_export *export)
21ab4e
 
21ab4e
 int
21ab4e
 mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms,
21ab4e
-                     struct mnt3_export *exp, char *subdir)
21ab4e
+                     struct mnt3_export *exp, char *subdir,
21ab4e
+                     gf_boolean_t send_reply)
21ab4e
 {
21ab4e
         mnt3_resolve_t        *mres = NULL;
21ab4e
         int                   ret = -EFAULT;
21ab4e
@@ -1542,6 +1540,10 @@ mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms,
21ab4e
                 }
21ab4e
         }
21ab4e
 
21ab4e
+        /* no reply is needed (WebNFS permissions checking), just return */
21ab4e
+        if (!send_reply)
21ab4e
+                return 0; /* no error, mnt3_verify_auth() allowed it */
21ab4e
+
21ab4e
         mres = GF_CALLOC (1, sizeof (mnt3_resolve_t), gf_nfs_mt_mnt3_resolve);
21ab4e
         if (!mres) {
21ab4e
                 gf_msg (GF_MNT, GF_LOG_ERROR, ENOMEM, NFS_MSG_NO_MEMORY,
21ab4e
@@ -1586,11 +1588,11 @@ mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms,
21ab4e
         if ((!req) || (!ms) || (!exp))
21ab4e
                 return ret;
21ab4e
 
21ab4e
-        volume_subdir = __volume_subdir (exp->expname, NULL);
21ab4e
+        volume_subdir = mnt3_get_volume_subdir (exp->expname, NULL);
21ab4e
         if (!volume_subdir)
21ab4e
                 goto err;
21ab4e
 
21ab4e
-        ret = mnt3_resolve_subdir (req, ms, exp, volume_subdir);
21ab4e
+        ret = mnt3_resolve_subdir (req, ms, exp, volume_subdir, _gf_true);
21ab4e
         if (ret < 0) {
21ab4e
                 gf_msg (GF_MNT, GF_LOG_ERROR, ret, NFS_MSG_RESOLVE_SUBDIR_FAIL,
21ab4e
                         "Failed to resolve export dir: %s", exp->expname);
21ab4e
@@ -1687,7 +1689,7 @@ err:
21ab4e
         return ret;
21ab4e
 }
21ab4e
 
21ab4e
-static int
21ab4e
+int
21ab4e
 mnt3_check_client_net_tcp (rpcsvc_request_t *req, char *volname)
21ab4e
 {
21ab4e
         rpcsvc_t                *svc = NULL;
21ab4e
@@ -1761,25 +1763,41 @@ err:
21ab4e
 
21ab4e
 int
21ab4e
 mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms,
21ab4e
-                        char *subdir)
21ab4e
+                        char *path, gf_boolean_t send_reply)
21ab4e
 {
21ab4e
         char                    volname[1024] = {0, };
21ab4e
         struct mnt3_export      *exp = NULL;
21ab4e
         char                    *volname_ptr = NULL;
21ab4e
+        char                    *subdir = NULL;
21ab4e
         int                     ret = -ENOENT;
21ab4e
         struct nfs_state        *nfs = NULL;
21ab4e
 
21ab4e
-        if ((!ms) || (!subdir))
21ab4e
+        if ((!ms) || (!path))
21ab4e
                 return -1;
21ab4e
 
21ab4e
         volname_ptr = volname;
21ab4e
-        subdir = __volume_subdir (subdir, &volname_ptr);
21ab4e
-        if (!subdir)
21ab4e
+        subdir = mnt3_get_volume_subdir (path, &volname_ptr);
21ab4e
+        if (!subdir) {
21ab4e
+                gf_msg_trace (GF_MNT, 0, "Could not parse volname/subdir from "
21ab4e
+                              "%s", path);
21ab4e
                 goto err;
21ab4e
+        }
21ab4e
 
21ab4e
-        exp = mnt3_mntpath_to_export (ms, volname, _gf_false);
21ab4e
-        if (!exp)
21ab4e
-                goto err;
21ab4e
+        /* first try to match the full export/subdir */
21ab4e
+        exp = mnt3_mntpath_to_export (ms, path, _gf_false);
21ab4e
+        if (!exp) {
21ab4e
+                gf_msg_trace (GF_MNT, 0, "Could not find exact matching export "
21ab4e
+                              "for path=%s", path);
21ab4e
+                /* if no exact match is found, look for a fallback */
21ab4e
+                exp = mnt3_mntpath_to_export (ms, volname, _gf_true);
21ab4e
+                if (!exp) {
21ab4e
+                        gf_msg_trace (GF_MNT, 0, "Could not find export for "
21ab4e
+                                      "volume %s", volname);
21ab4e
+                        goto err;
21ab4e
+                }
21ab4e
+        }
21ab4e
+        gf_msg_trace (GF_MNT, 0, "volume %s and export %s will be used for "
21ab4e
+                      "path %s", exp->vol->name, exp->expname, path);
21ab4e
 
21ab4e
         nfs = (struct nfs_state *)ms->nfsx->private;
21ab4e
         if (!nfs)
21ab4e
@@ -1798,7 +1816,7 @@ mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms,
21ab4e
                 goto err;
21ab4e
         }
21ab4e
 
21ab4e
-        ret = mnt3_resolve_subdir (req, ms, exp, subdir);
21ab4e
+        ret = mnt3_resolve_subdir (req, ms, exp, subdir, send_reply);
21ab4e
         if (ret < 0) {
21ab4e
                 gf_msg (GF_MNT, GF_LOG_ERROR, ret, NFS_MSG_RESOLVE_SUBDIR_FAIL,
21ab4e
                         "Failed to resolve export dir: %s", subdir);
21ab4e
@@ -1841,7 +1859,7 @@ mnt3_find_export (rpcsvc_request_t *req, char *path, struct mnt3_export **e)
21ab4e
                 goto err;
21ab4e
         }
21ab4e
 
21ab4e
-        ret = mnt3_parse_dir_exports (req, ms, path);
21ab4e
+        ret = mnt3_parse_dir_exports (req, ms, path, _gf_true);
21ab4e
 
21ab4e
 err:
21ab4e
         return ret;
21ab4e
@@ -2914,7 +2932,7 @@ nfs3_rootfh (struct svc_req *req, xlator_t *nfsx,
21ab4e
          * 3. If a subdir is exported using nfs.export-dir,
21ab4e
          *      then the mount type would be MNT3_EXPTYPE_DIR,
21ab4e
          *      so make sure to find the proper path to be
21ab4e
-         *      resolved using __volume_subdir()
21ab4e
+         *      resolved using mnt3_get_volume_subdir()
21ab4e
          * 3. Make sure subdir export is allowed.
21ab4e
          */
21ab4e
         ms = __mnt3udp_get_mstate(nfsx);
21ab4e
@@ -2937,7 +2955,7 @@ nfs3_rootfh (struct svc_req *req, xlator_t *nfsx,
21ab4e
                         return NULL;
21ab4e
                 }
21ab4e
 
21ab4e
-                path = __volume_subdir (path, &volptr);
21ab4e
+                path = mnt3_get_volume_subdir (path, &volptr);
21ab4e
                 if (exp == NULL)
21ab4e
                         exp = mnt3_mntpath_to_export (ms, volname , _gf_false);
21ab4e
         }
21ab4e
diff --git a/xlators/nfs/server/src/mount3.h b/xlators/nfs/server/src/mount3.h
21ab4e
index ce01a6c..8868aec 100644
21ab4e
--- a/xlators/nfs/server/src/mount3.h
21ab4e
+++ b/xlators/nfs/server/src/mount3.h
21ab4e
@@ -178,4 +178,11 @@ struct mount3_resolve_state {
21ab4e
 
21ab4e
 typedef struct mount3_resolve_state mnt3_resolve_t;
21ab4e
 
21ab4e
+int
21ab4e
+mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms,
21ab4e
+                        char *subdir, gf_boolean_t send_reply);
21ab4e
+
21ab4e
+char*
21ab4e
+mnt3_get_volume_subdir (char *path, char **volname);
21ab4e
+
21ab4e
 #endif
21ab4e
diff --git a/xlators/nfs/server/src/nfs-common.c b/xlators/nfs/server/src/nfs-common.c
21ab4e
index 5269188..2f742d4 100644
21ab4e
--- a/xlators/nfs/server/src/nfs-common.c
21ab4e
+++ b/xlators/nfs/server/src/nfs-common.c
21ab4e
@@ -73,8 +73,8 @@ nfs_xlator_to_xlid (xlator_list_t *cl, xlator_t *xl)
21ab4e
 xlator_t *
21ab4e
 nfs_mntpath_to_xlator (xlator_list_t *cl, char *path)
21ab4e
 {
21ab4e
-        char            *volname  = NULL;
21ab4e
-        char            *volptr   = NULL;
21ab4e
+        char            *volname  = NULL; /* volume name only */
21ab4e
+        char            *volptr   = NULL; /* ptr to original volname */
21ab4e
         size_t           pathlen  = -1;
21ab4e
         xlator_t        *targetxl = NULL;
21ab4e
         int              i        = 0;
21ab4e
@@ -82,14 +82,16 @@ nfs_mntpath_to_xlator (xlator_list_t *cl, char *path)
21ab4e
         if ((!cl) || (!path))
21ab4e
                 return NULL;
21ab4e
 
21ab4e
-        volname = strdupa (path);
21ab4e
-        pathlen = strlen (volname);
21ab4e
         gf_msg_trace (GF_NFS, 0, "Subvolume search: %s", path);
21ab4e
+
21ab4e
+        volname = volptr = gf_strdup (path);
21ab4e
+        if (!volname)
21ab4e
+                return NULL;
21ab4e
+
21ab4e
         if (volname[0] == '/')
21ab4e
-                volptr = &volname[1];
21ab4e
-        else
21ab4e
-                volptr = &volname[0];
21ab4e
+                volname++;
21ab4e
 
21ab4e
+        pathlen = strlen (volname);
21ab4e
         for (i = 0; i < pathlen; i++) {
21ab4e
                 if (volname[i] == '/') {
21ab4e
                         volname[i] = '\0';
21ab4e
@@ -98,10 +100,10 @@ nfs_mntpath_to_xlator (xlator_list_t *cl, char *path)
21ab4e
         }
21ab4e
 
21ab4e
         while (cl) {
21ab4e
-                gf_msg_trace (GF_NFS, 0, "Volptr: %s and cl->xlator->name: %s",
21ab4e
-                              volptr, cl->xlator->name);
21ab4e
+                gf_msg_trace (GF_NFS, 0, "Volname: %s and cl->xlator->name: %s",
21ab4e
+                              volname, cl->xlator->name);
21ab4e
 
21ab4e
-                if (strcmp (volptr, cl->xlator->name) == 0) {
21ab4e
+                if (strcmp (volname, cl->xlator->name) == 0) {
21ab4e
                         targetxl = cl->xlator;
21ab4e
                         break;
21ab4e
                 }
21ab4e
@@ -109,8 +111,9 @@ nfs_mntpath_to_xlator (xlator_list_t *cl, char *path)
21ab4e
                 cl = cl->next;
21ab4e
         }
21ab4e
 
21ab4e
-        return targetxl;
21ab4e
+        GF_FREE (volptr);
21ab4e
 
21ab4e
+        return targetxl;
21ab4e
 }
21ab4e
 
21ab4e
 
21ab4e
diff --git a/xlators/nfs/server/src/nfs3.c b/xlators/nfs/server/src/nfs3.c
21ab4e
index bb68bc1..7443dbc 100644
21ab4e
--- a/xlators/nfs/server/src/nfs3.c
21ab4e
+++ b/xlators/nfs/server/src/nfs3.c
21ab4e
@@ -349,44 +349,51 @@ out:
21ab4e
 }
21ab4e
 
21ab4e
 
21ab4e
-static enum nfsstat3
21ab4e
-nfs3_funge_webnfs_zerolen_fh (struct nfs3_state *nfs3st, struct nfs3_fh *fhd,
21ab4e
-                               char *name)
21ab4e
+static int
21ab4e
+nfs3_funge_webnfs_zerolen_fh (rpcsvc_request_t *req, struct nfs3_state *nfs3st,
21ab4e
+                              struct nfs3_fh *fhd, char *name)
21ab4e
 {
21ab4e
-        xlator_t        *fungexl  = NULL;
21ab4e
-        glfs_t          *fs       = NULL;
21ab4e
-        loc_t            loc      = { 0, };
21ab4e
-        enum nfsstat3    nfsstat  = NFS3ERR_SERVERFAULT;
21ab4e
-        int              ret      = -1;
21ab4e
-        size_t           namelen  = -1;
21ab4e
+        xlator_t           *fungexl           = NULL;
21ab4e
+        struct nfs_state   *nfs               = NULL;
21ab4e
+        glfs_t             *fs                = NULL;
21ab4e
+        loc_t               loc               = { 0, };
21ab4e
+        int                 ret               = -1;
21ab4e
+        char               *subdir            = NULL;
21ab4e
+        char                volname[NAME_MAX] = { 0, };
21ab4e
 
21ab4e
         fungexl = nfs_mntpath_to_xlator (nfs3st->exportslist, name);
21ab4e
         if (!fungexl) {
21ab4e
-                nfsstat = NFS3ERR_NOENT;
21ab4e
+                gf_msg_trace (GF_NFS3, 0, "failed to find xlator for volume");
21ab4e
+                ret = -ENOENT;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+        /* fungexl is valid, set for nfs3_request_xlator_deviceid() */
21ab4e
+        rpcsvc_request_set_private (req, fungexl);
21ab4e
+
21ab4e
+        /* Permission checks are done through mnt3_parse_dir_exports(). The
21ab4e
+         * "nfs.export-dir" option gets checked as well. */
21ab4e
+        nfs = nfs_state (nfs3st->nfsx);
21ab4e
+        ret = mnt3_parse_dir_exports (req, nfs->mstate, name, _gf_false);
21ab4e
+        if (ret) {
21ab4e
+                gf_msg_trace (GF_NFS3, -ret, "mounting not possible");
21ab4e
                 goto out;
21ab4e
         }
21ab4e
 
21ab4e
         /* glfs_resolve_at copied from UDP MNT support */
21ab4e
         fs = glfs_new_from_ctx (fungexl->ctx);
21ab4e
         if (!fs) {
21ab4e
-                nfsstat = NFS3ERR_NOENT;
21ab4e
+                gf_msg_trace (GF_NFS3, 0, "failed to create glfs instance");
21ab4e
+                ret = -ENOENT;
21ab4e
                 goto out;
21ab4e
         }
21ab4e
 
21ab4e
-        /* strip volname/ from 'name' */
21ab4e
-        namelen = strlen(name);
21ab4e
-        while (namelen != 0) {
21ab4e
-                name++;
21ab4e
-                if (name[0] == '/') {
21ab4e
-                        break;
21ab4e
-                }
21ab4e
-                namelen--;
21ab4e
-        }
21ab4e
-        gf_msg_debug (GF_NFS, 0, "NAME :%s ", name);
21ab4e
+        /* split name "volname/sub/dir/s" into pieces */
21ab4e
+        subdir = mnt3_get_volume_subdir (name, (char**) &volname);
21ab4e
 
21ab4e
-        ret = glfs_resolve_at (fs, fungexl, NULL, name, &loc, NULL, 1, 0);
21ab4e
+        ret = glfs_resolve_at (fs, fungexl, NULL, subdir, &loc, NULL, 1, 0);
21ab4e
         if (ret != 0) {
21ab4e
-                nfsstat = NFS3ERR_NOENT;
21ab4e
+                gf_msg_trace (GF_NFS3, 0, "failed to resolve %s", subdir);
21ab4e
+                ret = -ENOENT;
21ab4e
                 goto out;
21ab4e
         }
21ab4e
 
21ab4e
@@ -399,17 +406,17 @@ nfs3_funge_webnfs_zerolen_fh (struct nfs3_state *nfs3st, struct nfs3_fh *fhd,
21ab4e
                                                         fungexl);
21ab4e
         else {
21ab4e
                 if (__nfs3_get_volume_id (nfs3st, fungexl, fhd->exportid) < 0) {
21ab4e
-                        nfsstat = NFS3ERR_STALE;
21ab4e
+                        ret = -ESTALE;
21ab4e
                         goto out;
21ab4e
                 }
21ab4e
         }
21ab4e
 
21ab4e
-        nfsstat = NFS3_OK;
21ab4e
+        ret = 0;
21ab4e
 out:
21ab4e
         if (fs)
21ab4e
                 glfs_free_from_ctx (fs);
21ab4e
 
21ab4e
-        return nfsstat;
21ab4e
+        return ret;
21ab4e
 }
21ab4e
 
21ab4e
 
21ab4e
@@ -470,8 +477,10 @@ nfs3_solaris_zerolen_fh (struct nfs3_fh *fh, int fhlen)
21ab4e
         if (nfs3_fh_validate (fh))
21ab4e
                 return 0;
21ab4e
 
21ab4e
-        if (fhlen == 0)
21ab4e
+        if (fhlen == 0) {
21ab4e
+                gf_msg_trace (GF_NFS3, 0, "received WebNFS request");
21ab4e
                 return 1;
21ab4e
+        }
21ab4e
 
21ab4e
         return 0;
21ab4e
 }
21ab4e
@@ -1544,8 +1553,8 @@ nfs3_lookup (rpcsvc_request_t *req, struct nfs3_fh *fh, int fhlen, char *name)
21ab4e
                                 name);
21ab4e
         nfs3_validate_nfs3_state (req, nfs3, stat, nfs3err, ret);
21ab4e
         if (nfs3_solaris_zerolen_fh (fh, fhlen)) {
21ab4e
-                stat = nfs3_funge_webnfs_zerolen_fh (nfs3, fh, name);
21ab4e
-                if (stat != NFS3_OK)
21ab4e
+                ret = nfs3_funge_webnfs_zerolen_fh (req, nfs3, fh, name);
21ab4e
+                if (ret < 0)
21ab4e
                         goto nfs3err;
21ab4e
 
21ab4e
                 /* this fh means we're doing a mount, name is no more useful */
21ab4e
@@ -1564,12 +1573,12 @@ nfs3_lookup (rpcsvc_request_t *req, struct nfs3_fh *fh, int fhlen, char *name)
21ab4e
         if (ret < 0) {
21ab4e
                 gf_msg (GF_NFS, GF_LOG_ERROR, -ret,
21ab4e
                         NFS_MSG_HARD_RESOLVE_FAIL,
21ab4e
-                        "failed to start hard reslove");
21ab4e
-                stat = nfs3_errno_to_nfsstat3 (-ret);
21ab4e
+                        "failed to start hard resolve");
21ab4e
         }
21ab4e
 
21ab4e
 nfs3err:
21ab4e
         if (ret < 0) {
21ab4e
+                stat = nfs3_errno_to_nfsstat3 (-ret);
21ab4e
                 nfs3_log_common_res (rpcsvc_request_xid (req),
21ab4e
                                      NFS3_LOOKUP, stat, -ret,
21ab4e
                                      cs ? cs->resolvedloc.path : NULL);
21ab4e
-- 
21ab4e
1.8.3.1
21ab4e