summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/src/glfs-internal.h51
-rw-r--r--api/src/glfs.c37
-rw-r--r--rpc/rpc-lib/src/rpcsvc.c44
-rw-r--r--rpc/rpc-lib/src/rpcsvc.h5
-rw-r--r--tests/bugs/bug-1116503.t21
-rw-r--r--xlators/nfs/server/src/Makefile.am4
-rw-r--r--xlators/nfs/server/src/mount3.c394
-rw-r--r--xlators/nfs/server/src/mount3udp_svc.c74
-rw-r--r--xlators/nfs/server/src/nfs3-fh.c2
-rw-r--r--xlators/nfs/server/src/nfs3-fh.h2
-rw-r--r--xlators/nfs/server/src/nfs3-helpers.c4
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;
}