summaryrefslogtreecommitdiffstats
path: root/xlators/nfs/server/src/mount3.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/nfs/server/src/mount3.c')
-rw-r--r--xlators/nfs/server/src/mount3.c394
1 files changed, 319 insertions, 75 deletions
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;
}