diff options
| author | Santosh Kumar Pradhan <spradhan@redhat.com> | 2014-07-22 16:56:57 +0530 | 
|---|---|---|
| committer | Niels de Vos <ndevos@redhat.com> | 2014-10-07 00:51:29 -0700 | 
| commit | ddb31110db8e1b5995d392ced988f34d2f9145d2 (patch) | |
| tree | 196f7271492c76a673e3a330cb22c3e4685b0e48 | |
| parent | 1642ee54cf78bb2d117f7ffb2a180acf12c54ab6 (diff) | |
gNFS: Subdir mount does not work on UDP proto
After enabling nfs.mount-udp, mounting a subdir on a volume over
NFS fails. Because mountudpproc3_mnt_3_svc() invokes nfs3_rootfh()
which internally calls mnt3_mntpath_to_export() to resolve the
mount path. mnt3_mntpath_to_export() just works if the mount path
requested is volume itself. It is not able to resolve, if the path
is a subdir inside the volume.
MOUNT over TCP uses mnt3_find_export() to resolve subdir path but
UDP can't use this routine because mnt3_find_export() needs the
req data (of type rpcsvc_request_t) and it's available only for
TCP version of RPC.
FIX:
(1) Use syncop_lookup() framework to resolve the MOUNT PATH by
    breaking it into components and resolve component-by-component.
    i.e. glfs_resolve_at () API from libgfapi shared object.
(2) If MOUNT PATH is subdir, then make sure subdir export is not
    disabled.
(3) Add auth mechanism to respect nfs.rpc-auth-allow/reject and
    subdir auth i.e. nfs.export-dir
(4) Enhanced error handling for MOUNT over UDP
Change-Id: I42ee69415d064b98af4f49773026562824f684d1
BUG: 1118311
Signed-off-by: Santosh Kumar Pradhan <spradhan@redhat.com>
Reviewed-on: http://review.gluster.org/8346
Reviewed-by: soumya k <skoduri@redhat.com>
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Niels de Vos <ndevos@redhat.com>
| -rw-r--r-- | api/src/glfs-internal.h | 51 | ||||
| -rw-r--r-- | api/src/glfs.c | 37 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpcsvc.c | 44 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/rpcsvc.h | 5 | ||||
| -rw-r--r-- | tests/bugs/bug-1116503.t | 21 | ||||
| -rw-r--r-- | xlators/nfs/server/src/Makefile.am | 4 | ||||
| -rw-r--r-- | xlators/nfs/server/src/mount3.c | 394 | ||||
| -rw-r--r-- | xlators/nfs/server/src/mount3udp_svc.c | 74 | ||||
| -rw-r--r-- | xlators/nfs/server/src/nfs3-fh.c | 2 | ||||
| -rw-r--r-- | xlators/nfs/server/src/nfs3-fh.h | 2 | ||||
| -rw-r--r-- | xlators/nfs/server/src/nfs3-helpers.c | 4 | 
11 files changed, 494 insertions, 144 deletions
diff --git a/api/src/glfs-internal.h b/api/src/glfs-internal.h index 6fdec961a1c..ff875280ce6 100644 --- a/api/src/glfs-internal.h +++ b/api/src/glfs-internal.h @@ -226,4 +226,55 @@ int glfs_getxattr_process (void *value, size_t size, dict_t *xattr,  /* Sends RPC call to glusterd to fetch required volume info */  int glfs_get_volume_info (struct glfs *fs); +/* +  SYNOPSIS + +       glfs_new_from_ctx: Creates a virtual mount object by taking a +       glusterfs_ctx_t object. + +  DESCRIPTION + +       glfs_new_from_ctx() is not same as glfs_new(). It takes the +       glusterfs_ctx_t object instead of creating one by glusterfs_ctx_new(). +       Again the usage is restricted to NFS MOUNT over UDP i.e. in +       glfs_resolve_at() which would take fs object as input but never use +       (purpose is not to change the ABI of glfs_resolve_at()). + +  PARAMETERS + +       @ctx: glusterfs_ctx_t object + +  RETURN VALUES + +       fs     : Pointer to the newly created glfs_t object. +       NULL   : Otherwise. +*/ + +struct glfs *glfs_new_from_ctx (glusterfs_ctx_t *ctx); + +/* +  SYNOPSIS + +       glfs_free_from_ctx: Free up the memory occupied by glfs_t object +       created by glfs_new_from_ctx(). + +  DESCRIPTION + +       The glfs_t object allocated by glfs_new_from_ctx() must be released +       by the caller using this routine. The usage is restricted to NFS +       MOUNT over UDP i.e. +       __mnt3udp_get_export_subdir_inode () +                                => glfs_resolve_at(). + +  PARAMETERS + +       @fs: The glfs_t object to be deallocated. + +  RETURN VALUES + +       void +*/ + +void glfs_free_from_ctx (struct glfs *fs); +  #endif /* !_GLFS_INTERNAL_H */ diff --git a/api/src/glfs.c b/api/src/glfs.c index bcabb29f857..c7c4c00450a 100644 --- a/api/src/glfs.c +++ b/api/src/glfs.c @@ -554,6 +554,43 @@ glfs_new (const char *volname)  } +struct glfs * +glfs_new_from_ctx (glusterfs_ctx_t *ctx) +{ +        struct glfs    *fs = NULL; + +        if (!ctx) +                return NULL; + +        fs = GF_CALLOC (1, sizeof (*fs), glfs_mt_glfs_t); +        if (!fs) +                return NULL; +        fs->ctx = ctx; + +        (void) pthread_cond_init (&fs->cond, NULL); + +        (void) pthread_mutex_init (&fs->mutex, NULL); + +        INIT_LIST_HEAD (&fs->openfds); + +        return fs; +} + + +void +glfs_free_from_ctx (struct glfs *fs) +{ +        if (!fs) +                return; + +        (void) pthread_cond_destroy (&fs->cond); + +        (void) pthread_mutex_destroy (&fs->mutex); + +        GF_FREE (fs); +} + +  int  glfs_set_volfile (struct glfs *fs, const char *volfile)  { diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c index 1238a6a1c1e..b19a905692d 100644 --- a/rpc/rpc-lib/src/rpcsvc.c +++ b/rpc/rpc-lib/src/rpcsvc.c @@ -2366,21 +2366,18 @@ rpcsvc_combine_allow_reject_volume_check (int allow, int reject)  }  int -rpcsvc_auth_check (rpcsvc_t *svc, char *volname, -                   rpc_transport_t *trans) +rpcsvc_auth_check (rpcsvc_t *svc, char *volname, char *ipaddr)  {          int     ret                            = RPCSVC_AUTH_REJECT;          int     accept                         = RPCSVC_AUTH_REJECT;          int     reject                         = RPCSVC_AUTH_REJECT;          char   *hostname                       = NULL; -        char   *ip                             = NULL; -        char    client_ip[RPCSVC_PEER_STRLEN]  = {0};          char   *allow_str                      = NULL;          char   *reject_str                     = NULL;          char   *srchstr                        = NULL;          dict_t *options                        = NULL; -        if (!svc || !volname || !trans) +        if (!svc || !volname || !ipaddr)                  return ret;          /* Fetch the options from svc struct and validate */ @@ -2388,13 +2385,6 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname,          if (!options)                  return ret; -        ret = rpcsvc_transport_peername (trans, client_ip, RPCSVC_PEER_STRLEN); -        if (ret != 0) { -                gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get remote addr: " -                        "%s", gai_strerror (ret)); -                return RPCSVC_AUTH_REJECT; -        } -          /* Accept if its the default case: Allow all, Reject none           * The default volfile always contains a 'allow *' rule           * for each volume. If allow rule is missing (which implies @@ -2435,13 +2425,9 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname,                          return RPCSVC_AUTH_ACCEPT;          } -        /* Non-default rule, authenticate */ -        if (!get_host_name (client_ip, &ip)) -                ip = client_ip; -          /* addr-namelookup check */          if (svc->addr_namelookup == _gf_true) { -                ret = gf_get_hostname_from_ip (ip, &hostname); +                ret = gf_get_hostname_from_ip (ipaddr, &hostname);                  if (ret) {                          if (hostname)                                  GF_FREE (hostname); @@ -2454,10 +2440,10 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname,          }          accept = rpcsvc_transport_peer_check_allow (options, volname, -                                                    ip, hostname); +                                                    ipaddr, hostname);          reject = rpcsvc_transport_peer_check_reject (options, volname, -                                                     ip, hostname); +                                                     ipaddr, hostname);          if (hostname)                  GF_FREE (hostname); @@ -2465,32 +2451,16 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname,  }  int -rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname, -                                 rpc_transport_t *trans) +rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname, uint16_t port)  { -        union gf_sock_union     sock_union;          int                     ret = RPCSVC_AUTH_REJECT; -        socklen_t               sinsize = sizeof (&sock_union.sin);          char                    *srchstr = NULL;          char                    *valstr = NULL; -        uint16_t                port = 0;          gf_boolean_t            insecure = _gf_false; -        memset (&sock_union, 0, sizeof (sock_union)); - -        if ((!svc) || (!volname) || (!trans)) +        if ((!svc) || (!volname))                  return ret; -        ret = rpcsvc_transport_peeraddr (trans, NULL, 0, &sock_union.storage, -                                         sinsize); -        if (ret != 0) { -                gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to get peer addr: %s", -                        gai_strerror (ret)); -                ret = RPCSVC_AUTH_REJECT; -                goto err; -        } - -        port = ntohs (sock_union.sin.sin_port);          gf_log (GF_RPCSVC, GF_LOG_TRACE, "Client port: %d", (int)port);          /* If the port is already a privileged one, dont bother with checking           * options. diff --git a/rpc/rpc-lib/src/rpcsvc.h b/rpc/rpc-lib/src/rpcsvc.h index 911fc958cc0..2e6fd93b60a 100644 --- a/rpc/rpc-lib/src/rpcsvc.h +++ b/rpc/rpc-lib/src/rpcsvc.h @@ -500,11 +500,10 @@ rpcsvc_transport_peeraddr (rpc_transport_t *trans, char *addrstr, int addrlen,                             struct sockaddr_storage *returnsa, socklen_t sasize);  extern int -rpcsvc_auth_check (rpcsvc_t *svc, char *volname, rpc_transport_t *trans); +rpcsvc_auth_check (rpcsvc_t *svc, char *volname, char *ipaddr);  extern int -rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname, -                                 rpc_transport_t *trans); +rpcsvc_transport_privport_check (rpcsvc_t *svc, char *volname, uint16_t port);  #define rpcsvc_request_seterr(req, err)                 (req)->rpc_err = err  #define rpcsvc_request_set_autherr(req, err)            (req)->auth_err = err diff --git a/tests/bugs/bug-1116503.t b/tests/bugs/bug-1116503.t index 0aad440560a..9bad1cd9e09 100644 --- a/tests/bugs/bug-1116503.t +++ b/tests/bugs/bug-1116503.t @@ -19,6 +19,27 @@ TEST $CLI volume start $V0  EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available;  TEST mount_nfs $H0:/$V0 $N0 nolock,mountproto=udp,proto=tcp; +TEST mkdir -p $N0/foo/bar +TEST ls $N0/foo +TEST ls $N0/foo/bar  EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; +TEST mount_nfs $H0:/$V0/foo $N0 nolock,mountproto=udp,proto=tcp; +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 + +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; +TEST mount_nfs $H0:/$V0/foo/bar $N0 nolock,mountproto=udp,proto=tcp; +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 + +TEST $CLI volume set $V0 nfs.addr-namelookup on +TEST $CLI volume set $V0 nfs.rpc-auth-allow $H0 +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; +TEST mount_nfs $H0:/$V0/foo/bar $N0 nolock,mountproto=udp,proto=tcp; +EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $N0 + +TEST $CLI volume set $V0 nfs.rpc-auth-reject $H0 +EXPECT_WITHIN $NFS_EXPORT_TIMEOUT "1" is_nfs_export_available; +TEST ! mount_nfs $H0:/$V0/foo/bar $N0 nolock,mountproto=udp,proto=tcp; +  cleanup; diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am index 32d93812b50..989747a249d 100644 --- a/xlators/nfs/server/src/Makefile.am +++ b/xlators/nfs/server/src/Makefile.am @@ -5,7 +5,8 @@ server_la_LDFLAGS = -module -avoid-version  server_la_SOURCES = nfs.c nfs-common.c nfs-fops.c nfs-inodes.c \  	nfs-generics.c mount3.c nfs3-fh.c nfs3.c nfs3-helpers.c nlm4.c \  	nlmcbk_svc.c mount3udp_svc.c acl3.c -server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la +server_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \ +                   $(top_builddir)/api/src/libgfapi.la  noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h \  	mount3.h nfs3-fh.h nfs3.h nfs3-helpers.h nfs-mem-types.h nlm4.h \ @@ -14,6 +15,7 @@ noinst_HEADERS = nfs.h nfs-common.h nfs-fops.h nfs-inodes.h nfs-generics.h \  AM_CPPFLAGS = $(GF_CPPFLAGS) \  	-DLIBDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/auth\" \  	-I$(top_srcdir)/libglusterfs/src \ +	-I$(top_srcdir)/api/src \  	-I$(nfsrpclibdir) -I$(CONTRIBDIR)/rbtree \  	-I$(top_srcdir)/rpc/xdr/src/ -DDATADIR=\"$(localstatedir)\" diff --git a/xlators/nfs/server/src/mount3.c b/xlators/nfs/server/src/mount3.c index 63d35735e7d..568b2f29fbd 100644 --- a/xlators/nfs/server/src/mount3.c +++ b/xlators/nfs/server/src/mount3.c @@ -31,6 +31,8 @@  #include "nfs.h"  #include "common-utils.h"  #include "store.h" +#include "glfs-internal.h" +#include "glfs.h"  #include <errno.h>  #include <sys/socket.h> @@ -211,7 +213,10 @@ mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh, int *authflavor,          uint32_t        fhlen = 0;          res.fhs_status = stat; -        fhlen = nfs3_fh_compute_size (fh); + +        if (fh) +                fhlen = nfs3_fh_compute_size (); +          res.mountres3_u.mountinfo.fhandle.fhandle3_len = fhlen;          res.mountres3_u.mountinfo.fhandle.fhandle3_val = (char *)fh;          res.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = authflavor; @@ -1021,7 +1026,7 @@ mnt3_match_subnet_v4 (struct addrinfo *ai, uint32_t saddr, uint32_t mask)   * the directory or not. Client's IP address will be compared with   * allowed IP list or range present in mnt3_export structure.   * - * @param req - RPC request. This structure contains client's IP address. + * @param client_addr - This structure contains client's IP address.   * @param export - mnt3_export structure. Contains allowed IP list/range.   *   * @return 0 - on Success and -EACCES on failure. @@ -1029,12 +1034,11 @@ mnt3_match_subnet_v4 (struct addrinfo *ai, uint32_t saddr, uint32_t mask)   * TODO: Support IPv6 subnetwork   */  int -mnt3_verify_auth (rpcsvc_request_t *req, struct mnt3_export *export) +mnt3_verify_auth (struct sockaddr_in *client_addr, struct mnt3_export *export)  {          int                     retvalue = -EACCES;          int                     ret = 0;          struct host_auth_spec   *host = NULL; -        struct sockaddr_in      *client_addr = NULL;          struct sockaddr_in      *allowed_addr = NULL;          struct addrinfo         *allowed_addrinfo = NULL; @@ -1045,8 +1049,7 @@ mnt3_verify_auth (rpcsvc_request_t *req, struct mnt3_export *export)          };          /* Sanity check */ -        if ((NULL == req) || -            (NULL == req->trans) || +        if ((NULL == client_addr) ||              (NULL == export) ||              (NULL == export->hostspec)) {                  gf_log (GF_MNT, GF_LOG_ERROR, "Invalid argument"); @@ -1055,9 +1058,6 @@ mnt3_verify_auth (rpcsvc_request_t *req, struct mnt3_export *export)          host = export->hostspec; -        /* Client's IP address. */ -        client_addr = (struct sockaddr_in *)(&(req->trans->peerinfo.sockaddr)); -          /*           * Currently IPv4 subnetwork is supported i.e. AF_INET.           * TODO: IPv6 subnetwork i.e. AF_INET6. @@ -1121,16 +1121,19 @@ int  mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms,                       struct mnt3_export *exp, char *subdir)  { -        mnt3_resolve_t  *mres = NULL; -        int             ret = -EFAULT; -        struct nfs3_fh  pfh = GF_NFS3FH_STATIC_INITIALIZER; +        mnt3_resolve_t        *mres = NULL; +        int                   ret = -EFAULT; +        struct nfs3_fh        pfh = GF_NFS3FH_STATIC_INITIALIZER; +        struct sockaddr_in    *sin = NULL;          if ((!req) || (!ms) || (!exp) || (!subdir))                  return ret; +        sin = (struct sockaddr_in *)(&(req->trans->peerinfo.sockaddr)); +          /* Need to check AUTH */          if (NULL != exp->hostspec) { -                ret = mnt3_verify_auth (req, exp); +                ret = mnt3_verify_auth (sin, exp);                  if (0 != ret) {                          gf_log (GF_MNT,GF_LOG_ERROR,                                          "AUTH verification failed"); @@ -1149,15 +1152,17 @@ mnt3_resolve_subdir (rpcsvc_request_t *req, struct mount3_state *ms,          mres->req = req;          strncpy (mres->remainingdir, subdir, MNTPATHLEN);          if (gf_nfs_dvm_off (nfs_state (ms->nfsx))) -                pfh = nfs3_fh_build_indexed_root_fh (mres->mstate->nfsx->children, mres->exp->vol); +                pfh = nfs3_fh_build_indexed_root_fh ( +                                            mres->mstate->nfsx->children, +                                            mres->exp->vol);          else                  pfh = nfs3_fh_build_uuid_root_fh (exp->volumeid);          mres->parentfh = pfh;          ret = __mnt3_resolve_subdir (mres);          if (ret < 0) { -                gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" -                        , mres->exp->expname); +                gf_log (GF_MNT, GF_LOG_ERROR, +                        "Failed to resolve export dir: %s", mres->exp->expname);                  GF_FREE (mres);          } @@ -1182,8 +1187,8 @@ mnt3_resolve_export_subdir (rpcsvc_request_t *req, struct mount3_state *ms,          ret = mnt3_resolve_subdir (req, ms, exp, volume_subdir);          if (ret < 0) { -                gf_log (GF_MNT, GF_LOG_ERROR, "Failed to resolve export dir: %s" -                        , exp->expname); +                gf_log (GF_MNT, GF_LOG_ERROR, +                        "Failed to resolve export dir: %s", exp->expname);                  goto err;          } @@ -1241,45 +1246,100 @@ foundexp:  } -int -mnt3_check_client_net (struct mount3_state *ms, rpcsvc_request_t *req, -                       xlator_t *targetxl) +static int +mnt3_check_client_net_check (rpcsvc_t *svc, char *expvol, +                             char *ipaddr, uint16_t port)  { +        int ret = RPCSVC_AUTH_REJECT; + +        if ((!svc) || (!expvol) || (!ipaddr)) +                goto err; + +        ret = rpcsvc_auth_check (svc, expvol, ipaddr); +        if (ret == RPCSVC_AUTH_REJECT) { +                gf_log (GF_MNT, GF_LOG_INFO, "Peer %s  not allowed", ipaddr); +                goto err; +        } + +        ret = rpcsvc_transport_privport_check (svc, expvol, port); +        if (ret == RPCSVC_AUTH_REJECT) { +                gf_log (GF_MNT, GF_LOG_INFO, "Peer %s rejected. Unprivileged " +                        "port %d not allowed", ipaddr, port); +                goto err; +        } +        ret = RPCSVC_AUTH_ACCEPT; +err: +        return ret; +} + +static int +mnt3_check_client_net_tcp (rpcsvc_request_t *req, char *volname) +{          rpcsvc_t                *svc = NULL;          rpc_transport_t         *trans = NULL; -        struct sockaddr_storage sastorage = {0,}; +        union gf_sock_union     sock_union; +        socklen_t               socksize = sizeof (struct sockaddr_in);          char                    peer[RPCSVC_PEER_STRLEN] = {0,}; -        int                     ret = -1; +        char                    *ipaddr = NULL; +        uint16_t                port = 0; +        int                     ret = RPCSVC_AUTH_REJECT; -        if ((!ms) || (!req) || (!targetxl)) -                return -1; +        if ((!req) || (!volname)) +                goto err;          svc = rpcsvc_request_service (req); -          trans = rpcsvc_request_transport (req); +        if ((!svc) || (!trans)) +                goto err; +          ret = rpcsvc_transport_peeraddr (trans, peer, RPCSVC_PEER_STRLEN, -                                         &sastorage, sizeof (sastorage)); +                                         &sock_union.storage, socksize);          if (ret != 0) { -                gf_log (GF_MNT, GF_LOG_WARNING, "Failed to get peer addr: %s", -                        gai_strerror (ret)); +                gf_log (GF_MNT, GF_LOG_WARNING, +                                "Failed to get peer addr: %s", +                                gai_strerror (ret)); +                ret = RPCSVC_AUTH_REJECT; +                goto err;          } -        ret = rpcsvc_auth_check (svc, targetxl->name, trans); -        if (ret == RPCSVC_AUTH_REJECT) { -                gf_log (GF_MNT, GF_LOG_INFO, "Peer %s  not allowed", peer); +        /* peer[] gets IP:PORT formar, slash the port out */ +        if (!get_host_name ((char *)peer, &ipaddr)) +                ipaddr = peer; + +        port = ntohs (sock_union.sin.sin_port); + +        ret = mnt3_check_client_net_check (svc, volname, ipaddr, port); +err: +        return ret; +} + +static int +mnt3_check_client_net_udp (struct svc_req *req, char *volname, xlator_t *nfsx) +{ +        rpcsvc_t                *svc = NULL; +        struct sockaddr_in      *sin = NULL; +        char                    ipaddr[INET_ADDRSTRLEN + 1] = {0, }; +        uint16_t                port = 0; +        int                     ret = RPCSVC_AUTH_REJECT; +        struct nfs_state        *nfs = NULL; + +        if ((!req) || (!volname) || (!nfsx))                  goto err; -        } -        ret = rpcsvc_transport_privport_check (svc, targetxl->name, -                                               rpcsvc_request_transport (req)); -        if (ret == RPCSVC_AUTH_REJECT) { -                gf_log (GF_MNT, GF_LOG_INFO, "Peer %s rejected. Unprivileged " -                        "port not allowed", peer); +        sin = svc_getcaller (req->rq_xprt); +        if (!sin)                  goto err; -        } -        ret = 0; +        (void) inet_ntop (AF_INET, &sin->sin_addr, ipaddr, INET_ADDRSTRLEN); + +        port = ntohs (sin->sin_port); + +        nfs = (struct nfs_state *)nfsx->private; +        if (nfs != NULL) +                svc = nfs->rpcsvc; + +        ret = mnt3_check_client_net_check (svc, volname, ipaddr, port);  err:          return ret;  } @@ -1289,7 +1349,7 @@ int  mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms,                          char *subdir)  { -        char                    volname[1024]; +        char                    volname[1024] = {0, };          struct mnt3_export      *exp = NULL;          char                    *volname_ptr = NULL;          int                     ret = -ENOENT; @@ -1317,7 +1377,8 @@ mnt3_parse_dir_exports (rpcsvc_request_t *req, struct mount3_state *ms,                  goto err;          } -        if (mnt3_check_client_net (ms, req, exp->vol) == RPCSVC_AUTH_REJECT) { +        ret = mnt3_check_client_net_tcp (req, exp->vol->name); +        if (ret == RPCSVC_AUTH_REJECT) {                  gf_log (GF_MNT, GF_LOG_DEBUG, "Client mount not allowed");                  ret = -EACCES;                  goto err; @@ -1415,7 +1476,7 @@ mnt3svc_mnt (rpcsvc_request_t *req)                   * call to mnt3_find_export().                   *                   * This is subdir mount, we are already DONE! -                 * nfs_subvolume_started() and mnt3_check_client_net() +                 * nfs_subvolume_started() and mnt3_check_client_net_tcp()                   * validation are done in mnt3_parse_dir_exports()                   * which is invoked through mnt3_find_export().                   * @@ -1433,7 +1494,7 @@ mnt3svc_mnt (rpcsvc_request_t *req)                  goto mnterr;          } -        ret = mnt3_check_client_net (ms, req, exp->vol); +        ret = mnt3_check_client_net_tcp (req, exp->vol->name);          if (ret == RPCSVC_AUTH_REJECT) {                  mntstat = MNT3ERR_ACCES;                  gf_log (GF_MNT, GF_LOG_DEBUG, "Client mount not allowed"); @@ -1926,61 +1987,242 @@ err:          return ret;  } -/* just declaring, definition is way down below */ -rpcsvc_program_t        mnt3prog; -/* nfs3_rootfh used by mount3udp thread needs to access mount3prog.private - * directly as we don't have nfs xlator pointer to dereference it. But thats OK +/* + * __mnt3udp_get_mstate() Fetches mount3_state from xlator + * Linkage: Static + * Usage: Used only for UDP MOUNT codepath   */ +static struct mount3_state * +__mnt3udp_get_mstate (xlator_t *nfsx) +{ +        struct nfs_state        *nfs = NULL; +        struct mount3_state     *ms = NULL; + +        if (nfsx == NULL) +                return NULL; + +        nfs = (struct nfs_state *)nfsx->private; +        if (nfs == NULL) +                return NULL; + +        ms = (struct mount3_state *)nfs->mstate; +        return ms; +} + +static inode_t * +__mnt3udp_get_export_subdir_inode (struct svc_req *req, char *subdir, +                                   char *expname, /* OUT */ +                                   struct mnt3_export *exp) +{ +        inode_t                 *inode = NULL; +        loc_t                   loc = {0, }; +        struct iatt             buf = {0, }; +        int                     ret = -1; +        glfs_t                  *fs = NULL; + +        if ((!req) || (!subdir) || (!expname) || (!exp)) +                return NULL; + +        /* AUTH check for subdir i.e. nfs.export-dir */ +        if (exp->hostspec) { +                struct sockaddr_in *sin = svc_getcaller (req->rq_xprt); +                ret = mnt3_verify_auth (sin, exp); +                if (ret) { +                        gf_log (GF_MNT,GF_LOG_ERROR, +                                "AUTH(nfs.export-dir) verification failed"); +                        errno = EACCES; +                        return NULL; +                } +        } + +        /* +         * IMP: glfs_t fs object is not used by glfs_resolve_at (). The main +         * purpose is to not change the ABI of glfs_resolve_at () and not to +         * pass a NULL object. +         * +         * TODO: Instead of linking against libgfapi.so, just for one API +         * i.e. glfs_resolve_at(), It would be cleaner if PATH name to +         * inode resolution code can be moved to libglusterfs.so or so. +         */ +        fs = glfs_new_from_ctx (exp->vol->ctx); +        if (!fs) +                return NULL; + +        ret = glfs_resolve_at (fs, exp->vol, NULL, subdir, +                               &loc, &buf, 0 /* Follow link */, +                               0 /* Hard lookup */); + +        glfs_free_from_ctx (fs); + +        if (ret != 0) { +                loc_wipe (&loc); +                return NULL; +        } + +        inode = inode_ref (loc.inode); +        snprintf (expname, PATH_MAX, "/%s%s", exp->vol->name, loc.path); + +        loc_wipe (&loc); + +        return inode; +} +static inode_t * +__mnt3udp_get_export_volume_inode (struct svc_req *req, char *volpath, +                                   char *expname, /* OUT */ +                                   struct mnt3_export *exp) +{ +        char                    *rpath = NULL; +        inode_t                 *inode = NULL; + +        if ((!req) || (!volpath) || (!expname) || (!exp)) +                return NULL; + +        rpath = strchr (volpath, '/'); +        if (rpath == NULL) +                rpath = "/"; + +        inode = inode_from_path (exp->vol->itable, rpath); +        snprintf (expname, PATH_MAX, "/%s", exp->vol->name); + +        return inode; +} + +/* + * nfs3_rootfh() is used for NFS MOUNT over UDP i.e. mountudpproc3_mnt_3_svc(). + * Especially in mount3udp_thread() THREAD. Gluster NFS starts this thread + * when nfs.mount-udp is ENABLED (set to TRUE/ON). + */  struct nfs3_fh * -nfs3_rootfh (char* path) +nfs3_rootfh (struct svc_req *req, xlator_t *nfsx, +             char *path, char *expname /* OUT */)  { -        struct mount3_state     *ms = NULL;          struct nfs3_fh          *fh = NULL; -        struct mnt3_export      *exp = NULL;          inode_t                 *inode = NULL; -        char                    *tmp = NULL; +        struct mnt3_export      *exp = NULL; +        struct mount3_state     *ms = NULL; +        struct nfs_state        *nfs = NULL; +        int                     mnt3type = MNT3_EXPTYPE_DIR; +        int                     ret = RPCSVC_AUTH_REJECT; + +        if ((!req) || (!nfsx) || (!path) || (!expname)) { +                errno = EFAULT; +                return NULL; +        } + +        /* +         * 1. First check if the MOUNT is for whole volume. +         *      i.e. __mnt3udp_get_export_volume_inode () +         * 2. If NOT, then TRY for SUBDIR MOUNT. +         *      i.e. __mnt3udp_get_export_subdir_inode () +         * 3. If a subdir is exported using nfs.export-dir, +         *      then the mount type would be MNT3_EXPTYPE_DIR, +         *      so make sure to find the proper path to be +         *      resolved using __volume_subdir() +         * 3. Make sure subdir export is allowed. +         */ +        ms = __mnt3udp_get_mstate(nfsx); +        if (!ms) { +                errno = EFAULT; +                return NULL; +        } -        ms = mnt3prog.private;          exp = mnt3_mntpath_to_export (ms, path); -        if (exp == NULL) -                goto err; +        if (exp != NULL) +                mnt3type = exp->exptype; + +        if (mnt3type == MNT3_EXPTYPE_DIR) { +                char    volname [MNTPATHLEN] = {0, }; +                char    *volptr = volname; + +                /* Subdir export (nfs3.export-dirs) check */ +                if (!gf_mnt3_export_dirs(ms)) { +                        errno = EACCES; +                        return NULL; +                } + +                path = __volume_subdir (path, &volptr); +                if (exp == NULL) +                        exp = mnt3_mntpath_to_export (ms, volname); +        } + +        if (exp == NULL) { +                errno = ENOENT; +                return NULL; +        } + +        nfs = (struct nfs_state *)nfsx->private; +        if (!nfs_subvolume_started (nfs, exp->vol)) { +                errno = ENOENT; +                return NULL; +        } + +        /* AUTH check: respect nfs.rpc-auth-allow/reject */ +        ret = mnt3_check_client_net_udp (req, exp->vol->name, nfsx); +        if (ret == RPCSVC_AUTH_REJECT) { +                errno = EACCES; +                return NULL; +        } -        tmp = (char *)path; -        tmp = strchr (tmp, '/'); -        if (tmp == NULL) -                tmp = "/"; +        switch (mnt3type) { -        inode = inode_from_path (exp->vol->itable, tmp); -        if (inode == NULL) +        case MNT3_EXPTYPE_VOLUME: +                inode = __mnt3udp_get_export_volume_inode (req, path, +                                                           expname, exp); +                break; + +        case MNT3_EXPTYPE_DIR: +                inode = __mnt3udp_get_export_subdir_inode (req, path, +                                                           expname, exp); +                break; + +        default: +                /* Never reachable */ +                gf_log (GF_MNT, GF_LOG_ERROR, "Unknown MOUNT3 type"); +                errno = EFAULT; +                goto err; +        } + +        if (inode == NULL) { +                /* Don't over-write errno */ +                if (!errno) +                        errno = ENOENT;                  goto err; +        } +        /* Build the inode from FH */          fh = GF_CALLOC (1, sizeof(*fh), gf_nfs_mt_nfs3_fh); -        if (fh == NULL) +        if (fh == NULL) { +                errno = ENOMEM;                  goto err; -        nfs3_build_fh (inode, exp->volumeid, fh); +        } + +        (void) nfs3_build_fh (inode, exp->volumeid, fh);  err:          if (inode)                  inode_unref (inode); +          return fh;  }  int -mount3udp_add_mountlist (char *host, dirpath *expname) +mount3udp_add_mountlist (xlator_t *nfsx, char *host, char *export)  {          struct mountentry       *me = NULL;          struct mount3_state     *ms = NULL; -        char                    *export = NULL; -        ms = mnt3prog.private; +        if ((!host) || (!export) || (!nfsx)) +                return -1; + +        ms = __mnt3udp_get_mstate (nfsx); +        if (!ms) +                return -1; +          me = GF_CALLOC (1, sizeof (*me), gf_nfs_mt_mountentry);          if (!me)                  return -1; -        export = (char *)expname; -        while (*export == '/') -                export++;          strncpy (me->exname, export, MNTPATHLEN);          strncpy (me->hostname, host, MNTPATHLEN); @@ -1995,15 +2237,17 @@ mount3udp_add_mountlist (char *host, dirpath *expname)  }  int -mount3udp_delete_mountlist (char *hostname, dirpath *expname) +mount3udp_delete_mountlist (xlator_t *nfsx, char *hostname, char *export)  {          struct mount3_state     *ms = NULL; -        char                    *export = NULL; -        ms = mnt3prog.private; -        export = (char *)expname; -        while (*export == '/') -                export++; +        if ((!hostname) || (!export) || (!nfsx)) +                return -1; + +        ms = __mnt3udp_get_mstate (nfsx); +        if (!ms) +                return -1; +          mnt3svc_umount (ms, export, hostname);          return 0;  } diff --git a/xlators/nfs/server/src/mount3udp_svc.c b/xlators/nfs/server/src/mount3udp_svc.c index 70aead67edb..4ad8e11ad49 100644 --- a/xlators/nfs/server/src/mount3udp_svc.c +++ b/xlators/nfs/server/src/mount3udp_svc.c @@ -23,49 +23,73 @@  #include <netinet/in.h> -extern struct nfs3_fh* nfs3_rootfh (char *dp); -extern mountres3 mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh, -                                        int *authflavor, u_int aflen); +extern struct nfs3_fh* +nfs3_rootfh (struct svc_req *req, xlator_t *nfsx, char *dp, char *expname); + +extern mountres3 +mnt3svc_set_mountres3 (mountstat3 stat, struct nfs3_fh *fh, +                       int *authflavor, u_int aflen);  extern int -mount3udp_add_mountlist (char *host, dirpath *expname); +mount3udp_add_mountlist (xlator_t *nfsx, char *host, char *expname);  extern int -mount3udp_delete_mountlist (char *host, dirpath *expname); +mount3udp_delete_mountlist (xlator_t *nfsx, char *host, char *expname); + +extern mountstat3 +mnt3svc_errno_to_mnterr (int32_t errnum);  /* only this thread will use this, no locking needed */  char mnthost[INET_ADDRSTRLEN+1]; +#define MNT3UDP_AUTH_LEN 1 /* Only AUTH_UNIX for now */ +  mountres3 *  mountudpproc3_mnt_3_svc(dirpath **dpp, struct svc_req *req)  {          struct mountres3        *res = NULL;          int                     *autharr = NULL;          struct nfs3_fh          *fh = NULL; -        char                    *tmp = NULL; +        char                    *mpath = NULL; +        xlator_t                *nfsx = THIS; +        char                    expname[PATH_MAX] = {0, }; +        mountstat3              stat = MNT3ERR_SERVERFAULT; -        tmp = (char *)*dpp; -        while (*tmp == '/') -                tmp++; -        fh = nfs3_rootfh (tmp); -        if (fh == NULL) { -                gf_log (GF_MNT, GF_LOG_DEBUG, "unable to get fh for %s", tmp); -                goto err; -        } +        errno = 0; /* RESET errno */ + +        mpath = (char *)*dpp; +        while (*mpath == '/') +                mpath++;          res = GF_CALLOC (1, sizeof(*res), gf_nfs_mt_mountres3);          if (res == NULL) { -                gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory"); +                gf_log (GF_MNT, GF_LOG_ERROR, "Unable to allocate memory");                  goto err;          } -        autharr = GF_CALLOC (1, sizeof(*autharr), gf_nfs_mt_int); +        autharr = GF_CALLOC (MNT3UDP_AUTH_LEN, sizeof(int), gf_nfs_mt_int);          if (autharr == NULL) { -                gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory"); +                gf_log (GF_MNT, GF_LOG_ERROR, "Unable to allocate memory");                  goto err;          } +          autharr[0] = AUTH_UNIX; -        *res = mnt3svc_set_mountres3 (MNT3_OK, fh, autharr, 1); -        mount3udp_add_mountlist (mnthost, *dpp); + +        fh = nfs3_rootfh (req, nfsx, mpath, (char *)expname); + +        /* FAILURE: No FH */ +        if (fh == NULL) { +                gf_log (GF_MNT, GF_LOG_ERROR, "Unable to get fh for %s", mpath); +                if (errno) +                        stat = mnt3svc_errno_to_mnterr (errno); +                *res = mnt3svc_set_mountres3 (stat, NULL /* fh */, +                                              autharr, MNT3UDP_AUTH_LEN); +                return res; +        } + +        /* SUCCESS */ +        stat = MNT3_OK; +        *res = mnt3svc_set_mountres3 (stat, fh, autharr, MNT3UDP_AUTH_LEN); +        (void) mount3udp_add_mountlist (nfsx, mnthost, (char *) expname);          return res;   err: @@ -79,14 +103,16 @@ mountstat3 *  mountudpproc3_umnt_3_svc(dirpath **dp, struct svc_req *req)  {          mountstat3 *stat = NULL; +        char       *mpath = (char *) *dp; +        xlator_t   *nfsx = THIS;          stat = GF_CALLOC (1, sizeof(mountstat3), gf_nfs_mt_mountstat3);          if (stat == NULL) { -                gf_log (GF_MNT, GF_LOG_ERROR, "unable to allocate memory"); +                gf_log (GF_MNT, GF_LOG_ERROR, "Unable to allocate memory");                  return NULL;          }          *stat = MNT3_OK; -        mount3udp_delete_mountlist (mnthost, *dp); +        (void) mount3udp_delete_mountlist (nfsx, mnthost, mpath);          return stat;  } @@ -147,7 +173,7 @@ mountudp_program_3(struct svc_req *rqstp, register SVCXPRT *transp)          }          if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument,                             (caddr_t) &argument)) { -                gf_log (GF_MNT, GF_LOG_ERROR, "unable to free arguments"); +                gf_log (GF_MNT, GF_LOG_ERROR, "Unable to free arguments");          }          if (result == NULL)                  return; @@ -176,8 +202,8 @@ mount3udp_thread (void *argv)          GF_ASSERT (nfsx);          if (glusterfs_this_set(nfsx)) { -                gf_log (GF_MNT, GF_LOG_ERROR, "failed to set xlator, " -                        "nfs.mount-udp will not work"); +                gf_log (GF_MNT, GF_LOG_ERROR, +                        "Failed to set xlator, nfs.mount-udp will not work");                  return NULL;          } diff --git a/xlators/nfs/server/src/nfs3-fh.c b/xlators/nfs/server/src/nfs3-fh.c index e199c56dc40..510913e8c43 100644 --- a/xlators/nfs/server/src/nfs3-fh.c +++ b/xlators/nfs/server/src/nfs3-fh.c @@ -182,7 +182,7 @@ nfs3_fh_build_child_fh (struct nfs3_fh *parent, struct iatt *newstat,  uint32_t -nfs3_fh_compute_size (struct nfs3_fh *fh) +nfs3_fh_compute_size ()  {          return GF_NFSFH_STATIC_SIZE;  } diff --git a/xlators/nfs/server/src/nfs3-fh.h b/xlators/nfs/server/src/nfs3-fh.h index 1049cdc9621..b52e5d670c8 100644 --- a/xlators/nfs/server/src/nfs3-fh.h +++ b/xlators/nfs/server/src/nfs3-fh.h @@ -66,7 +66,7 @@ struct nfs3_fh {  #define GF_NFS3FH_STATIC_INITIALIZER    {{0},}  extern uint32_t -nfs3_fh_compute_size (struct nfs3_fh *fh); +nfs3_fh_compute_size ();  extern uint16_t  nfs3_fh_hash_entry (uuid_t gfid); diff --git a/xlators/nfs/server/src/nfs3-helpers.c b/xlators/nfs/server/src/nfs3-helpers.c index f67cccf1a9b..cba127b41da 100644 --- a/xlators/nfs/server/src/nfs3-helpers.c +++ b/xlators/nfs/server/src/nfs3-helpers.c @@ -424,7 +424,7 @@ nfs3_fill_lookup3res_success (lookup3res *res, nfsstat3 stat,          res->status = stat;          if (fh) {                  res->lookup3res_u.resok.object.data.data_val = (void *)fh; -                fhlen = nfs3_fh_compute_size (fh); +                fhlen = nfs3_fh_compute_size ();                  res->lookup3res_u.resok.object.data.data_len = fhlen;          } @@ -721,7 +721,7 @@ nfs3_fill_post_op_fh3 (struct nfs3_fh *fh, post_op_fh3 *pfh)                  return;          pfh->handle_follows = 1; -        fhlen = nfs3_fh_compute_size (fh); +        fhlen = nfs3_fh_compute_size ();          pfh->post_op_fh3_u.handle.data.data_val = (void *)fh;          pfh->post_op_fh3_u.handle.data.data_len = fhlen;  }  | 
