[Pvfs2-developers] reworked root squash patches

Murali Vilayannur vilayann at mcs.anl.gov
Mon Sep 11 14:23:05 EDT 2006


Hey guys,
Attached is a patch that implements root squash exports, read only export,
all squash exports, nosuid mount options (All of these stem from the NFS
exports model) for PVFS2. This patch is against HEAD.
Thanks,
Murali
-------------- next part --------------
Index: include/pvfs2-types.h
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/include/pvfs2-types.h,v
retrieving revision 1.132
diff -u -r1.132 pvfs2-types.h
--- include/pvfs2-types.h	17 Aug 2006 08:11:50 -0000	1.132
+++ include/pvfs2-types.h	11 Sep 2006 18:11:17 -0000
@@ -190,13 +190,13 @@
 #define PVFS_U_READ    (1 << 8)
 /* no PVFS_U_VTX (sticky bit) */
 #define PVFS_G_SGID    (1 << 10)
-/* no PVFS_U_SGID */
+#define PVFS_U_SUID    (1 << 11)
 
 /* valid permission mask */
 #define PVFS_PERM_VALID \
 (PVFS_O_EXECUTE | PVFS_O_WRITE | PVFS_O_READ | PVFS_G_EXECUTE | \
  PVFS_G_WRITE | PVFS_G_READ | PVFS_U_EXECUTE | PVFS_U_WRITE | \
- PVFS_U_READ | PVFS_G_SGID)
+ PVFS_U_READ | PVFS_G_SGID | PVFS_U_SUID)
 
 #define PVFS_USER_ALL  (PVFS_U_EXECUTE|PVFS_U_WRITE|PVFS_U_READ)
 #define PVFS_GROUP_ALL (PVFS_G_EXECUTE|PVFS_G_WRITE|PVFS_G_READ)
Index: include/pvfs2-util.h
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/include/pvfs2-util.h,v
retrieving revision 1.44
diff -u -r1.44 pvfs2-util.h
--- include/pvfs2-util.h	11 Sep 2006 00:38:43 -0000	1.44
+++ include/pvfs2-util.h	11 Sep 2006 18:11:17 -0000
@@ -95,23 +95,23 @@
 uint32_t PVFS_util_object_to_sys_attr_mask( 
     uint32_t obj_mask);
 
-static inline int PVFS2_translate_mode(int mode)
+static inline int PVFS2_translate_mode(int mode, int suid)
 {
     int ret = 0, i = 0;
-#define NUM_MODES 10
+#define NUM_MODES 11
     static int modes[NUM_MODES] =
     {
         S_IXOTH, S_IWOTH, S_IROTH,
         S_IXGRP, S_IWGRP, S_IRGRP,
         S_IXUSR, S_IWUSR, S_IRUSR,
-        S_ISGID 
+        S_ISGID, S_ISUID
     };
     static int pvfs2_modes[NUM_MODES] =
     {
         PVFS_O_EXECUTE, PVFS_O_WRITE, PVFS_O_READ,
         PVFS_G_EXECUTE, PVFS_G_WRITE, PVFS_G_READ,
         PVFS_U_EXECUTE, PVFS_U_WRITE, PVFS_U_READ,
-        PVFS_G_SGID
+        PVFS_G_SGID,    PVFS_U_SUID
     };
 
     for(i = 0; i < NUM_MODES; i++)
@@ -120,6 +120,10 @@
         {
             ret |= pvfs2_modes[i];
         }
+    }
+    if (suid == 0 && (ret & PVFS_U_SUID))
+    {
+         ret &= ~PVFS_U_SUID;
     }
     return ret;
 #undef NUM_MODES
Index: src/apps/admin/pvfs2-cp.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/apps/admin/pvfs2-cp.c,v
retrieving revision 1.20
diff -u -r1.20 pvfs2-cp.c
--- src/apps/admin/pvfs2-cp.c	1 Aug 2006 00:27:11 -0000	1.20
+++ src/apps/admin/pvfs2-cp.c	11 Sep 2006 18:11:17 -0000
@@ -682,7 +682,7 @@
 {
     attr->owner = credentials->uid; 
     attr->group = credentials->gid;
-    attr->perms = PVFS2_translate_mode(mode);
+    attr->perms = PVFS2_translate_mode(mode, 0);
     attr->mask = (PVFS_ATTR_SYS_ALL_SETABLE);
     attr->dfile_count = nr_datafiles;
 
Index: src/apps/admin/pvfs2-fsck.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/apps/admin/pvfs2-fsck.c,v
retrieving revision 1.17
diff -u -r1.17 pvfs2-fsck.c
--- src/apps/admin/pvfs2-fsck.c	1 Aug 2006 00:27:11 -0000	1.17
+++ src/apps/admin/pvfs2-fsck.c	11 Sep 2006 18:11:18 -0000
@@ -1034,7 +1034,7 @@
     attr.owner = creds->uid;
     attr.owner = creds->uid;
     attr.group = creds->gid;
-    attr.perms = PVFS2_translate_mode(0755);
+    attr.perms = PVFS2_translate_mode(0755, 0);
     attr.mask = PVFS_ATTR_SYS_ALL_SETABLE;
 
     ret = PVFS_sys_lookup(cur_fs,
Index: src/apps/admin/pvfs2-mkdir.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/apps/admin/pvfs2-mkdir.c,v
retrieving revision 1.9
diff -u -r1.9 pvfs2-mkdir.c
--- src/apps/admin/pvfs2-mkdir.c	1 Aug 2006 00:27:11 -0000	1.9
+++ src/apps/admin/pvfs2-mkdir.c	11 Sep 2006 18:11:18 -0000
@@ -456,7 +456,7 @@
     if(!mode_requested)
     {
         mode_t mode = S_IRWXO | S_IRWXG | S_IRWXU; /* 0777 */
-        opts->mode = PVFS2_translate_mode(mode & ~PVFS_util_get_umask());
+        opts->mode = PVFS2_translate_mode(mode & ~PVFS_util_get_umask(), 0);
     }
     
     /* Allocate memory to hold the filenames */
Index: src/common/misc/server-config.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/common/misc/server-config.c,v
retrieving revision 1.91
diff -u -r1.91 server-config.c
--- src/common/misc/server-config.c	11 Sep 2006 15:42:37 -0000	1.91
+++ src/common/misc/server-config.c	11 Sep 2006 18:11:19 -0000
@@ -43,6 +43,8 @@
 static DOTCONF_CB(exit_filesystem_context);
 static DOTCONF_CB(enter_storage_hints_context);
 static DOTCONF_CB(exit_storage_hints_context);
+static DOTCONF_CB(enter_export_options_context);
+static DOTCONF_CB(exit_export_options_context);
 static DOTCONF_CB(enter_mhranges_context);
 static DOTCONF_CB(exit_mhranges_context);
 static DOTCONF_CB(enter_dhranges_context);
@@ -67,6 +69,13 @@
 static DOTCONF_CB(get_range_list);
 static DOTCONF_CB(get_bmi_module_list);
 static DOTCONF_CB(get_flow_module_list);
+
+static DOTCONF_CB(get_root_squash);
+static DOTCONF_CB(get_read_only);
+static DOTCONF_CB(get_all_squash);
+static DOTCONF_CB(get_anon_gid);
+static DOTCONF_CB(get_anon_uid);
+
 static DOTCONF_CB(get_handle_recycle_timeout_seconds);
 static DOTCONF_CB(get_flow_buffer_size_bytes);
 static DOTCONF_CB(get_flow_buffers_per_flow);
@@ -255,11 +264,11 @@
      * which the connections are going to be accepted and serviced.
      * The format of the TrustedNetwork option is:
      *
-     * TrustedNetwork bmi-network-address bmi-network-mask
+     * TrustedNetwork bmi-network-address at bmi-network-mask
      *
      * As an example:
      *
-     * TrustedNetwork tcp://192.168.4.0 tcp://255.255.255.0
+     * TrustedNetwork tcp://192.168.4.0@24
      */
     {"TrustedNetwork",ARG_LIST, get_trusted_network,NULL,
         CTX_SECURITY,NULL},
@@ -302,6 +311,19 @@
     {"</FileSystem>",ARG_NONE, exit_filesystem_context,NULL,CTX_FILESYSTEM,
         NULL},
 
+     /* Specifies the beginning of a ExportOptions context.
+      * This groups options specific to a filesystem and related to the behavior
+      * of how it gets exported to various clients. Most of these options
+      * will affect things like what uids get translated to and so on..
+      */
+     {"<ExportOptions>",ARG_NONE, enter_export_options_context, NULL,CTX_FILESYSTEM,
+         NULL},
+ 
+     /* Specifies the end-tag of the ExportOptions context.
+      */
+     {"</ExportOptions>",ARG_NONE, exit_export_options_context, NULL,CTX_EXPORT,
+         NULL},
+ 
     /* This groups
      * options specific to a filesystem and related to the behavior of the
      * storage system.  Mostly these options are passed directly to the
@@ -344,7 +366,7 @@
      */
     {"</DataHandleRanges>",ARG_NONE, exit_dhranges_context,NULL,
         CTX_DATAHANDLERANGES,NULL},
-    
+
     /* Provides a context for defining the filesystem's default
      * distribution to use and the parameters to be set for that distribution.
      *
@@ -598,6 +620,49 @@
     {"FlowBuffersPerFlow", ARG_INT,
          get_flow_buffers_per_flow, NULL, CTX_FILESYSTEM,"8"},
 
+    /* Define options that will influence the way a file-system gets exported
+     * to the rest of the world.
+     */
+
+    /* RootSquash option specifies whether the exported file-system needs to squash accesses
+     * by root. This is an optional parameter that needs to be specified as part of the ExportOptions
+     * context and is a list of BMI URL specification of client addresses for which RootSquash
+     * has to be enforced. 
+     * RootSquash tcp://192.168.2.0@24 tcp://10.0.0.* tcp://192.168.* ...
+     */
+    {"RootSquash", ARG_LIST, get_root_squash, NULL,
+        CTX_EXPORT, ""},
+
+    /* ReadOnly option specifies whether the exported file-system needs to disallow write accesses
+     * from clients or anything that modifies the state of the file-system.
+     * This is an optional parameter that needs to be specified as part of the ExportOptions
+     * context and is a list of BMI URL specification of client addresses for which ReadOnly
+     * has to be enforced.
+     * ReadOnly tcp://192.168.2.0@24 tcp://10.0.0.* tcp://192.168.* ...
+     */
+    {"ReadOnly", ARG_LIST,  get_read_only,    NULL,
+        CTX_EXPORT, ""},
+
+    /* AllSquash option specifies whether the exported file-system needs to squash all accesses
+     * to the file-system to a specified uid/gid!
+     * This is an optional parameter that needs to be specified as part of the ExportOptions
+     * context and is a list of BMI URL specification of client addresses for which AllSquash
+     * has to be enforced.
+     * AllSquash tcp://192.168.2.0@24 tcp://10.0.0.* tcp://192.168.* ...
+     */
+    {"AllSquash", ARG_LIST, get_all_squash,   NULL,
+        CTX_EXPORT, ""},
+
+    /* AnonUID and AnonGID are 2 integers that tell the servers to translate the requesting clients'
+     * uid/gid to the specified ones whenever AllSquash is specified!
+     * If these are not specified and AllSquash is specified then the uid used will be
+     * that of nobody and gid that of nobody
+     */
+    {"AnonUID",  ARG_STR,  get_anon_uid,     NULL,
+        CTX_EXPORT, "65534"},
+    {"AnonGID",  ARG_STR,  get_anon_gid,     NULL,
+        CTX_EXPORT, "65534"},
+
     /* The TROVE storage layer has a management component that deals with
      * allocating handle values for new metafiles and datafiles.  The underlying
      * trove module can be given a hint to tell it how long to wait before
@@ -1070,6 +1135,23 @@
     return NULL;
 }
 
+DOTCONF_CB(enter_export_options_context)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_EXPORT;
+
+    return PINT_dotconf_set_defaults(
+        cmd->configfile, CTX_EXPORT);
+}
+
+DOTCONF_CB(exit_export_options_context)
+{
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+    config_s->configuration_context = CTX_FILESYSTEM;
+    return NULL;
+}
 
 DOTCONF_CB(enter_mhranges_context)
 {
@@ -1302,6 +1384,286 @@
     return NULL;
 }
 
+static void free_list_of_strings(int list_count, char ***new_list)
+{
+    int i;
+
+    if (new_list && *new_list != NULL)
+    {
+        for (i = 0; i < list_count; i++)
+        {
+            free((*new_list)[i]);
+            (*new_list)[i] = NULL;
+        }
+        free(*new_list);
+        *new_list = NULL;
+    }
+    return;
+}
+
+/*
+ * Given a parsed_list containing list_count number of strings,
+ * create a new array of pointers which holds a duplicate list
+ * of all the strings present in the original parsed list.
+ * Used as a helper function by all the routines/keywords that require a list
+ * of strings as their options/arguments.
+ */
+static int get_list_of_strings(int list_count, char **parsed_list,
+        char ***new_list)
+{
+    int i;
+
+    *new_list = (char **) calloc(list_count, sizeof(char *));
+    if (*new_list == NULL)
+    {
+        errno = ENOMEM;
+        return -1;
+    }
+    for (i = 0; i < list_count; i++)
+    {
+        (*new_list)[i] = strdup(parsed_list[i]);
+        if ((*new_list)[i] == NULL)
+        {
+            break;
+        }
+    }
+    if (i != list_count)
+    {
+        int j;
+        for (j = 0; j < i; j++)
+        {
+            free((*new_list)[j]);
+            (*new_list)[j] = NULL;
+        }
+        free(*new_list);
+        *new_list = NULL;
+        errno = ENOMEM;
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * Given a set/list of BMI addresses suffixed with @ and a netmask,
+ * this function will populate a netmasks array that contains
+ * the integer subsqeuent to the @ symbol.
+ * i.e given tcp://192.168.2.0@24 we will have tcp://192.168.2.0, 24 as the netmask
+ */
+static int setup_netmasks(int count, char **bmi_address, int *netmasks)
+{
+    int i;
+    for (i = 0; i < count; i++)
+    {
+        /* 
+         * if we find a @ then we parse the 
+         * chars at the end of it and make sure
+         * that it is less than equal to 32,
+         * else we check if there is a wildcard (*)
+         * present in which case we set it to -1
+         * else we assume that it is equal to 32.
+         */
+        char *special_char = strchr(bmi_address[i], '@'), *ptr = NULL;
+        if (special_char == NULL)
+        {
+            special_char = strchr(bmi_address[i], '*');
+            if (special_char == NULL)
+                netmasks[i] = 32;
+            else
+                netmasks[i] = -1;
+        }
+        else
+        {
+            *special_char = '\0';
+            netmasks[i] = strtol(special_char + 1, &ptr, 10);
+            if (*ptr != '\0' || netmasks[i] < 0
+                    || netmasks[i] > 32)
+                return -1;
+        }
+        gossip_debug(GOSSIP_SERVER_DEBUG, "Parsed %s:%d\n", bmi_address[i], netmasks[i]);
+    }
+    return 0;
+}
+
+DOTCONF_CB(get_root_squash)
+{
+    struct filesystem_configuration_s *fs_conf = NULL;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+
+    fs_conf = (struct filesystem_configuration_s *)
+        PINT_llist_head(config_s->file_systems);
+    assert(fs_conf);
+
+    if (cmd->arg_count == 0)
+    {
+        fs_conf->exp_flags &= ~TROVE_EXP_ROOT_SQUASH;
+    }
+    else 
+    {
+        fs_conf->exp_flags |= TROVE_EXP_ROOT_SQUASH;
+        fs_conf->root_squash_netmasks = (int *) calloc(cmd->arg_count, sizeof(int));
+        if (fs_conf->root_squash_netmasks == NULL)
+        {
+            fs_conf->root_squash_count = 0;
+            return("Could not allocate memory for root_squash_netmasks\n");
+        }
+        if (get_list_of_strings(cmd->arg_count, cmd->data.list,
+                    &fs_conf->root_squash_hosts) < 0)
+        {
+            free(fs_conf->root_squash_netmasks);
+            fs_conf->root_squash_netmasks = NULL;
+            fs_conf->root_squash_count = 0;
+            return("Could not allocate memory for root_squash_hosts\n");
+        }
+        fs_conf->root_squash_count = cmd->arg_count;
+        /* Setup the netmasks */
+        if (setup_netmasks(fs_conf->root_squash_count, fs_conf->root_squash_hosts, 
+                    fs_conf->root_squash_netmasks) < 0)
+        {
+            free(fs_conf->root_squash_netmasks);
+            fs_conf->root_squash_netmasks = NULL;
+            free_list_of_strings(fs_conf->root_squash_count, &fs_conf->root_squash_hosts);
+            fs_conf->root_squash_count = 0;
+            return("Could not setup netmasks for root_squash_hosts\n");
+        }
+        gossip_debug(GOSSIP_SERVER_DEBUG, "Parsed %d RootSquash wildcard entries\n",
+                cmd->arg_count);
+    }
+    return NULL;
+}
+
+DOTCONF_CB(get_read_only)
+{
+    struct filesystem_configuration_s *fs_conf = NULL;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+
+    fs_conf = (struct filesystem_configuration_s *)
+        PINT_llist_head(config_s->file_systems);
+    assert(fs_conf);
+    
+    if (cmd->arg_count == 0)
+    {
+        fs_conf->exp_flags &= ~TROVE_EXP_READ_ONLY;
+    }
+    else
+    {
+        fs_conf->exp_flags |= TROVE_EXP_READ_ONLY;
+        fs_conf->ro_netmasks = (int *) calloc(cmd->arg_count, sizeof(int));
+        if (fs_conf->ro_netmasks == NULL)
+        {
+            fs_conf->ro_count = 0;
+            return("Could not allocate memory for ro_netmasks\n");
+        }
+        if (get_list_of_strings(cmd->arg_count, cmd->data.list,
+                    &fs_conf->ro_hosts) < 0)
+        {
+            free(fs_conf->ro_netmasks);
+            fs_conf->ro_netmasks = NULL;
+            fs_conf->ro_count = 0;
+            return("Could not allocate memory for ro_hosts\n");
+        }
+        fs_conf->ro_count  = cmd->arg_count;
+        if (setup_netmasks(fs_conf->ro_count, fs_conf->ro_hosts, fs_conf->ro_netmasks) < 0)
+        {
+            free(fs_conf->ro_netmasks);
+            fs_conf->ro_netmasks = NULL;
+            free_list_of_strings(fs_conf->ro_count, &fs_conf->ro_hosts);
+            fs_conf->ro_count = 0;
+            return("Could not setup netmasks for ro_netmasks\n");
+        }
+        gossip_debug(GOSSIP_SERVER_DEBUG, "Parsed %d ro wildcard entries\n",
+                cmd->arg_count);
+    }
+    return NULL;
+}
+
+DOTCONF_CB(get_all_squash)
+{
+    struct filesystem_configuration_s *fs_conf = NULL;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+
+    fs_conf = (struct filesystem_configuration_s *)
+        PINT_llist_head(config_s->file_systems);
+    assert(fs_conf);
+
+    if (cmd->arg_count == 0)
+    {
+        fs_conf->exp_flags &= ~TROVE_EXP_ALL_SQUASH;
+    }
+    else 
+    {
+        fs_conf->exp_flags |= TROVE_EXP_ALL_SQUASH;
+        fs_conf->all_squash_netmasks = (int *) calloc(cmd->arg_count, sizeof(int));
+        if (fs_conf->all_squash_netmasks == NULL)
+        {
+            fs_conf->all_squash_count = 0;
+            return("Could not allocate memory for all_squash_netmasks\n");
+        }
+        if (get_list_of_strings(cmd->arg_count, cmd->data.list,
+                    &fs_conf->all_squash_hosts) < 0)
+        {
+            free(fs_conf->all_squash_netmasks);
+            fs_conf->all_squash_netmasks = NULL;
+            fs_conf->all_squash_count = 0;
+            return("Could not allocate memory for all_squash_hosts\n");
+        }
+        fs_conf->all_squash_count = cmd->arg_count;
+        if (setup_netmasks(fs_conf->all_squash_count, fs_conf->all_squash_hosts, 
+                    fs_conf->all_squash_netmasks) < 0)
+        {
+            free(fs_conf->all_squash_netmasks);
+            fs_conf->all_squash_netmasks = NULL;
+            free_list_of_strings(fs_conf->all_squash_count, &fs_conf->all_squash_hosts);
+            fs_conf->all_squash_count = 0;
+            return("Could not setup netmasks for all_squash_hosts\n");
+        }
+        gossip_debug(GOSSIP_SERVER_DEBUG, "Parsed %d AllSquash wildcard entries\n", 
+                cmd->arg_count);
+    }
+    return NULL;
+}
+
+DOTCONF_CB(get_anon_uid)
+{
+    struct filesystem_configuration_s *fs_conf = NULL;
+    unsigned int tmp_var;
+    int ret = -1;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+
+    fs_conf = (struct filesystem_configuration_s *)
+        PINT_llist_head(config_s->file_systems);
+    assert(fs_conf);
+    ret = sscanf(cmd->data.str, "%u", &tmp_var);
+    if(ret != 1)
+    {
+        return("AnonUID does not have a long long unsigned value.\n");
+    }
+    fs_conf->exp_anon_uid = tmp_var;
+    return NULL;
+}
+
+DOTCONF_CB(get_anon_gid)
+{
+    struct filesystem_configuration_s *fs_conf = NULL;
+    unsigned int tmp_var;
+    int ret = -1;
+    struct server_configuration_s *config_s = 
+        (struct server_configuration_s *)cmd->context;
+
+    fs_conf = (struct filesystem_configuration_s *)
+        PINT_llist_head(config_s->file_systems);
+    assert(fs_conf);
+    ret = sscanf(cmd->data.str, "%u", &tmp_var);
+    if(ret != 1)
+    {
+        return("AnonGID does not have a unsigned value.\n");
+    }
+    fs_conf->exp_anon_gid = tmp_var;
+    return NULL;
+}
 
 DOTCONF_CB(get_bmi_module_list)
 {
@@ -1379,20 +1741,30 @@
     struct server_configuration_s *config_s = 
         (struct server_configuration_s *)cmd->context;
 
-    if (cmd->arg_count != 2)
-    {
-        return("TrustedNetwork must be of the form <Network> <Mask>\n");
-    }
-    config_s->allowed_network = strdup(cmd->data.list[0]);
-    if (config_s->allowed_network == NULL)
+    config_s->allowed_masks = (int *) calloc(cmd->arg_count, sizeof(int));
+    if (config_s->allowed_masks == NULL)
     {
-        return("Could not allocate memory for network\n");
+        config_s->allowed_networks_count = 0;
+        return("Could not allocate memory for allowed netmasks\n");
     }
-    config_s->allowed_network_mask = strdup(cmd->data.list[1]);
-    if (config_s->allowed_network_mask == NULL)
+    if (get_list_of_strings(cmd->arg_count, cmd->data.list,
+                &config_s->allowed_networks) < 0)
     {
-        free(config_s->allowed_network);
-        return("Could not allocate memory for network mask\n");
+        free(config_s->allowed_masks);
+        config_s->allowed_masks = NULL;
+        config_s->allowed_networks_count = 0;
+        return("Could not allocate memory for trusted networks\n");
+    }
+    config_s->allowed_networks_count = cmd->arg_count;
+    /* Setup netmasks */
+    if (setup_netmasks(config_s->allowed_networks_count, config_s->allowed_networks,
+                config_s->allowed_masks) < 0)
+    {
+        free(config_s->allowed_masks);
+        config_s->allowed_masks = NULL;
+        free_list_of_strings(config_s->allowed_networks_count, &config_s->allowed_networks);
+        config_s->allowed_networks_count = 0;
+        return("Parse error in netmask specification\n");
     }
     /* okay, we enable trusted network as well */
     config_s->network_enabled = 1;
@@ -2067,19 +2439,25 @@
             config_s->flow_modules = NULL;
         }
 #ifdef USE_TRUSTED
-        if (config_s->allowed_network)
+        if (config_s->allowed_networks)
         {
-            free(config_s->allowed_network);
-            config_s->allowed_network = NULL;
+            int i;
+            for (i = 0; i < config_s->allowed_networks_count; i++)
+            {
+                free(config_s->allowed_networks[i]);
+                config_s->allowed_networks[i] = NULL;
+            }
+            free(config_s->allowed_networks);
+            config_s->allowed_networks = NULL;
         }
-        if (config_s->allowed_network_mask)
+        if (config_s->allowed_masks)
         {
-            free(config_s->allowed_network_mask);
-            config_s->allowed_network_mask = NULL;
+            free(config_s->allowed_masks);
+            config_s->allowed_masks = NULL;
         }
-        if (config_s->security)
+        if (config_s->security && config_s->security_dtor)
         {
-            free(config_s->security);
+            config_s->security_dtor(config_s->security);
             config_s->security = NULL;
         }
 #endif
@@ -2305,7 +2683,39 @@
             free(fs->attr_cache_keywords);
             fs->attr_cache_keywords = NULL;
         }
-
+        /* free all ro_hosts specifications */
+        if (fs->ro_hosts)
+        {
+            free_list_of_strings(fs->ro_count, &fs->ro_hosts);
+            fs->ro_count = 0;
+        }
+        if (fs->ro_netmasks)
+        {
+            free(fs->ro_netmasks);
+            fs->ro_netmasks = NULL;
+        }
+        /* free all root_squash_hosts specifications */
+        if (fs->root_squash_hosts)
+        {
+            free_list_of_strings(fs->root_squash_count, &fs->root_squash_hosts);
+            fs->root_squash_count = 0;
+        }
+        if (fs->root_squash_netmasks)
+        {
+            free(fs->root_squash_netmasks);
+            fs->root_squash_netmasks = NULL;
+        }
+        /* free all all_squash_hosts specifications */
+        if (fs->all_squash_hosts)
+        {
+            free_list_of_strings(fs->all_squash_count, &fs->all_squash_hosts);
+            fs->all_squash_count = 0;
+        }
+        if (fs->all_squash_netmasks)
+        {
+            free(fs->all_squash_netmasks);
+            fs->all_squash_netmasks = NULL;
+        }
         free(fs);
         fs = NULL;
     }
@@ -2412,6 +2822,65 @@
             src_fs->attr_cache_max_num_elems;
         dest_fs->trove_sync_meta = src_fs->trove_sync_meta;
         dest_fs->trove_sync_data = src_fs->trove_sync_data;
+ 
+        /* copy all relevant export options */
+        dest_fs->exp_flags    = src_fs->exp_flags;
+        dest_fs->ro_count     = src_fs->ro_count;
+        dest_fs->root_squash_count = src_fs->root_squash_count;
+        dest_fs->all_squash_count = src_fs->all_squash_count;
+        if (src_fs->ro_count > 0 && src_fs->ro_hosts)
+        {
+            int i;
+            dest_fs->ro_hosts = (char **) calloc(src_fs->ro_count, sizeof(char *));
+            assert(dest_fs->ro_hosts);
+            for (i = 0; i < src_fs->ro_count; i++)
+            {
+                dest_fs->ro_hosts[i] = strdup(src_fs->ro_hosts[i]);
+                assert(dest_fs->ro_hosts[i]);
+            }
+        }
+        if (src_fs->ro_count > 0 && src_fs->ro_netmasks)
+        {
+            dest_fs->ro_netmasks = (int *) calloc(src_fs->ro_count, sizeof(int));
+            assert(dest_fs->ro_netmasks);
+            memcpy(dest_fs->ro_netmasks, src_fs->ro_netmasks, src_fs->ro_count * sizeof(int));
+        }
+        if (src_fs->root_squash_count > 0 && src_fs->root_squash_hosts)
+        {
+            int i;
+            dest_fs->root_squash_hosts = (char **) calloc(src_fs->root_squash_count, sizeof(char *));
+            assert(dest_fs->root_squash_hosts);
+            for (i = 0; i < src_fs->root_squash_count; i++)
+            {
+                dest_fs->root_squash_hosts[i] = strdup(src_fs->root_squash_hosts[i]);
+                assert(dest_fs->root_squash_hosts[i]);
+            }
+        }
+        if (src_fs->root_squash_count > 0 && src_fs->root_squash_netmasks)
+        {
+            dest_fs->root_squash_netmasks = (int *) calloc(src_fs->root_squash_count, sizeof(int));
+            assert(dest_fs->root_squash_netmasks);
+            memcpy(dest_fs->root_squash_netmasks, src_fs->root_squash_netmasks, src_fs->root_squash_count * sizeof(int));
+        }
+        if (src_fs->all_squash_count > 0 && src_fs->all_squash_hosts)
+        {
+            int i;
+            dest_fs->all_squash_hosts = (char **) calloc(src_fs->all_squash_count, sizeof(char *));
+            assert(dest_fs->all_squash_hosts);
+            for (i = 0; i < src_fs->all_squash_count; i++)
+            {
+                dest_fs->all_squash_hosts[i] = strdup(src_fs->all_squash_hosts[i]);
+                assert(dest_fs->all_squash_hosts[i]);
+            }
+        }
+        if (src_fs->all_squash_count > 0 && src_fs->all_squash_netmasks)
+        {
+            dest_fs->all_squash_netmasks = (int *) calloc(src_fs->all_squash_count, sizeof(int));
+            assert(dest_fs->all_squash_netmasks);
+            memcpy(dest_fs->all_squash_netmasks, src_fs->all_squash_netmasks, src_fs->all_squash_count * sizeof(int));
+        }
+        dest_fs->exp_anon_uid = src_fs->exp_anon_uid;
+        dest_fs->exp_anon_gid = src_fs->exp_anon_gid;
 
         dest_fs->fp_buffer_size = src_fs->fp_buffer_size;
         dest_fs->fp_buffers_per_flow = src_fs->fp_buffers_per_flow;
@@ -2570,24 +3039,26 @@
 }
 
 /*
- * Function: PINT_config_get_allowed_network
+ * Function: PINT_config_get_allowed_networks
  *
  * Params:   struct server_configuration_s *server_config
  *           int  *enabled
- *           char **allowed_network (OUT)
- *           char **allowed_netmask (OUT)
+ *           int  *allowed_network_count (OUT)
+ *           char **allowed_networks (OUT)
+ *           int *allowed_netmasks (OUT)
  *
- * Returns:  Fills up *allowed_network and *allowed_netmask
+ * Returns:  Fills up *allowed_network_count, *allowed_networks and *allowed_netmasks
  *           and returns 0 on success and -1 on failure
  *
- * Synopsis: Retrieve the allowed network address and netmask.
+ * Synopsis: Retrieve the list of allowed network addresses and netmasks
  */
 
-int PINT_config_get_allowed_network(
+int PINT_config_get_allowed_networks(
     struct server_configuration_s *config_s,
     int  *enabled,
-    char **allowed_network,
-    char **allowed_mask)
+    int  *allowed_networks_count,
+    char ***allowed_networks,
+    int  **allowed_masks)
 {
     int ret = -1;
 
@@ -2596,8 +3067,9 @@
         *enabled = config_s->network_enabled;
         if (*enabled == 1)
         {
-            *allowed_network = config_s->allowed_network;
-            *allowed_mask    = config_s->allowed_network_mask;
+            *allowed_networks_count = config_s->allowed_networks_count;
+            *allowed_networks = config_s->allowed_networks;
+            *allowed_masks    = config_s->allowed_masks;
         }
         ret = 0;
     }
Index: src/common/misc/server-config.h
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/common/misc/server-config.h,v
retrieving revision 1.54
diff -u -r1.54 server-config.h
--- src/common/misc/server-config.h	11 Sep 2006 15:42:38 -0000	1.54
+++ src/common/misc/server-config.h	11 Sep 2006 18:11:19 -0000
@@ -25,7 +25,8 @@
     CTX_DATAHANDLERANGES = (1 << 6),
     CTX_STORAGEHINTS     = (1 << 7),
     CTX_DISTRIBUTION     = (1 << 8),
-    CTX_SECURITY         = (1 << 9)
+    CTX_SECURITY         = (1 << 9),
+    CTX_EXPORT           = (1 << 10),
 };
 
 typedef struct phys_server_desc
@@ -88,6 +89,23 @@
     int fp_buffer_size;
     int fp_buffers_per_flow;
 
+    /* Export flags bitwise OR of flags specified */
+    int exp_flags;
+
+    int    ro_count;
+    char **ro_hosts;
+    int   *ro_netmasks;
+
+    int    root_squash_count;
+    char **root_squash_hosts;
+    int   *root_squash_netmasks;
+
+    int    all_squash_count;
+    char **all_squash_hosts;
+    int   *all_squash_netmasks;
+
+    PVFS_uid exp_anon_uid;
+    PVFS_gid exp_anon_gid;
 } filesystem_configuration_s;
 
 typedef struct distribution_param_configuration_s
@@ -140,9 +158,11 @@
     int           ports_enabled;    /* Should we enable trusted port connections at all? */
     unsigned long allowed_ports[2]; /* {Min, Max} value of ports from which connections will be allowed */
     int          network_enabled;   /* Should we enable trusted network connections at all? */
-    char  *allowed_network;         /* BMI address of the trusted network */
-    char  *allowed_network_mask;    /* BMI address of the trusted network mask */
+    int   allowed_networks_count;   /* Number of trusted networks parsed */
+    char  **allowed_networks;       /* BMI addresses of the trusted networks */
+    int   *allowed_masks;            /* Netmasks for each of the specified trusted network */
     void  *security;                /* BMI module specific information */
+    void  (*security_dtor)(void *); /* Destructor to free BMI module specific information */
 #endif
     int  configuration_context;
     PINT_llist *host_aliases;       /* ptrs are type host_alias_s       */
@@ -176,11 +196,12 @@
     int  *enabled,
     unsigned long *allowed_ports);
 
-int PINT_config_get_allowed_network(
+int PINT_config_get_allowed_networks(
     struct server_configuration_s *config,
     int  *enabled,
-    char **allowed_network,
-    char **allowed_mask);
+    int   *allowed_networks_count,
+    char  ***allowed_networks,
+    int   **allowed_masks);
 
 #endif
 
@@ -234,6 +255,8 @@
 int PINT_config_trim_filesystems_except(
     struct server_configuration_s *config_s,
     PVFS_fs_id fs_id);
+
+struct server_configuration_s *PINT_get_server_config(void);
 
 #ifdef __PVFS2_TROVE_SUPPORT__
 int PINT_config_pvfs2_mkspace(
Index: src/io/bmi/bmi-method-support.h
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/io/bmi/bmi-method-support.h,v
retrieving revision 1.25
diff -u -r1.25 bmi-method-support.h
--- src/io/bmi/bmi-method-support.h	22 Aug 2006 15:41:13 -0000	1.25
+++ src/io/bmi/bmi-method-support.h	11 Sep 2006 18:11:19 -0000
@@ -171,6 +171,7 @@
     void (*BMI_meth_close_context)(bmi_context_id);
     int (*BMI_meth_cancel)(bmi_op_id_t, bmi_context_id);
     const char* (*BMI_meth_rev_lookup_unexpected)(method_addr_p);
+    int (*BMI_meth_query_addr_range)(method_addr_p, const char *, int);
 };
 
 
Index: src/io/bmi/bmi.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/io/bmi/bmi.c,v
retrieving revision 1.73
diff -u -r1.73 bmi.c
--- src/io/bmi/bmi.c	22 Aug 2006 15:41:14 -0000	1.73
+++ src/io/bmi/bmi.c	11 Sep 2006 18:11:20 -0000
@@ -14,6 +14,7 @@
 #include <string.h>
 #include <assert.h>
 #include <sys/time.h>
+#include <stdio.h>
 
 #include "bmi.h"
 #include "bmi-method-support.h"
@@ -1320,6 +1321,83 @@
 	return (bmi_errno_to_pvfs(-ENOSYS));
     }
     return (0);
+}
+
+/** Given a string representation of a host/network address and a BMI
+ * address handle, return whether the BMI address handle is part of the wildcard
+ * address range specified by the string.
+ * \return 1 on success, -errno on failure and 0 if it is not part of
+ * the specified range
+ */
+int BMI_query_addr_range (PVFS_BMI_addr_t addr, const char *id_string, int netmask)
+{
+    int ret = -1;
+    int i = 0, failed = 1;
+    int provided_method_length = 0;
+    char *ptr, *provided_method_name = NULL;
+    ref_st_p tmp_ref = NULL;
+
+    if((strlen(id_string)+1) > BMI_MAX_ADDR_LEN)
+    {
+	return(bmi_errno_to_pvfs(-ENAMETOOLONG));
+    }
+    /* lookup the provided address */
+    gen_mutex_lock(&ref_mutex);
+    tmp_ref = ref_list_search_addr(cur_ref_list, addr);
+    if (!tmp_ref)
+    {
+	gen_mutex_unlock(&ref_mutex);
+	return (bmi_errno_to_pvfs(-EPROTO));
+    }
+    gen_mutex_unlock(&ref_mutex);
+
+    ptr = strchr(id_string, ':');
+    if (ptr == NULL)
+    {
+        return (bmi_errno_to_pvfs(-EINVAL));
+    }
+    ret = -EPROTO;
+    provided_method_length = (unsigned long) ptr - (unsigned long) id_string;
+    provided_method_name = (char *) calloc(provided_method_length + 1, sizeof(char));
+    if (provided_method_name == NULL)
+    {
+        return bmi_errno_to_pvfs(-ENOMEM);
+    }
+    strncpy(provided_method_name, id_string, provided_method_length);
+
+    /* Now we will run through each method looking for one that
+     * matches the specified wildcard address. 
+     */
+    i = 0;
+    gen_mutex_lock(&active_method_count_mutex);
+    while (i < active_method_count)
+    {
+        char *active_method_name = (char *) active_method_table[i]->method_name + 4;
+        /* provided name matches this interface */
+        if (!strncmp(active_method_name, provided_method_name, provided_method_length))
+        {
+            int (*meth_fnptr)(method_addr_p, const char *, int);
+            failed = 0;
+            if ((meth_fnptr = active_method_table[i]->BMI_meth_query_addr_range) == NULL)
+            {
+                ret = -ENOSYS;
+                gossip_lerr("Error: method doesn't implement querying address range/wildcards yet!\n");
+                failed = 1;
+                break;
+            }
+            /* pass it into the specific bmi layer */
+            ret = meth_fnptr(tmp_ref->method_addr, id_string, netmask);
+            if (ret < 0)
+                failed = 1;
+            break;
+        }
+	i++;
+    }
+    gen_mutex_unlock(&active_method_count_mutex);
+    free(provided_method_name);
+    if (failed)
+        return bmi_errno_to_pvfs(ret);
+    return ret;
 }
 
 /** Resolves the string representation of a host address into a BMI
Index: src/io/bmi/bmi.h
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/io/bmi/bmi.h,v
retrieving revision 1.28
diff -u -r1.28 bmi.h
--- src/io/bmi/bmi.h	22 Aug 2006 15:41:14 -0000	1.28
+++ src/io/bmi/bmi.h	11 Sep 2006 18:11:20 -0000
@@ -129,6 +129,8 @@
 
 const char* BMI_addr_rev_lookup_unexpected(PVFS_BMI_addr_t addr);
 
+int BMI_query_addr_range (PVFS_BMI_addr_t addr, const char *id_string, int netmask);
+
 int BMI_post_send_list(bmi_op_id_t * id,
 		       PVFS_BMI_addr_t dest,
 		       const void *const *buffer_list,
Index: src/io/bmi/bmi_gm/bmi-gm.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/io/bmi/bmi_gm/bmi-gm.c,v
retrieving revision 1.81
diff -u -r1.81 bmi-gm.c
--- src/io/bmi/bmi_gm/bmi-gm.c	22 Aug 2006 15:41:14 -0000	1.81
+++ src/io/bmi/bmi_gm/bmi-gm.c	11 Sep 2006 18:11:21 -0000
@@ -171,7 +171,8 @@
     .BMI_meth_open_context = BMI_gm_open_context,
     .BMI_meth_close_context = BMI_gm_close_context,
     .BMI_meth_cancel = BMI_gm_cancel,
-    .BMI_meth_rev_lookup_unexpected = NULL
+    .BMI_meth_rev_lookup_unexpected = NULL,
+    .BMI_meth_query_addr_range = NULL,
 };
 
 /* module parameters */
Index: src/io/bmi/bmi_ib/ib.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/io/bmi/bmi_ib/ib.c,v
retrieving revision 1.38
diff -u -r1.38 ib.c
--- src/io/bmi/bmi_ib/ib.c	28 Aug 2006 17:33:11 -0000	1.38
+++ src/io/bmi/bmi_ib/ib.c	11 Sep 2006 18:11:22 -0000
@@ -2018,5 +2018,6 @@
     .BMI_meth_close_context = BMI_ib_close_context,
     .BMI_meth_cancel = BMI_ib_cancel,
     .BMI_meth_rev_lookup_unexpected = BMI_ib_rev_lookup,
+	 .BMI_meth_query_addr_range = NULL,
 };
 
Index: src/io/bmi/bmi_tcp/bmi-tcp-addressing.h
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/io/bmi/bmi_tcp/bmi-tcp-addressing.h,v
retrieving revision 1.14
diff -u -r1.14 bmi-tcp-addressing.h
--- src/io/bmi/bmi_tcp/bmi-tcp-addressing.h	25 Oct 2005 18:00:58 -0000	1.14
+++ src/io/bmi/bmi_tcp/bmi-tcp-addressing.h	11 Sep 2006 18:11:22 -0000
@@ -34,8 +34,9 @@
     int                 port_enforce;
     unsigned long       ports[2];
     int                 network_enforce;
-    struct in_addr      network;
-    struct in_addr      netmask;
+    int                 network_count;
+    struct in_addr      *network;
+    struct in_addr      *netmask;
 };
 
 #endif
Index: src/io/bmi/bmi_tcp/bmi-tcp.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/io/bmi/bmi_tcp/bmi-tcp.c,v
retrieving revision 1.107
diff -u -r1.107 bmi-tcp.c
--- src/io/bmi/bmi_tcp/bmi-tcp.c	11 Sep 2006 15:42:39 -0000	1.107
+++ src/io/bmi/bmi_tcp/bmi-tcp.c	11 Sep 2006 18:11:22 -0000
@@ -40,6 +40,7 @@
 #include "pint-event.h"
 #ifdef USE_TRUSTED
 #include "server-config.h"
+#include "bmi-tcp-addressing.h"
 #endif
 #include "gen-locks.h"
 
@@ -123,6 +124,7 @@
 		     bmi_context_id context_id);
 method_addr_p BMI_tcp_method_addr_lookup(const char *id_string);
 const char* BMI_tcp_addr_rev_lookup_unexpected(method_addr_p map);
+int BMI_tcp_query_addr_range(method_addr_p, const char *, int);
 int BMI_tcp_post_send_list(bmi_op_id_t * id,
 			   method_addr_p dest,
 			   const void *const *buffer_list,
@@ -308,7 +310,8 @@
     .BMI_meth_open_context = BMI_tcp_open_context,
     .BMI_meth_close_context = BMI_tcp_close_context,
     .BMI_meth_cancel = BMI_tcp_cancel,
-    .BMI_meth_rev_lookup_unexpected = BMI_tcp_addr_rev_lookup_unexpected
+    .BMI_meth_rev_lookup_unexpected = BMI_tcp_addr_rev_lookup_unexpected,
+    .BMI_meth_query_addr_range = BMI_tcp_query_addr_range,
 };
 
 /* module parameters */
@@ -658,6 +661,75 @@
     return (0);
 }
 
+#ifdef USE_TRUSTED
+
+static struct tcp_allowed_connection_s *
+alloc_trusted_connection_info(int network_count)
+{
+    struct tcp_allowed_connection_s *tcp_allowed_connection_info = NULL;
+
+    tcp_allowed_connection_info = (struct tcp_allowed_connection_s *)
+            calloc(1, sizeof(struct tcp_allowed_connection_s));
+    if (tcp_allowed_connection_info)
+    {
+        tcp_allowed_connection_info->network =
+            (struct in_addr *) calloc(network_count, sizeof(struct in_addr));
+        if (tcp_allowed_connection_info->network == NULL)
+        {
+            free(tcp_allowed_connection_info);
+            tcp_allowed_connection_info = NULL;
+        }
+        else
+        {
+            tcp_allowed_connection_info->netmask =
+                (struct in_addr *) calloc(network_count, sizeof(struct in_addr));
+            if (tcp_allowed_connection_info->netmask == NULL)
+            {
+                free(tcp_allowed_connection_info->network);
+                free(tcp_allowed_connection_info);
+                tcp_allowed_connection_info = NULL;
+            }
+            else {
+                tcp_allowed_connection_info->network_count = network_count;
+            }
+        }
+    }
+    return tcp_allowed_connection_info;
+}
+
+static void 
+dealloc_trusted_connection_info(void* ptcp_allowed_connection_info)
+{
+    struct tcp_allowed_connection_s *tcp_allowed_connection_info =
+        (struct tcp_allowed_connection_s *) ptcp_allowed_connection_info;
+    if (tcp_allowed_connection_info)
+    {
+        free(tcp_allowed_connection_info->network);
+        tcp_allowed_connection_info->network = NULL;
+        free(tcp_allowed_connection_info->netmask);
+        tcp_allowed_connection_info->netmask = NULL;
+        free(tcp_allowed_connection_info);
+    }
+    return;
+}
+
+#endif
+
+/*
+ * This function will convert a mask_bits value to an in_addr
+ * representation. i.e for example if
+ * mask_bits was 24 then it would be 255.255.255.0
+ * if mask_bits was 22 then it would be 255.255.252.0
+ * etc
+ */
+static void convert_mask(int mask_bits, struct in_addr *mask)
+{
+   uint32_t addr = -1;
+   addr = addr & ~~(-1 << (mask_bits ? (32 - mask_bits) : 32));
+   mask->s_addr = htonl(addr);
+   return;
+}
+
 /* BMI_tcp_set_info()
  * 
  * Pass in optional parameters.
@@ -726,10 +798,13 @@
         }
         else 
         {
-            char *bmi_network = NULL, *bmi_netmask = NULL;
-            struct server_configuration_s *svc_config = (struct server_configuration_s *) inout_parameter;
-            tcp_allowed_connection = 
-                (struct tcp_allowed_connection_s *) calloc(1, sizeof(struct tcp_allowed_connection_s));
+            int    bmi_networks_count = 0;
+            char **bmi_networks = NULL;
+            int   *bmi_netmasks = NULL;
+            struct server_configuration_s *svc_config = NULL;
+
+            svc_config = (struct server_configuration_s *) inout_parameter;
+            tcp_allowed_connection = alloc_trusted_connection_info(svc_config->allowed_networks_count);
             if (tcp_allowed_connection == NULL)
             {
                 ret = -ENOMEM;
@@ -740,6 +815,7 @@
 #endif
             /* Stash this in the server_configuration_s structure. freed later on */
             svc_config->security = tcp_allowed_connection;
+            svc_config->security_dtor = &dealloc_trusted_connection_info;
             ret = 0;
             /* Fill up the list of allowed ports */
             PINT_config_get_allowed_ports(svc_config, 
@@ -761,40 +837,35 @@
                 }
             }
             ret = 0;
-            /* Retrieve the BMI network address and port */
-            PINT_config_get_allowed_network(svc_config,
+            /* Retrieve the list of BMI network addresses and masks  */
+            PINT_config_get_allowed_networks(svc_config,
                     &tcp_allowed_connection->network_enforce,
-                    &bmi_network, &bmi_netmask);
+                    &bmi_networks_count,
+                    &bmi_networks,
+                    &bmi_netmasks);
 
             /* if it was enabled, make sure that we know how to deal with it */
             if (tcp_allowed_connection->network_enforce == 1)
             {
-                char *tcp_string = NULL;
-                /* Convert the network string into an in_addr_t structure */
-                tcp_string = string_key("tcp", bmi_network);
-                if (!tcp_string)
+                int i;
+
+                for (i = 0; i < bmi_networks_count; i++)
                 {
-                    /* the string doesn't even have our info */
-                    gossip_lerr("Error: malformed tcp network address\n");
-                    ret = bmi_tcp_errno_to_pvfs(-EINVAL);
-                }
-                else {
-                    /* convert this into an in_addr_t */
-                    inet_aton(tcp_string, &tcp_allowed_connection->network);
-                    free(tcp_string);
-                    /* Do the same for the netmask as well */
-                    tcp_string = string_key("tcp", bmi_netmask);
+                    char *tcp_string = NULL;
+                    /* Convert the network string into an in_addr_t structure */
+                    tcp_string = string_key("tcp", bmi_networks[i]);
                     if (!tcp_string)
                     {
                         /* the string doesn't even have our info */
-                        gossip_lerr("Error: malformed tcp netmask\n");
+                        gossip_lerr("Error: malformed tcp network address\n");
                         ret = bmi_tcp_errno_to_pvfs(-EINVAL);
                     }
                     else {
                         /* convert this into an in_addr_t */
-                        inet_aton(tcp_string, &tcp_allowed_connection->netmask);
+                        inet_aton(tcp_string, &tcp_allowed_connection->network[i]);
                         free(tcp_string);
                     }
+                    convert_mask(bmi_netmasks[i], &tcp_allowed_connection->netmask[i]);
                 }
                 /* don't enforce anything if there were any errors */
                 if (ret != 0)
@@ -1533,6 +1604,152 @@
     return(0);
 }
 
+/*
+ * For now, we only support wildcard strings that are IP addresses
+ * and not *hostnames*!
+ */
+static int check_valid_wildcard(const char *wildcard_string, unsigned long *octets)
+{
+    int i, len = strlen(wildcard_string), last_dot = -1, octet_count = 0;
+    char str[16];
+    for (i = 0; i < len; i++)
+    {
+        char c = wildcard_string[i];
+        memset(str, 0, 16);
+        if ((c < '0' || c > '9') && c != '*' && c != '.')
+            return -EINVAL;
+        if (c == '*') {
+            if (octet_count >= 4)
+                return -EINVAL;
+            octets[octet_count++] = 256;
+        }
+        else if (c == '.')
+        {
+            char *endptr = NULL;
+            if (octet_count >= 4)
+                return -EINVAL;
+            strncpy(str, &wildcard_string[last_dot + 1], (i - last_dot - 1));
+            octets[octet_count++] = strtol(str, &endptr, 10);
+            if (*endptr != '\0' || octets[octet_count-1] >= 256)
+                return -EINVAL;
+            last_dot = i;
+        }
+    }
+    for (i = octet_count; i < 4; i++)
+    {
+         octets[i] = 256;
+    }
+    return 0;
+}
+
+/*
+ * return 1 if the addr specified is part of the wildcard specification of octet
+ * return 0 otherwise.
+ */
+static int check_octets(struct in_addr addr, unsigned long *octets)
+{
+#define B1_MASK  0xff000000
+#define B1_SHIFT 24
+#define B2_MASK  0x00ff0000
+#define B2_SHIFT 16
+#define B3_MASK  0x0000ff00
+#define B3_SHIFT 8
+#define B4_MASK  0x000000ff
+    uint32_t host_addr = ntohl(addr.s_addr);
+    /* * stands for all clients */
+    if (octets[0] == 256)
+    {
+        return 1;
+    }
+    if (((host_addr & B1_MASK) >> B1_SHIFT) != octets[0])
+    {
+        return 0;
+    }
+    if (octets[1] == 256)
+    {
+        return 1;
+    }
+    if (((host_addr & B2_MASK) >> B2_SHIFT) != octets[1])
+    {
+        return 0;
+    }
+    if (octets[2] == 256)
+    {
+        return 1;
+    }
+    if (((host_addr & B3_MASK) >> B3_SHIFT) != octets[2])
+    {
+        return 0;
+    }
+    if (octets[3] == 256)
+    {
+        return 1;
+    }
+    if ((host_addr & B4_MASK) != octets[3])
+    {
+        return 0;
+    }
+    return 1;
+#undef B1_MASK
+#undef B1_SHIFT 
+#undef B2_MASK 
+#undef B2_SHIFT
+#undef B3_MASK
+#undef B3_SHIFT
+#undef B4_MASK
+}
+/* BMI_tcp_query_addr_range()
+ * Check if a given address is within the network specified by the wildcard string!
+ * or if it is part of the subnet mask specified
+ */
+int BMI_tcp_query_addr_range(method_addr_p map, const char *wildcard_string, int netmask)
+{
+    struct tcp_addr *tcp_addr_data = map->method_data;
+    struct sockaddr_in map_addr;
+    socklen_t map_addr_len = sizeof(map_addr);
+    char *tcp_wildcard = (char *) wildcard_string + 6 /* strlen("tcp://") */;
+
+    memset(&map_addr, 0, sizeof(map_addr));
+    getsockname(tcp_addr_data->socket, (struct sockaddr *) &map_addr, &map_addr_len);
+    /* Wildcard specification */
+    if (netmask == -1)
+    {
+        unsigned long octets[4];
+        if (check_valid_wildcard(tcp_wildcard, octets) < 0)
+        {
+            gossip_lerr("Invalid wildcard specification: %s\n", tcp_wildcard);
+            return -EINVAL;
+        }
+        gossip_debug(GOSSIP_BMI_DEBUG_TCP, "Map Address is : %s, Wildcard Octets: %lu.%lu.%lu.%lu\n", inet_ntoa(map_addr.sin_addr),
+                octets[0], octets[1], octets[2], octets[3]);
+        if (check_octets(map_addr.sin_addr, octets) == 1)
+        {
+            return 1;
+        }
+    }
+    /* Netmask specification */
+    else {
+        struct sockaddr_in mask_addr, network_addr;
+        memset(&mask_addr, 0, sizeof(mask_addr));
+        memset(&network_addr, 0, sizeof(network_addr));
+        /* Convert the netmask address */
+        convert_mask(netmask, &mask_addr.sin_addr);
+        /* Invalid network address */
+        if (inet_aton(tcp_wildcard, &network_addr.sin_addr) == 0)
+        {
+            gossip_lerr("Invalid network specification: %s\n", tcp_wildcard);
+            return -EINVAL;
+        }
+        /* Matches the subnet mask! */
+        if ((map_addr.sin_addr.s_addr & mask_addr.sin_addr.s_addr)
+                == network_addr.sin_addr.s_addr)
+        {
+            return 1;
+        }
+    }
+    return 0;
+}
+
 /* BMI_tcp_addr_rev_lookup_unexpected()
  *
  * looks up an address that was initialized unexpectedly and returns a string
@@ -3141,9 +3358,14 @@
     static unsigned short my_requested_port = 1023;
     unsigned short my_local_port = 0;
     struct sockaddr_in my_local_sockaddr;
-    int len = sizeof(struct sockaddr_in);
+    socklen_t len = sizeof(struct sockaddr_in);
     memset(&my_local_sockaddr, 0, sizeof(struct sockaddr_in));
 
+    /* setup for a fast restart to avoid bind addr in use errors */
+    if (BMI_sockio_set_sockopt(tcp_addr_data->socket, SO_REUSEADDR, 1) < 0)
+    {
+        gossip_lerr("Could not set SO_REUSEADDR on local socket (port %hd)\n", my_local_port);
+    }
     if (BMI_sockio_bind_sock(tcp_addr_data->socket, my_requested_port) < 0)
     {
         gossip_lerr("Could not bind to local port %hd: %s\n", 
@@ -3159,11 +3381,6 @@
         my_local_port = ntohs(my_local_sockaddr.sin_port);
     }
     gossip_debug(GOSSIP_BMI_DEBUG_TCP, "Bound locally to port: %hd\n", my_local_port);
-    /* setup for a fast restart to avoid bind addr in use errors */
-    if (BMI_sockio_set_sockopt(tcp_addr_data->socket, SO_REUSEADDR, 1) < 0)
-    {
-        gossip_lerr("Could not set SO_REUSEADDR on local socket (port %hd)\n", my_local_port);
-    }
     return 0;
 }
 
@@ -3187,7 +3404,7 @@
 {
     char *peer_hostname = inet_ntoa(peer_sockaddr->sin_addr);
     unsigned short peer_port = ntohs(peer_sockaddr->sin_port);
-    int   what_failed   = -1;
+    int   i, what_failed   = -1;
 
     /* Don't refuse connects if there were any
      * parse errors or if it is not enabled in the config file
@@ -3205,12 +3422,20 @@
         {
             goto port_check;
         }
-        /* check the masks */
-        if ((peer_sockaddr->sin_addr.s_addr & gtcp_allowed_connection->netmask.s_addr)
-                != gtcp_allowed_connection->network.s_addr)
+        for (i = 0; i < gtcp_allowed_connection->network_count; i++)
         {
-            what_failed = 0;
+            /* check with all the masks */
+            if ((peer_sockaddr->sin_addr.s_addr & gtcp_allowed_connection->netmask[i].s_addr) 
+                    != gtcp_allowed_connection->network[i].s_addr)
+            {
+                continue;
+            }
+            else {
+                goto port_check;
+            }
         }
+        /* not from a trusted network */
+        what_failed = 0;
     }
 port_check:
     /* make sure that the client port numbers are within specified limits */
Index: src/io/trove/trove.h
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/io/trove/trove.h,v
retrieving revision 1.37
diff -u -r1.37 trove.h
--- src/io/trove/trove.h	15 Aug 2006 20:24:26 -0000	1.37
+++ src/io/trove/trove.h	11 Sep 2006 18:11:23 -0000
@@ -62,6 +62,13 @@
     TROVE_KEYVAL_HANDLE_COUNT    = 1 << 7
 };
 
+enum
+{
+    TROVE_EXP_ROOT_SQUASH = 1,
+    TROVE_EXP_READ_ONLY   = 2,
+    TROVE_EXP_ALL_SQUASH  = 4,
+};
+
 /* get/setinfo option flags */
 enum
 {
Index: src/kernel/linux-2.6/pvfs2-kernel.h
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/kernel/linux-2.6/pvfs2-kernel.h,v
retrieving revision 1.126
diff -u -r1.126 pvfs2-kernel.h
--- src/kernel/linux-2.6/pvfs2-kernel.h	18 Aug 2006 00:12:26 -0000	1.126
+++ src/kernel/linux-2.6/pvfs2-kernel.h	11 Sep 2006 18:11:23 -0000
@@ -399,6 +399,11 @@
      * requires the file system to honor acl's 
      */
     int acl;
+    /** suid option (if set) is inspired by the nfs mount option
+    * that requires the file system to honor the setuid bit of a 
+    * file if set. NOTE: this is disabled by default.
+    */
+    int suid;
 } pvfs2_mount_options_t;
 
 /** per superblock private pvfs2 info */
@@ -851,6 +856,9 @@
 #define get_acl_flag(inode)                               \
 (PVFS2_SB(inode->i_sb)->mnt_options.acl)
 
+#define get_suid_flag(inode)                              \
+(PVFS2_SB(inode->i_sb)->mnt_options.suid)
+
 #ifdef USE_MMAP_RA_CACHE
 #define clear_inode_mmap_ra_cache(inode)                  \
 do {                                                      \
@@ -925,7 +933,7 @@
     sys_attr.owner = current->fsuid;              \
     sys_attr.group = current->fsgid;              \
     sys_attr.size = 0;                            \
-    sys_attr.perms = PVFS2_translate_mode(mode);  \
+    sys_attr.perms = PVFS2_translate_mode(mode,0);  \
     sys_attr.objtype = type;                      \
     sys_attr.mask = PVFS_ATTR_SYS_ALL_SETABLE;    \
 } while(0)
@@ -949,7 +957,7 @@
     sys_attr.owner = current->fsuid;              \
     sys_attr.group = current->fsgid;              \
     sys_attr.size = 0;                            \
-    sys_attr.perms = PVFS2_translate_mode(mode);  \
+    sys_attr.perms = PVFS2_translate_mode(mode,0);  \
     sys_attr.objtype = type;                      \
     sys_attr.mask = PVFS_ATTR_SYS_ALL_SETABLE;    \
 } while(0)
Index: src/kernel/linux-2.6/pvfs2-utils.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/kernel/linux-2.6/pvfs2-utils.c,v
retrieving revision 1.134
diff -u -r1.134 pvfs2-utils.c
--- src/kernel/linux-2.6/pvfs2-utils.c	22 Aug 2006 18:58:32 -0000	1.134
+++ src/kernel/linux-2.6/pvfs2-utils.c	11 Sep 2006 18:11:24 -0000
@@ -223,6 +223,9 @@
 
         if (attrs->perms & PVFS_G_SGID)
             perm_mode |= S_ISGID;
+        /* Should we honor the suid bit of the file? */
+        if (get_suid_flag(inode) == 1 && (attrs->perms & PVFS_U_SUID))
+            perm_mode |= S_ISUID;
 
         inode->i_mode |= perm_mode;
 
@@ -294,9 +297,10 @@
 
 static inline void convert_attribute_mode_to_pvfs_sys_attr(
     int mode,
-    PVFS_sys_attr *attrs)
+    PVFS_sys_attr *attrs,
+    int suid)
 {
-    attrs->perms = PVFS2_translate_mode(mode);
+    attrs->perms = PVFS2_translate_mode(mode, suid);
     attrs->mask |= PVFS_ATTR_SYS_PERM;
 
     gossip_debug(GOSSIP_UTILS_DEBUG, "mode is %d | translated perms is %d\n", mode,
@@ -397,7 +401,7 @@
         }
 
         convert_attribute_mode_to_pvfs_sys_attr(
-            tmp_mode, attrs);
+            tmp_mode, attrs, get_suid_flag(inode));
     }
 
     return 0;
Index: src/kernel/linux-2.6/super.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/kernel/linux-2.6/super.c,v
retrieving revision 1.80
diff -u -r1.80 super.c
--- src/kernel/linux-2.6/super.c	24 Aug 2006 20:36:13 -0000	1.80
+++ src/kernel/linux-2.6/super.c	11 Sep 2006 18:11:24 -0000
@@ -21,8 +21,8 @@
     pvfs2_sb_info_t *pvfs2_sb = NULL;
     int i = 0, j = 0, num_keywords = 0, got_device = 0;
 
-    static char *keywords[] = {"intr", "acl"};
-    static int num_possible_keywords = 2;
+    static char *keywords[] = {"intr", "acl", "suid"};
+    static int num_possible_keywords = 3;
     static char options[PVFS2_MAX_NUM_OPTIONS][PVFS2_MAX_MOUNT_OPT_LEN];
 
     if (!silent)
@@ -107,6 +107,16 @@
                                         "acl specified\n");
                         }
                         pvfs2_sb->mnt_options.acl = 1;
+                        break;
+                    }
+                    else if (strncmp(options[i], "suid", 4) == 0)
+                    {
+                        if (!silent)
+                        {
+                            gossip_debug(GOSSIP_SUPER_DEBUG, "pvfs2: mount option "
+                                        "suid specified\n");
+                        }
+                        pvfs2_sb->mnt_options.suid = 1;
                         break;
                     }
                 }
Index: src/server/prelude.sm
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/server/prelude.sm,v
retrieving revision 1.61
diff -u -r1.61 prelude.sm
--- src/server/prelude.sm	17 Aug 2006 08:11:51 -0000	1.61
+++ src/server/prelude.sm	11 Sep 2006 18:11:24 -0000
@@ -182,6 +182,275 @@
     return ret;
 }
 
+static void get_fs_intent(struct PVFS_server_req *req, PVFS_fs_id *fsid, int *read_only)
+{
+    if (req == NULL)
+    {
+        *fsid = PVFS_FS_ID_NULL;
+        *read_only = -1;
+        return;
+    }
+    switch (req->op)
+    {
+        case PVFS_SERV_CREATE:
+            *fsid = req->u.create.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_REMOVE:
+            *fsid = req->u.remove.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_IO:
+            *fsid = req->u.io.fs_id;
+            *read_only = (req->u.io.io_type == PVFS_IO_READ) ? 1 : 0;
+            break;
+        case PVFS_SERV_GETATTR:
+            *fsid = req->u.getattr.fs_id;
+            *read_only = 1;
+            break;
+        case PVFS_SERV_SETATTR:
+            *fsid = req->u.setattr.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_LOOKUP_PATH:
+            *fsid = req->u.lookup_path.fs_id;
+            *read_only = 1;
+            break;
+        case PVFS_SERV_CRDIRENT:
+            *fsid = req->u.crdirent.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_RMDIRENT:
+            *fsid = req->u.rmdirent.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_CHDIRENT:
+            *fsid = req->u.chdirent.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_TRUNCATE:
+            *fsid = req->u.truncate.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_MKDIR:
+            *fsid = req->u.mkdir.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_READDIR:
+            *fsid = req->u.readdir.fs_id;
+            *read_only = 1;
+            break;
+        case PVFS_SERV_FLUSH:
+            *fsid = req->u.flush.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_MGMT_SETPARAM:
+            *fsid = req->u.mgmt_setparam.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_STATFS:
+            *fsid = req->u.statfs.fs_id;
+            *read_only = 1;
+            break;
+        case PVFS_SERV_MGMT_ITERATE_HANDLES:
+            *fsid = req->u.mgmt_iterate_handles.fs_id;
+            *read_only = 1;
+            break;
+        case PVFS_SERV_MGMT_DSPACE_INFO_LIST:
+            *fsid = req->u.mgmt_dspace_info_list.fs_id;
+            *read_only = 1;
+            break;
+        case PVFS_SERV_MGMT_REMOVE_OBJECT:
+            *fsid = req->u.mgmt_remove_object.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_MGMT_REMOVE_DIRENT:
+            *fsid = req->u.mgmt_remove_dirent.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_MGMT_GET_DIRDATA_HANDLE:
+            *fsid = req->u.mgmt_get_dirdata_handle.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_GETEATTR:
+            *fsid = req->u.geteattr.fs_id;
+            *read_only = 1;
+            break;
+        case PVFS_SERV_SETEATTR:
+            *fsid = req->u.seteattr.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_DELEATTR:
+            *fsid = req->u.deleattr.fs_id;
+            *read_only = 0;
+            break;
+        case PVFS_SERV_LISTEATTR:
+            *fsid = req->u.listeattr.fs_id;
+            *read_only = 1;
+            break;
+        case PVFS_SERV_PROTO_ERROR:
+        case PVFS_SERV_JOB_TIMER:
+        case PVFS_SERV_MGMT_EVENT_MON:
+        case PVFS_SERV_MGMT_PERF_MON:
+        case PVFS_SERV_PERF_UPDATE:
+        case PVFS_SERV_MGMT_NOOP:
+        case PVFS_SERV_WRITE_COMPLETION:
+        case PVFS_SERV_GETCONFIG:
+        default:
+            *fsid = PVFS_FS_ID_NULL;
+            *read_only = -1;
+            break;
+    }
+    return;
+}
+
+static void get_anon_ids(struct filesystem_configuration_s *fsconfig,
+    PVFS_uid *uid, PVFS_gid *gid)
+{
+    *uid = fsconfig->exp_anon_uid;
+    *gid = fsconfig->exp_anon_gid;
+    return;
+}
+
+static int iterate_all_squash_wildcards(struct filesystem_configuration_s *fsconfig,
+    PVFS_BMI_addr_t client_addr)
+{
+    int i;
+
+    for (i = 0; i < fsconfig->all_squash_count; i++)
+    {
+        gossip_debug(GOSSIP_SERVER_DEBUG, "BMI_query_addr_range %Ld, %s\n",
+            client_addr, fsconfig->all_squash_hosts[i]);
+        if (BMI_query_addr_range(client_addr, fsconfig->all_squash_hosts[i],
+                fsconfig->all_squash_netmasks[i]) == 1)
+        {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int iterate_root_squash_wildcards(struct filesystem_configuration_s *fsconfig,
+    PVFS_BMI_addr_t client_addr)
+{
+    int i;
+
+    for (i = 0; i < fsconfig->root_squash_count; i++)
+    {
+        gossip_debug(GOSSIP_SERVER_DEBUG, "BMI_query_addr_range %Ld, %s\n",
+            client_addr, fsconfig->root_squash_hosts[i]);
+        if (BMI_query_addr_range(client_addr, fsconfig->root_squash_hosts[i], 
+                fsconfig->root_squash_netmasks[i]) == 1)
+        {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+/* Translate_ids will return 1 if it did some uid/gid squashing, 0 otherwise */
+static int translate_ids(PVFS_fs_id fsid, PVFS_uid uid, PVFS_gid gid, 
+    PVFS_uid *translated_uid, PVFS_gid *translated_gid, PVFS_BMI_addr_t client_addr)
+{
+    int exp_flags = 0;
+    struct server_configuration_s *serv_config = NULL;
+    struct filesystem_configuration_s * fsconfig = NULL;
+
+    serv_config = PINT_get_server_config();
+    fsconfig = PINT_config_find_fs_id(serv_config, fsid);
+
+    if (fsconfig == NULL)
+    {
+        return 0;
+    }
+    exp_flags = fsconfig->exp_flags;
+    /* If all squash was set */
+    if (exp_flags & TROVE_EXP_ALL_SQUASH)
+    {
+        if (iterate_all_squash_wildcards(fsconfig, client_addr) == 1)
+        {
+            get_anon_ids(fsconfig, translated_uid, translated_gid);
+            gossip_debug(GOSSIP_SERVER_DEBUG,
+                "Translated ids from <%u:%u> to <%u:%u>\n",
+                uid, gid, *translated_uid, *translated_gid);
+            return 1;
+        }
+    }
+    /* if only root squash was set translate uids for root alone*/
+    if (exp_flags & TROVE_EXP_ROOT_SQUASH)
+    {
+        if (uid == 0 || gid == 0)
+        {
+            if (iterate_root_squash_wildcards(fsconfig, client_addr) == 1)
+            {
+                get_anon_ids(fsconfig, translated_uid, translated_gid);
+                gossip_debug(GOSSIP_SERVER_DEBUG,
+                    "Translated ids from <%u:%u> to <%u:%u>\n",
+                    uid, gid, *translated_uid, *translated_gid);
+                return 1;
+            }
+        }
+    }
+    /* no such translation required! */
+    *translated_uid = uid;
+    *translated_gid = gid;
+    return 0;
+}
+
+static int iterate_ro_wildcards(struct filesystem_configuration_s *fsconfig, PVFS_BMI_addr_t client_addr)
+{
+    int i;
+
+    for (i = 0; i < fsconfig->ro_count; i++)
+    {
+        gossip_debug(GOSSIP_SERVER_DEBUG, "BMI_query_addr_range %Ld, %s\n",
+            client_addr, fsconfig->ro_hosts[i]);
+        /* Does the client address match the wildcard specification and/or the netmask specification? */
+        if (BMI_query_addr_range(client_addr, fsconfig->ro_hosts[i],
+                fsconfig->ro_netmasks[i]) == 1)
+        {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+static int permit_operation(PVFS_fs_id fsid, int read_only, PVFS_BMI_addr_t client_addr)
+{ 
+    int exp_flags = 0; 
+    struct server_configuration_s *serv_config = NULL;
+    struct filesystem_configuration_s * fsconfig = NULL;
+
+    if (read_only == 1)
+    {
+        return 0;
+    }
+    serv_config = PINT_get_server_config();
+    fsconfig = PINT_config_find_fs_id(serv_config, fsid);
+
+    if (fsconfig == NULL)
+    {
+        return 0;
+    }
+    exp_flags = fsconfig->exp_flags;
+
+    /* cheap test to see if ReadOnly was even specified in the exportoptions */
+    if (!(exp_flags & TROVE_EXP_READ_ONLY))
+    {
+        return 0;
+    }
+    /* Drat. Iterate thru the list of wildcards specified in server_configuration and see
+     * the client address matches. if yes, then we deny permission
+     */
+    if (iterate_ro_wildcards(fsconfig, client_addr) == 1)
+    {
+        gossip_debug(GOSSIP_SERVER_DEBUG, 
+            "Disallowing read-write operation on a read-only exported file-system\n");
+        return -EROFS;
+    }
+    return 0;
+}
+
 /* prelude_perm_check()
  *
  * this really just marks the spot where we would want to do
@@ -193,6 +462,10 @@
 {
     PVFS_object_attr *obj_attr = NULL;
     PVFS_ds_attributes *ds_attr = NULL;
+    PVFS_uid translated_uid = s_op->req->credentials.uid;
+    PVFS_gid translated_gid = s_op->req->credentials.gid;
+    PVFS_fs_id  fsid;
+    int  rdonly = -1;
 
     /* moved gossip server debug output to end of state, so we can report
      * resulting status value.
@@ -228,6 +501,40 @@
         js_p->error_code = 0;
     }
 #endif
+    get_fs_intent(s_op->req, &fsid, &rdonly);
+    if (fsid != PVFS_FS_ID_NULL)
+    {
+        /*
+         * if we are exporting a volume readonly, disallow any operation that modifies
+         * the state of the file-system.
+         */
+        if (permit_operation(fsid, rdonly, s_op->addr) < 0)
+        {
+            js_p->error_code = -PVFS_EROFS;
+            return 1;
+        }
+        else 
+        {
+            /* Translate the uid and gid's in case we need to do some squashing based on the export and the client address */
+            if (translate_ids(fsid, s_op->req->credentials.uid, s_op->req->credentials.gid,
+                &translated_uid, &translated_gid, s_op->addr) == 1)
+            {
+                s_op->req->credentials.uid = translated_uid;
+                s_op->req->credentials.gid = translated_gid;
+                /* in the case of a setattr, translate the ids as well right here */
+                if (s_op->req->op == PVFS_SERV_SETATTR)
+                {
+                    s_op->req->u.setattr.attr.owner = translated_uid;
+                    s_op->req->u.setattr.attr.group = translated_gid;
+                }
+                else if (s_op->req->op == PVFS_SERV_MKDIR)
+                {
+                    s_op->req->u.mkdir.attr.owner = translated_uid;
+                    s_op->req->u.mkdir.attr.group = translated_gid;
+                }
+            }
+       }
+    }
 
     /* anything else we treat as a real error */
     if (js_p->error_code)
@@ -243,32 +550,32 @@
         "%d, credentials.gid = %d)\n",
         PINT_map_server_op_to_string(s_op->req->op), s_op->attr.mask,
         ((s_op->attr.mask & PVFS_ATTR_COMMON_UID) ? "yes" : "no"),
-        s_op->attr.owner, s_op->req->credentials.uid,
+        s_op->attr.owner, translated_uid,
         ((s_op->attr.mask & PVFS_ATTR_COMMON_GID) ? "yes" : "no"),
-        s_op->attr.group, s_op->req->credentials.gid);
+        s_op->attr.group, translated_gid);
     
     switch(PINT_server_req_table[s_op->req->op].perm)
     {
         case PINT_SERVER_CHECK_WRITE:
             js_p->error_code = PINT_check_mode(
-                &(s_op->attr), s_op->req->credentials.uid,
-                s_op->req->credentials.gid, PINT_ACCESS_WRITABLE);
+                &(s_op->attr), translated_uid,
+                translated_gid, PINT_ACCESS_WRITABLE);
             break;
         case PINT_SERVER_CHECK_READ:
             js_p->error_code = PINT_check_mode(
-                &(s_op->attr), s_op->req->credentials.uid,
-                s_op->req->credentials.gid, PINT_ACCESS_READABLE);
+                &(s_op->attr), translated_uid,
+                translated_gid, PINT_ACCESS_READABLE);
             break;
         case PINT_SERVER_CHECK_CRDIRENT:
             /* must also check executable after writable */
             js_p->error_code = PINT_check_mode(
-                &(s_op->attr), s_op->req->credentials.uid,
-                s_op->req->credentials.gid, PINT_ACCESS_WRITABLE);
+                &(s_op->attr), translated_uid,
+                translated_gid, PINT_ACCESS_WRITABLE);
             if(js_p->error_code == 0)
             {
                 js_p->error_code = PINT_check_mode(
-                    &(s_op->attr), s_op->req->credentials.uid,
-                    s_op->req->credentials.gid, PINT_ACCESS_EXECUTABLE);
+                    &(s_op->attr), translated_uid,
+                    translated_gid, PINT_ACCESS_EXECUTABLE);
             }
             break;
         case PINT_SERVER_CHECK_ATTR:
@@ -299,11 +606,11 @@
                 */
                 if (((s_op->attr.mask & PVFS_ATTR_COMMON_UID) &&
                      ((s_op->attr.owner == 0) ||
-                      (s_op->attr.owner == s_op->req->credentials.uid))) ||
+                      (s_op->attr.owner == translated_uid))) ||
                     (((s_op->attr.mask & PVFS_ATTR_COMMON_GID) &&
                       ((s_op->attr.group == 0) ||
-                       (s_op->attr.group == s_op->req->credentials.gid)))) ||
-                    (s_op->req->credentials.uid == 0))
+                       (s_op->attr.group == translated_gid)))) ||
+                    (translated_uid == 0))
                 {
                     js_p->error_code = 0;
                 }
Index: src/server/pvfs2-server.c
===================================================================
RCS file: /projects/cvsroot/pvfs2-1/src/server/pvfs2-server.c,v
retrieving revision 1.225
diff -u -r1.225 pvfs2-server.c
--- src/server/pvfs2-server.c	11 Sep 2006 15:42:41 -0000	1.225
+++ src/server/pvfs2-server.c	11 Sep 2006 18:11:25 -0000
@@ -408,6 +408,11 @@
         &pvfs2_small_io_sm}
 };
 
+struct server_configuration_s *PINT_get_server_config(void)
+{
+    return &server_config;
+}
+
 int main(int argc, char **argv)
 {
     int ret = -1, siglevel = 0;
@@ -1235,6 +1240,14 @@
                          "for %s: %s\n", cur_fs->file_system_name,
                          ((cur_fs->trove_sync_data == TROVE_SYNC) ?
                           "yes" : "no"));
+
+            gossip_debug(GOSSIP_SERVER_DEBUG, "Export options for "
+                         "%s:\n RootSquash %s\n AllSquash %s\n ReadOnly %s\n"
+                         " AnonUID %u\n AnonGID %u\n", cur_fs->file_system_name,
+                         (cur_fs->exp_flags & TROVE_EXP_ROOT_SQUASH) ? "yes" : "no",
+                         (cur_fs->exp_flags & TROVE_EXP_ALL_SQUASH)  ? "yes" : "no",
+                         (cur_fs->exp_flags & TROVE_EXP_READ_ONLY)   ? "yes" : "no",
+                         cur_fs->exp_anon_uid, cur_fs->exp_anon_gid);
 
             /* format and pass sync mode to the flow implementation */
             snprintf(buf, 16, "%d,%d", cur_fs->coll_id,


More information about the Pvfs2-developers mailing list