diff options
-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; } |