diff options
Diffstat (limited to 'xlators')
-rw-r--r-- | xlators/nfs/server/src/Makefile.am | 5 | ||||
-rw-r--r-- | xlators/nfs/server/src/mount3-auth.c | 641 | ||||
-rw-r--r-- | xlators/nfs/server/src/mount3-auth.h | 59 | ||||
-rw-r--r-- | xlators/nfs/server/src/mount3.h | 3 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs-mem-types.h | 1 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs3-fh.h | 3 |
6 files changed, 709 insertions, 3 deletions
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. |