summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libglusterfs/src/common-utils.c69
-rw-r--r--libglusterfs/src/common-utils.h1
-rw-r--r--xlators/nfs/server/src/Makefile.am5
-rw-r--r--xlators/nfs/server/src/mount3-auth.c641
-rw-r--r--xlators/nfs/server/src/mount3-auth.h59
-rw-r--r--xlators/nfs/server/src/mount3.h3
-rw-r--r--xlators/nfs/server/src/nfs-mem-types.h1
-rw-r--r--xlators/nfs/server/src/nfs3-fh.h3
8 files changed, 779 insertions, 3 deletions
diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c
index cfbf3191eef..6dcfc098dc2 100644
--- a/libglusterfs/src/common-utils.c
+++ b/libglusterfs/src/common-utils.c
@@ -1688,6 +1688,75 @@ out:
return ret;
}
+/**
+ * gf_is_ip_in_net -- Checks if an IP Address is in a network.
+ * A network should be specified by something like
+ * '10.5.153.0/24' (in CIDR notation).
+ *
+ * @result : Sets to true if the IP is in the network
+ * @ip_str : The IP to check
+ * @network: The network to check the IP against.
+ *
+ * @return: success: 0
+ * failure: -EINVAL for bad args, retval of inet_pton otherwise
+ */
+gf_boolean_t
+gf_is_ip_in_net (const char *network, const char *ip_str)
+{
+ unsigned long ip_buf = 0;
+ unsigned long net_ip_buf = 0;
+ unsigned long subnet_mask = 0;
+ int ret = -EINVAL;
+ char *slash = NULL;
+ char *net_ip = NULL;
+ char *subnet = NULL;
+ char *net_str = NULL;
+ int family = AF_INET;
+ gf_boolean_t result = _gf_false;
+
+ GF_ASSERT (network);
+ GF_ASSERT (ip_str);
+
+ if (strchr (network, ':'))
+ family = AF_INET6;
+ else if (strchr (network, '.'))
+ family = AF_INET;
+ else {
+ family = -1;
+ goto out;
+ }
+
+ net_str = strdupa (network);
+ slash = strchr (net_str, '/');
+ if (!slash)
+ goto out;
+ *slash = '\0';
+
+ subnet = slash + 1;
+ net_ip = net_str;
+
+ /* Convert IP address to a long */
+ ret = inet_pton (family, ip_str, &ip_buf);
+ if (ret < 0)
+ gf_log ("common-utils", GF_LOG_ERROR,
+ "inet_pton() failed with %s", strerror (errno));
+
+ /* Convert network IP address to a long */
+ ret = inet_pton (family, net_ip, &net_ip_buf);
+ if (ret < 0) {
+ gf_log ("common-utils", GF_LOG_ERROR,
+ "inet_pton() failed with %s", strerror (errno));
+ goto out;
+ }
+
+ /* Converts /x into a mask */
+ subnet_mask = (1 << atoi (subnet)) - 1;
+
+ result = ((ip_buf & subnet_mask) == (net_ip_buf & subnet_mask));
+out:
+ return result;
+}
+
char *
strtail (char *str, const char *pattern)
{
diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h
index 71ff9eab5de..64544126836 100644
--- a/libglusterfs/src/common-utils.h
+++ b/libglusterfs/src/common-utils.h
@@ -618,6 +618,7 @@ void skip_word (char **str);
char *get_nth_word (const char *str, int n);
gf_boolean_t mask_match (const uint32_t a, const uint32_t b, const uint32_t m);
+gf_boolean_t gf_is_ip_in_net (const char *network, const char *ip_str);
char valid_host_name (char *address, int length);
char valid_ipv4_address (char *address, int length, gf_boolean_t wildcard_acc);
char valid_ipv6_address (char *address, int length, gf_boolean_t wildcard_acc);
diff --git a/xlators/nfs/server/src/Makefile.am b/xlators/nfs/server/src/Makefile.am
index 94f47021178..2b0badc4fdd 100644
--- a/xlators/nfs/server/src/Makefile.am
+++ b/xlators/nfs/server/src/Makefile.am
@@ -4,13 +4,14 @@ nfsrpclibdir = $(top_srcdir)/rpc/rpc-lib/src
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 netgroups.c exports.c
+ nlmcbk_svc.c mount3udp_svc.c acl3.c netgroups.c exports.c \
+ mount3-auth.c
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 \
- acl3.h netgroups.h exports.h
+ acl3.h netgroups.h exports.h mount3-auth.h
AM_CPPFLAGS = $(GF_CPPFLAGS) \
-DLIBDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/auth\" \
diff --git a/xlators/nfs/server/src/mount3-auth.c b/xlators/nfs/server/src/mount3-auth.c
new file mode 100644
index 00000000000..25246f96ab1
--- /dev/null
+++ b/xlators/nfs/server/src/mount3-auth.c
@@ -0,0 +1,641 @@
+/*
+ Copyright 2014-present Facebook. All Rights Reserved
+
+ This file is part of GlusterFS.
+
+ Author :
+ Shreyas Siravara <shreyas.siravara@gmail.com>
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+/* This file contains code for handling mount authentication.
+ * The primary structure here is 'mnt3_auth_params' which contains
+ * 3 important fields: 1) Pointer to a netgroups file struct, 2) Pointer to an
+ * exports file struct. 3) Pointer to a mount state struct.
+ *
+ * - The auth parameter struct belongs to a mount state so the mount state
+ * pointer represents the mount state that this auth parameter struct belongs
+ * to.
+ *
+ * - Currently, the only supported mount auth parameters are an exports file
+ * and a netgroups file. The two pointers in the struct represent the files
+ * we are to authenticate against.
+ *
+ * - To initialize a struct, make a call to mnt3_auth_params_init () with a mnt
+ * state as a parameter.
+ *
+ * - To set an exports file authentication parameter, call
+ * mnt3_auth_set_exports_auth () with an exports file as a parameter.
+ *
+ * - Same goes for the netgroups file parameter, except use the netgroups file
+ * as the parameter.
+ */
+
+#include "mount3-auth.h"
+#include "exports.h"
+#include "netgroups.h"
+#include "mem-pool.h"
+
+/**
+ * mnt3_auth_params_init -- Initialize the mount3 authorization parameters
+ * and return the allocated struct. The mount3_state
+ * parameter is pointed to by a field in the struct.
+ *
+ * @ms: Mount state that is needed for auth.
+ *
+ * @return: success: Pointer to the allocated struct
+ * failure: NULL
+ *
+ * For external use.
+ */
+struct mnt3_auth_params *
+mnt3_auth_params_init (struct mount3_state *ms)
+{
+ struct mnt3_auth_params *auth_params = NULL;
+
+ auth_params = GF_MALLOC (sizeof (*auth_params),
+ gf_nfs_mt_mnt3_auth_params);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, auth_params, out);
+
+ auth_params->ngfile = NULL;
+ auth_params->expfile = NULL;
+ auth_params->ms = ms;
+out:
+ return auth_params;
+}
+
+/**
+ * mnt3_auth_params_deinit -- Free the memory used by the struct.
+ *
+ * @auth_params: Pointer to the struct we want to free
+ *
+ * For external use.
+ */
+void
+mnt3_auth_params_deinit (struct mnt3_auth_params *auth_params)
+{
+ if (!auth_params)
+ goto out;
+
+ /* Atomically set the auth params in the mount state to NULL
+ * so subsequent fops will be denied while the auth params
+ * are being cleaned up.
+ */
+ (void)__sync_lock_test_and_set (&auth_params->ms->auth_params, NULL);
+
+ ng_file_deinit (auth_params->ngfile);
+ exp_file_deinit (auth_params->expfile);
+ auth_params->ms = NULL;
+ GF_FREE (auth_params);
+out:
+ return;
+}
+
+/**
+ * mnt3_set_exports_auth -- Set the exports auth file
+ *
+ * @auth_params : Pointer to the auth params struct
+ * @filename : File name to load from disk and parse
+ *
+ * @return : success: 0
+ * failure: -1
+ *
+ * For external use.
+ */
+int
+mnt3_auth_set_exports_auth (struct mnt3_auth_params *auth_params,
+ const char *filename)
+{
+ struct exports_file *expfile = NULL;
+ struct exports_file *oldfile = NULL;
+ int ret = -EINVAL;
+
+ /* Validate args */
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, auth_params, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, filename, out);
+
+ /* Parse the exports file and set the auth parameter */
+ ret = exp_file_parse (filename, &expfile, auth_params->ms);
+ if (ret < 0) {
+ gf_log (GF_MNT_AUTH, GF_LOG_ERROR, "Failed to load & parse file"
+ " %s, see logs for more information", filename);
+ goto out;
+ }
+
+ /* Atomically set the file pointer */
+ oldfile = __sync_lock_test_and_set (&auth_params->expfile, expfile);
+ exp_file_deinit (oldfile);
+ ret = 0;
+out:
+ return ret;
+}
+
+/**
+ * mnt3_set_netgroups_auth -- Set netgroups auth file
+ *
+ * @auth_params : Pointer to the auth params struct.
+ * @filename : File name to load from disk and parse
+ *
+ * @return : success: 0
+ * failure: -1
+ *
+ * For external use.
+ */
+int
+mnt3_auth_set_netgroups_auth (struct mnt3_auth_params *auth_params,
+ const char *filename)
+{
+ struct netgroups_file *ngfile = NULL;
+ struct netgroups_file *oldfile = NULL;
+ int ret = -EINVAL;
+
+ /* Validate args */
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, auth_params, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, filename, out);
+
+ ngfile = ng_file_parse (filename);
+ if (!ngfile) {
+ gf_log (GF_MNT_AUTH, GF_LOG_ERROR, "Failed to load file"
+ " %s, see logs for more information", filename);
+ ret = -1;
+ goto out;
+ }
+
+ /* Atomically set the file pointer */
+ oldfile = __sync_lock_test_and_set (&auth_params->ngfile, ngfile);
+ ng_file_deinit (oldfile);
+ ret = 0;
+out:
+ return ret;
+}
+
+/* Struct used to pass parameters to
+ * _mnt3_auth_subnet_match () which
+ * checks if an IP matches a subnet
+ */
+struct _mnt3_subnet_match_s {
+ char *ip; /* IP address to match */
+ struct export_item **host; /* Host structure to set */
+};
+
+/**
+ * _mnt3_auth_subnet_match -- Check if an ip (specified in the parameter tmp)
+ * is in the subnet specified by key.
+ *
+ * @dict: The dict to walk
+ * @key : The key we are on
+ * @val : The value we are on
+ * @tmp : Parameter that points to the above struct
+ *
+ */
+static int
+_mnt3_auth_subnet_match (dict_t *dict, char *key, data_t *val, void *tmp)
+{
+ struct _mnt3_subnet_match_s *match = NULL;
+
+ match = (struct _mnt3_subnet_match_s *)tmp;
+
+ if (!match)
+ return 0;
+
+ if (!match->host)
+ return 0;
+
+ if (!match->ip)
+ return 0;
+
+ /* Already found the host */
+ if (*(match->host))
+ return 0;
+
+ /* Don't process anything that's not in CIDR */
+ if (!strchr (key, '/'))
+ return 0;
+
+ /* Strip out leading whitespaces */
+ while (*key == ' ')
+ key++;
+
+ /* If we found that the IP was in the network, set the host
+ * to point to the value in the dict.
+ */
+ if (gf_is_ip_in_net (key, match->ip)) {
+ *(match->host) = (struct export_item *)val->data;
+ }
+ return 0;
+}
+
+/**
+ * _find_host_in_export -- Find a host in the exports file.
+ *
+ * Case 1: FH is non-null
+ * -----------------------
+ * The lookup process is two-step: The FH has a mountid which represents the
+ * export that was mounted by the client. The export is defined as an entry in
+ * the exports file. The FH's 'mountid' is hashed in the exports file to lookup
+ * an export directory.
+ *
+ * Case 2: FH is null
+ * -------------------
+ * The lookup process is two-step: You need a directory and a hostname
+ * to do the lookup. We first lookup the export directory in the file
+ * and then do a lookup on the directory to find the host. If the host
+ * is not found, we must finally check for subnets and then do a match.
+ *
+ * @file: Exports file to lookup in
+ * @dir : Directory to do the lookup
+ * @host: Host to lookup in the directory
+ *
+ * Not for external use.
+ */
+static struct export_item *
+_mnt3_auth_check_host_in_export (const struct exports_file *file,
+ const char *dir, const char *host,
+ struct nfs3_fh *fh)
+{
+ struct export_dir *expdir = NULL;
+ struct export_item *host_s = NULL;
+ struct _mnt3_subnet_match_s snet_match_s = {0, };
+
+ /* Validate args */
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, file, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, host, out);
+
+ /* If the filehandle is defined, use that to perform authentication.
+ * All file operations that need authentication must follow this
+ * code path.
+ */
+ if (fh) {
+ expdir = exp_file_dir_from_uuid (file, fh->mountid);
+ if (!expdir)
+ goto out;
+ } else {
+ /* Get the exports directory from the exports file */
+ expdir = exp_file_get_dir (file, dir);
+ if (!expdir)
+ goto out;
+ }
+
+ /* Extract the host from the export directory */
+ host_s = exp_dir_get_host (expdir, host);
+ if (!host_s)
+ goto subnet_match;
+ else
+ goto out;
+
+ /* If the host is not found, we need to walk through the hosts
+ * in the exports directory and see if any of the "hosts" are actually
+ * networks (e.g. 10.5.153.0/24). If they are we should match the
+ * incoming network.
+ */
+subnet_match:
+ if (!expdir->hosts)
+ goto out;
+ snet_match_s.ip = (char *)host;
+ snet_match_s.host = &host_s;
+ dict_foreach (expdir->hosts, _mnt3_auth_subnet_match, &snet_match_s);
+out:
+ return host_s;
+}
+
+/* This struct represents all the parameters necessary to search through a
+ * netgroups file to find a host.
+ */
+struct ng_auth_search {
+ const char *search_for; /* strings to search for */
+ gf_boolean_t found; /* mark true once found */
+ const struct netgroups_file *file; /* netgroups file to search */
+ const char *expdir;
+ struct export_item *expitem; /* pointer to the export */
+ const struct exports_file *expfile;
+ gf_boolean_t _is_host_dict; /* searching a host dict? */
+ struct netgroup_entry *found_entry; /* the entry we found! */
+};
+
+/**
+ * __netgroup_dict_search -- Function to search the netgroups dict.
+ *
+ * @dict: The dict we are walking
+ * @key : The key we are on
+ * @val : The value associated with that key
+ * @data: Additional parameters. We pass a pointer to ng_auth_search_s
+ *
+ * This is passed as a function pointer to dict_foreach ().
+ *
+ * Not for external use.
+ */
+static int
+__netgroup_dict_search (dict_t *dict, char *key, data_t *val, void *data)
+{
+ struct ng_auth_search *ngsa = NULL;
+ struct netgroup_entry *ngentry = NULL;
+ data_t *hdata = NULL;
+
+ /* 'ngsa' is the search params */
+ ngsa = (struct ng_auth_search *)data;
+ ngentry = (struct netgroup_entry *)val->data;
+
+ if (ngsa->_is_host_dict) {
+ /* If are on a host dict, we can simply hash the search key
+ * against the host dict and see if we find anything.
+ */
+ hdata = dict_get (dict, (char *)ngsa->search_for);
+ if (hdata) {
+ /* If it was found, log the message, mark the search
+ * params dict as found and return.
+ */
+ gf_log (GF_MNT_AUTH, GF_LOG_DEBUG,
+ "key %s was hashed and found", key);
+ ngsa->found = _gf_true;
+ ngsa->found_entry = (struct netgroup_entry *)hdata->data;
+ goto out;
+ }
+ }
+
+ /* If the key is what we are searching for, mark the item as
+ * found and return.
+ */
+ if (strcmp (key, ngsa->search_for) == 0) {
+ ngsa->found = _gf_true;
+ ngsa->found_entry = ngentry;
+ goto out;
+ }
+
+ /* If we have a netgroup hosts dict, then search the dict using this
+ * same function.
+ */
+ if (ngentry->netgroup_hosts) {
+ ngsa->_is_host_dict = _gf_true;
+ dict_foreach (ngentry->netgroup_hosts, __netgroup_dict_search,
+ ngsa);
+ }
+
+ /* If that search was successful, just return */
+ if (ngsa->found)
+ goto out;
+
+ /* If we have a netgroup dict, then search the dict using this same
+ * function.
+ */
+ if (ngentry->netgroup_ngs) {
+ ngsa->_is_host_dict = _gf_false;
+ dict_foreach (ngentry->netgroup_ngs, __netgroup_dict_search,
+ ngsa);
+ }
+out:
+ return 0;
+}
+
+/**
+ * __export_dir_lookup_netgroup -- Function to search an exports directory
+ * for a host name.
+ *
+ * This function walks all the netgroups & hosts in an export directory
+ * and tries to match it with the search key. This function calls the above
+ * netgroup search function to search through the netgroups.
+ *
+ * This function is very similar to the above function, but both are necessary
+ * since we are walking two different dicts. For each netgroup in _this_ dict
+ * (the exports dict) we are going to find the corresponding netgroups dict
+ * and walk that (nested) structure until we find the host we are looking for.
+ *
+ * @dict: The dict we are walking
+ * @key : The key we are on
+ * @val : The value associated with that key
+ * @data: Additional parameters. We pass a pointer to ng_auth_search_s
+ *
+ * This is passed as a function pointer to dict_foreach ().
+ *
+ * Not for external use.
+ */
+static int
+__export_dir_lookup_netgroup (dict_t *dict, char *key, data_t *val,
+ void *data)
+{
+ struct ng_auth_search *ngsa = NULL; /* Search params */
+ struct netgroups_file *nfile = NULL; /* Netgroups file to search */
+ struct netgroup_entry *ngentry = NULL; /* Entry in the netgroups file */
+ struct export_dir *tmpdir = NULL;
+
+ ngsa = (struct ng_auth_search *)data;
+ nfile = (struct netgroups_file *)ngsa->file;
+
+ GF_ASSERT ((*key == '@'));
+
+ /* We use ++key here because keys start with '@' for ngs */
+ ngentry = ng_file_get_netgroup (nfile, (key + 1));
+ if (!ngentry) {
+ gf_log (GF_MNT_AUTH, GF_LOG_DEBUG, "%s not found in %s",
+ key, nfile->filename);
+ goto out;
+ }
+
+ tmpdir = exp_file_get_dir (ngsa->expfile, ngsa->expdir);
+ if (!tmpdir)
+ goto out;
+
+ ngsa->expitem = exp_dir_get_netgroup (tmpdir, key);
+ if (!ngsa->expitem)
+ goto out;
+
+ /* Run through the host dict */
+ if (ngentry->netgroup_hosts) {
+ ngsa->_is_host_dict = _gf_true;
+ dict_foreach (ngentry->netgroup_hosts, __netgroup_dict_search,
+ ngsa);
+ }
+
+ /* If the above search was successful, just return */
+ if (ngsa->found)
+ goto out;
+
+ /* Run through the netgroups dict */
+ if (ngentry->netgroup_ngs) {
+ ngsa->_is_host_dict = _gf_false;
+ dict_foreach (ngentry->netgroup_ngs, __netgroup_dict_search,
+ ngsa);
+ }
+out:
+ return 0;
+}
+
+/**
+ * _mnt3_auth_setup_search_param -- This function sets up an ng_auth_search
+ * struct with host and file as the parameters.
+ * Host is what we are searching for and file
+ * is what we are searching in.
+ * @params: Search params to setup
+ * @host : The host to set
+ * @nfile : The netgroups file to set
+ *
+ */
+void _mnt3_auth_setup_search_params (struct ng_auth_search *params,
+ const char *host, const char *dir,
+ const struct netgroups_file *nfile,
+ const struct exports_file *expfile)
+{
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, params, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, host, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, nfile, out);
+
+ params->search_for = host;
+ params->found = _gf_false;
+ params->file = nfile;
+ params->_is_host_dict = _gf_false;
+ params->found_entry = NULL;
+ params->expitem = NULL;
+ params->expfile = expfile;
+ params->expdir = dir;
+out:
+ return;
+}
+
+/**
+ * _mnt3_auth_find_host_in_netgroup -- Given a host name for an directory
+ * find if that hostname is in the
+ * directory's dict of netgroups.
+ * @nfile: Netgroups file to search
+ * @efile: Exports file to search
+ * @dir : The exports directory name (used to lookup in exports file)
+ * @host : The host we are searching for
+ *
+ * Search procedure:
+ *
+ * - Lookup directory string against exports file structure,
+ * get an exports directory structure.
+ * - Walk the export file structure's netgroup dict. This dict
+ * holds each netgroup that is authorized to mount that directory.
+ * - We then have to walk the netgroup structure, which is a set of
+ * nested dicts until we find the host we are looking for.
+ *
+ * @return: success: Pointer to the netgroup entry found
+ * failure: NULL
+ *
+ * Not for external use.
+ */
+static struct netgroup_entry *
+_mnt3_auth_check_host_in_netgroup (const struct mnt3_auth_params *auth_params,
+ struct nfs3_fh *fh, const char *host,
+ const char *dir, struct export_item **item)
+{
+ struct export_dir *expdir = NULL;
+ struct ng_auth_search ngsa = {0, };
+ struct netgroup_entry *found_entry = NULL;
+ struct exports_file *efile = auth_params->expfile;
+ struct netgroups_file *nfile = auth_params->ngfile;
+
+ /* Validate args */
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, nfile, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, efile, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, host, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, item, out);
+
+ if (fh) {
+ expdir = exp_file_dir_from_uuid (efile, fh->mountid);
+ if (!expdir)
+ goto out;
+ } else {
+ /* Get the exports directory */
+ expdir = exp_file_get_dir (efile, dir);
+ if (!expdir)
+ goto out;
+ }
+
+ /* Setup search struct */
+ _mnt3_auth_setup_search_params (&ngsa, host, expdir->dir_name, nfile,
+ efile);
+
+ /* Do the search */
+ dict_foreach (expdir->netgroups, __export_dir_lookup_netgroup, &ngsa);
+ found_entry = ngsa.found_entry;
+ *item = ngsa.expitem;
+out:
+ return found_entry;
+}
+
+/**
+ * check_rw_access -- Checks if the export item
+ * has read-write access.
+ *
+ * @host_item : The export item to check
+ *
+ * @return -EROFS if it does not have rw access, 0 otherwise
+ *
+ */
+int
+check_rw_access (struct export_item *item)
+{
+ struct export_options *opts = NULL;
+ int ret = -EROFS;
+
+ if (!item)
+ goto out;
+
+ opts = item->opts;
+ if (!opts)
+ goto out;
+
+ if (opts->rw)
+ ret = 0;
+out:
+ return ret;
+}
+
+/**
+ * mnt3_auth_host -- Check if a host is authorized for a directory
+ *
+ * @auth_params : Auth parameters to authenticate against
+ * @host: Host requesting the directory
+ * @dir : Directory that the host requests
+ * @fh : The filehandle passed from an fop to authenticate
+ *
+ * 'fh' is null on mount requests and 'dir' is null on fops
+ *
+ * Procedure:
+ *
+ * - Check if the host is in the exports directory.
+ * - If not, check if the host is in the netgroups file for the
+ * netgroups authorized for the exports.
+ *
+ * @return: 0 if authorized
+ * -EACCES for completely unauthorized fop
+ * -EROFS for unauthorized write operations (rm, mkdir, write) *
+ */
+int
+mnt3_auth_host (const struct mnt3_auth_params *auth_params, const char *host,
+ struct nfs3_fh *fh, const char *dir, gf_boolean_t is_write_op,
+ struct export_item **save_item)
+{
+ int auth_status_code = -EACCES;
+ struct export_item *item = NULL;
+
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, auth_params, out);
+ GF_VALIDATE_OR_GOTO (GF_MNT_AUTH, host, out);
+
+ /* Find the host in the exports file */
+ item = _mnt3_auth_check_host_in_export (auth_params->expfile, dir,
+ host, fh);
+ if (item) {
+ auth_status_code = (is_write_op) ?
+ check_rw_access (item) : 0;
+ goto out;
+ }
+
+ /* Find the host in the netgroups file for the exports directory */
+ if (_mnt3_auth_check_host_in_netgroup (auth_params, fh, host, dir,
+ &item)) {
+ auth_status_code = (is_write_op) ?
+ check_rw_access (item) : 0;
+ goto out;
+ }
+
+out:
+ if (save_item)
+ *save_item = item;
+
+ return auth_status_code;
+}
diff --git a/xlators/nfs/server/src/mount3-auth.h b/xlators/nfs/server/src/mount3-auth.h
new file mode 100644
index 00000000000..b25d4724fac
--- /dev/null
+++ b/xlators/nfs/server/src/mount3-auth.h
@@ -0,0 +1,59 @@
+/*
+ Copyright 2014-present Facebook. All Rights Reserved
+
+ This file is part of GlusterFS.
+
+ Author :
+ Shreyas Siravara <shreyas.siravara@gmail.com>
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#ifndef _MOUNT3_AUTH
+#define _MOUNT3_AUTH
+
+#include "nfs-mem-types.h"
+#include "netgroups.h"
+#include "exports.h"
+#include "mount3.h"
+#include "nfs.h"
+
+#define GF_MNT_AUTH GF_NFS"-mount3-auth"
+
+struct mnt3_auth_params {
+ struct netgroups_file *ngfile; /* The netgroup file to auth against */
+ struct exports_file *expfile; /* The export file to auth against */
+ struct mount3_state *ms; /* The mount state that owns this */
+};
+
+/* Initialize auth params struct */
+struct mnt3_auth_params *
+mnt3_auth_params_init (struct mount3_state *ms);
+
+/* Set the netgroups file to use in the auth */
+int
+mnt3_auth_set_netgroups_auth (struct mnt3_auth_params *aps,
+ const char *filename);
+
+/* Set the exports file to use in the auth */
+int
+mnt3_auth_set_exports_auth (struct mnt3_auth_params *aps, const char *filename);
+
+/* Check if a host is authorized to perform a mount / nfs-fop */
+int
+mnt3_auth_host (const struct mnt3_auth_params *aps, const char *host,
+ struct nfs3_fh *fh, const char *dir, gf_boolean_t is_write_op,
+ struct export_item **save_item);
+
+/* Free resources used by the auth params struct */
+void
+mnt3_auth_params_deinit (struct mnt3_auth_params *aps);
+
+int
+mnt3_auth_fop_options_verify (const struct mnt3_auth_params *auth_params,
+ const char *host, const char *dir);
+
+#endif /* _MOUNT3_AUTH */
diff --git a/xlators/nfs/server/src/mount3.h b/xlators/nfs/server/src/mount3.h
index 8474244f191..ed553d122ae 100644
--- a/xlators/nfs/server/src/mount3.h
+++ b/xlators/nfs/server/src/mount3.h
@@ -109,6 +109,9 @@ struct mount3_state {
/* Used to protect the mountlist. */
gf_lock_t mountlock;
+ /* Used to insert additional authentication parameters */
+ struct mnt3_auth_params *auth_params;
+
/* Set to 0 if exporting full volumes is disabled. On by default. */
gf_boolean_t export_volumes;
gf_boolean_t export_dirs;
diff --git a/xlators/nfs/server/src/nfs-mem-types.h b/xlators/nfs/server/src/nfs-mem-types.h
index 33adcf5e292..79737633d24 100644
--- a/xlators/nfs/server/src/nfs-mem-types.h
+++ b/xlators/nfs/server/src/nfs-mem-types.h
@@ -34,6 +34,7 @@ enum gf_nfs_mem_types_ {
gf_nfs_mt_list_head,
gf_nfs_mt_mnt3_resolve,
gf_nfs_mt_mnt3_export,
+ gf_nfs_mt_mnt3_auth_params,
gf_nfs_mt_int,
gf_nfs_mt_mountres3,
gf_nfs_mt_mountstat3,
diff --git a/xlators/nfs/server/src/nfs3-fh.h b/xlators/nfs/server/src/nfs3-fh.h
index b52e5d670c8..42d4eaa64d3 100644
--- a/xlators/nfs/server/src/nfs3-fh.h
+++ b/xlators/nfs/server/src/nfs3-fh.h
@@ -29,7 +29,7 @@
#define GF_NFSFH_IDENT2 'G'
#define GF_NFSFH_IDENT3 'L'
#define GF_NFSFH_IDENT_SIZE (sizeof(char) * 4)
-#define GF_NFSFH_STATIC_SIZE (GF_NFSFH_IDENT_SIZE + (2*sizeof (uuid_t)))
+#define GF_NFSFH_STATIC_SIZE (GF_NFSFH_IDENT_SIZE + (3*sizeof (uuid_t)))
#define nfs3_fh_exportid_to_index(exprtid) ((uint16_t)exprtid[15])
/* ATTENTION: Change in size of the structure below should be reflected in the
@@ -56,6 +56,7 @@ struct nfs3_fh {
/* File/dir gfid. */
uuid_t gfid;
+ uuid_t mountid;
/* This structure must be exactly NFS3_FHSIZE (64) bytes long.
Having the structure shorter results in buffer overflows
during XDR decoding.