diff options
| -rwxr-xr-x | tests/bugs/bug-1053579.t | 60 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.c | 11 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volume-set.c | 13 | ||||
| -rw-r--r-- | xlators/protocol/client/src/client.c | 29 | ||||
| -rw-r--r-- | xlators/protocol/client/src/client.h | 1 | ||||
| -rw-r--r-- | xlators/protocol/server/src/server-helpers.c | 116 | ||||
| -rw-r--r-- | xlators/protocol/server/src/server.c | 34 | ||||
| -rw-r--r-- | xlators/protocol/server/src/server.h | 5 | 
8 files changed, 254 insertions, 15 deletions
diff --git a/tests/bugs/bug-1053579.t b/tests/bugs/bug-1053579.t index 0b6eb4331c1..a2d028bfa3b 100755 --- a/tests/bugs/bug-1053579.t +++ b/tests/bugs/bug-1053579.t @@ -9,19 +9,16 @@ cleanup  NEW_USER=bug1053579  NEW_UID=1053579  NEW_GID=1053579 +LAST_GID=1053779 +NEW_GIDS=${NEW_GID} -# create many groups, $NEW_USER will have 200 groups -NEW_GIDS=1053580 -groupadd -o -g ${NEW_GID} gid${NEW_GID} 2> /dev/null -for G in $(seq 1053581 1053279) +# create a user that belongs to many groups +for GID in $(seq ${NEW_GID} ${LAST_GID})  do -        groupadd -o -g ${G} gid${G} 2> /dev/null -        NEW_GIDS="${GIDS},${G}" +        groupadd -o -g ${GID} ${NEW_USER}-${GID} +        NEW_GIDS="${NEW_GIDS},${NEW_USER}-${GID}"  done - -# create a user that belongs to many groups -groupadd -o -g ${NEW_GID} gid${NEW_GID} -useradd -o -u ${NEW_UID} -g ${NEW_GID} -G ${NEW_GIDS} ${NEW_USER} +TEST useradd -o -M -u ${NEW_UID} -g ${NEW_GID} -G ${NEW_USER}-${NEW_GIDS} ${NEW_USER}  # preparation done, start the tests @@ -33,13 +30,50 @@ TEST $CLI volume start $V0  EXPECT_WITHIN 20 "1" is_nfs_export_available -# Mount volume as NFS export +# mount the volume  TEST mount -t nfs -o vers=3,nolock $H0:/$V0 $N0 +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 + +# the actual test, this used to crash +su -c "stat $N0/. > /dev/null" ${NEW_USER} +TEST [ $? -eq 0 ] + +# create a file that only a user in a high-group can access +echo 'Hello World!' > $N0/README +chgrp ${LAST_GID} $N0/README +chmod 0640 $N0/README + +su -c "cat $N0/README 2>&1 > /dev/null" ${NEW_USER} +TEST [ $? -ne 0 ] +# This passes only on build.gluster.org, not reproducible on other machines?! +#su -c "cat $M0/README 2>&1 > /dev/null" ${NEW_USER} +#TEST [ $? -ne 0 ] + +# we need to unmount before we can enable the server.manage-gids option +TEST umount $M0 -# the actual test :-) -TEST su -c '"stat /mnt/. > /dev/null"' ${USER} +# enable server.manage-gids and things should work +TEST $CLI volume set $V0 server.manage-gids on +# mount the volume again +TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 + +su -c "cat $N0/README 2>&1 > /dev/null" ${NEW_USER} +TEST [ $? -eq 0 ] +su -c "cat $M0/README 2>&1 > /dev/null" ${NEW_USER} +TEST [ $? -eq 0 ] + +# cleanup +userdel --force ${NEW_USER} +for GID in $(seq ${NEW_GID} ${LAST_GID}) +do +        groupdel ${NEW_USER}-${GID} +done + +rm -f $N0/README  TEST umount $N0 +TEST umount $M0 +  TEST $CLI volume stop $V0  TEST $CLI volume delete $V0 diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 8d7e09838a7..31af116621c 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -2583,7 +2583,16 @@ client_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo,                  }          } -	ret = client_graph_set_perf_options(graph, volinfo, set_dict); +        ret = dict_get_str_boolean (set_dict, "server.manage-gids", _gf_false); +        if (ret != -1) { +               ret = dict_set_str (set_dict, "client.send-gids", +                                   ret ? "false" : "true"); +               if (ret) +                       gf_log (THIS->name, GF_LOG_WARNING, "changing client" +                               " protocol option failed"); +        } + +        ret = client_graph_set_perf_options(graph, volinfo, set_dict);          if (ret)                  goto out; diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c index 631c73ce08e..d29e5d5a20a 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c @@ -860,6 +860,19 @@ struct volopt_map_entry glusterd_volopt_map[] = {            .type        = NO_DOC,            .op_version  = 2          }, +        { .key         = "server.manage-gids", +          .voltype     = "protocol/server", +          .op_version  = 4, +        }, +        { .key         = "client.send-gids", +          .voltype     = "protocol/client", +          .type        = NO_DOC, +          .op_version  = 4, +        }, +        { .key         = "server.gid-timeout", +          .voltype     = "protocol/server", +          .op_version  = 4, +        },          /* Performance xlators enable/disbable options */          { .key         = "performance.write-behind", diff --git a/xlators/protocol/client/src/client.c b/xlators/protocol/client/src/client.c index b0a71d3f9ea..45ef9de5fac 100644 --- a/xlators/protocol/client/src/client.c +++ b/xlators/protocol/client/src/client.c @@ -159,6 +159,8 @@ client_submit_request (xlator_t *this, void *req, call_frame_t *frame,          struct iobref  *new_iobref = NULL;          ssize_t         xdr_size   = 0;          struct rpc_req  rpcreq     = {0, }; +        uint64_t        ngroups    = 0; +        uint64_t        gid        = 0;          GF_VALIDATE_OR_GOTO ("client", this, out);          GF_VALIDATE_OR_GOTO (this->name, prog, out); @@ -225,6 +227,18 @@ client_submit_request (xlator_t *this, void *req, call_frame_t *frame,                  count = 1;          } +        /* do not send all groups if they are resolved server-side */ +        if (!conf->send_gids) { +                /* copy some values for restoring later */ +                ngroups = frame->root->ngrps; +                frame->root->ngrps = 1; +                if (ngroups <= SMALL_GROUP_COUNT) { +                        gid = frame->root->groups_small[0]; +                        frame->root->groups_small[0] = frame->root->gid; +                        frame->root->groups = frame->root->groups_small; +                } +        } +          /* Send the msg */          ret = rpc_clnt_submit (conf->rpc, prog, procnum, cbkfn, &iov, count,                                 NULL, 0, new_iobref, frame, rsphdr, rsphdr_count, @@ -247,6 +261,13 @@ client_submit_request (xlator_t *this, void *req, call_frame_t *frame,          if (start_ping)                  client_start_ping ((void *) this); +        if (!conf->send_gids) { +                /* restore previous values */ +                frame->root->ngrps = ngroups; +                if (ngroups <= SMALL_GROUP_COUNT) +                        frame->root->groups_small[0] = gid; +        } +          ret = 0;          if (new_iobref) @@ -2328,6 +2349,8 @@ build_client_config (xlator_t *this, clnt_conf_t *conf)          GF_OPTION_INIT ("filter-O_DIRECT", conf->filter_o_direct,                          bool, out); +        GF_OPTION_INIT ("send-gids", conf->send_gids, bool, out); +          ret = 0;  out:          return ret; @@ -2515,6 +2538,8 @@ reconfigure (xlator_t *this, dict_t *options)          GF_OPTION_RECONF ("filter-O_DIRECT", conf->filter_o_direct,                            options, bool, out); +        GF_OPTION_RECONF ("send-gids", conf->send_gids, options, bool, out); +          ret = client_init_grace_timer (this, options, conf);          if (ret)                  goto out; @@ -2870,5 +2895,9 @@ struct volume_options options[] = {            "still continue to cache the file. This works similar to NFS's "            "behavior of O_DIRECT",          }, +        { .key   = {"send-gids"}, +          .type  = GF_OPTION_TYPE_BOOL, +          .default_value = "on", +        },          { .key   = {NULL} },  }; diff --git a/xlators/protocol/client/src/client.h b/xlators/protocol/client/src/client.h index afab2d74fe8..b31e6172149 100644 --- a/xlators/protocol/client/src/client.h +++ b/xlators/protocol/client/src/client.h @@ -120,6 +120,7 @@ typedef struct clnt_conf {  						*/          gf_boolean_t           filter_o_direct; /* if set, filter O_DIRECT from                                                     the flags list of open() */ +        gf_boolean_t           send_gids; /* let the server resolve gids */  } clnt_conf_t;  typedef struct _client_fd_ctx { diff --git a/xlators/protocol/server/src/server-helpers.c b/xlators/protocol/server/src/server-helpers.c index b2b6c486fe1..a7e171c5537 100644 --- a/xlators/protocol/server/src/server-helpers.c +++ b/xlators/protocol/server/src/server-helpers.c @@ -15,8 +15,117 @@  #include "server.h"  #include "server-helpers.h" +#include "gidcache.h"  #include <fnmatch.h> +#include <pwd.h> +#include <grp.h> + +/* based on nfs_fix_aux_groups() */ +int +gid_resolve (server_conf_t *conf, call_stack_t *root) +{ +        int               ret = 0; +        struct passwd     mypw; +        char              mystrs[1024]; +        struct passwd    *result; +        gid_t             mygroups[GF_MAX_AUX_GROUPS]; +        gid_list_t        gl; +        const gid_list_t *agl; +        int               ngroups, i; + +        agl = gid_cache_lookup (&conf->gid_cache, root->uid, 0, 0); +        if (agl) { +                root->ngrps = agl->gl_count; +                goto fill_groups; +        } + +        ret = getpwuid_r (root->uid, &mypw, mystrs, sizeof(mystrs), &result); +        if (ret != 0) { +                gf_log("gid-cache", GF_LOG_ERROR, "getpwuid_r(%u) failed", +                       root->uid); +                return -1; +        } + +        if (!result) { +                gf_log ("gid-cache", GF_LOG_ERROR, "getpwuid_r(%u) found " +                        "nothing", root->uid); +                return -1; +        } + +        gf_log ("gid-cache", GF_LOG_TRACE, "mapped %u => %s", root->uid, +                result->pw_name); + +        ngroups = GF_MAX_AUX_GROUPS; +        ret = getgrouplist (result->pw_name, root->gid, mygroups, &ngroups); +        if (ret == -1) { +                gf_log ("gid-cache", GF_LOG_ERROR, "could not map %s to group " +                        "list (%d gids)", result->pw_name, root->ngrps); +                return -1; +        } +        root->ngrps = (uint16_t) ngroups; + +fill_groups: +        if (agl) { +                /* the gl is not complete, we only use gl.gl_list later on */ +                gl.gl_list = agl->gl_list; +        } else { +                /* setup a full gid_list_t to add it to the gid_cache */ +                gl.gl_id = root->uid; +                gl.gl_uid = root->uid; +                gl.gl_gid = root->gid; +                gl.gl_count = root->ngrps; + +                gl.gl_list = GF_MALLOC (root->ngrps * sizeof(gid_t), +                                        gf_common_mt_groups_t); +                if (gl.gl_list) +                        memcpy (gl.gl_list, mygroups, +                                sizeof(gid_t) * root->ngrps); +                else +                        return -1; +        } + +        if (root->ngrps == 0) { +                ret = 0; +                goto out; +        } + +        if (call_stack_alloc_groups (root, root->ngrps) != 0) { +                ret = -1; +                goto out; +        } + +        /* finally fill the groups from the */ +        for (i = 0; i < root->ngrps; ++i) +                root->groups[i] = gl.gl_list[i]; + +out: +        if (agl) { +                gid_cache_release (&conf->gid_cache, agl); +        } else { +                if (gid_cache_add (&conf->gid_cache, &gl) != 1) +                        GF_FREE (gl.gl_list); +        } + +        return ret; +} + +int +server_resolve_groups (call_frame_t *frame, rpcsvc_request_t *req) +{ +        xlator_t      *this = NULL; +        server_conf_t *conf = NULL; + +        GF_VALIDATE_OR_GOTO ("server", frame, out); +        GF_VALIDATE_OR_GOTO ("server", req, out); + +        this = req->trans->xl; +        conf = this->private; + +        return gid_resolve (conf, frame->root); +out: +        return -1; +}  int  server_decode_groups (call_frame_t *frame, rpcsvc_request_t *req) @@ -302,6 +411,7 @@ get_frame_from_request (rpcsvc_request_t *req)  {          call_frame_t  *frame = NULL;          client_t      *client = NULL; +        server_conf_t *conf = NULL;          GF_VALIDATE_OR_GOTO ("server", req, out); @@ -322,7 +432,11 @@ get_frame_from_request (rpcsvc_request_t *req)          frame->root->client   = client;          frame->root->lk_owner = req->lk_owner; -        server_decode_groups (frame, req); +        conf = frame->this->private; +        if (conf->server_manage_gids) +            server_resolve_groups (frame, req); +        else +            server_decode_groups (frame, req);          frame->local = req;  out: diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c index a8597ca194a..73a453c744e 100644 --- a/xlators/protocol/server/src/server.c +++ b/xlators/protocol/server/src/server.c @@ -738,6 +738,17 @@ reconfigure (xlator_t *this, dict_t *options)                  goto out;          } +        GF_OPTION_RECONF ("manage-gids", conf->server_manage_gids, options, +                          bool, out); + +        GF_OPTION_RECONF ("gid-timeout", conf->gid_cache_timeout, options, +                          int32, out); +        if (gid_cache_reconf (&conf->gid_cache, conf->gid_cache_timeout) < 0) { +                gf_log(this->name, GF_LOG_ERROR, "Failed to reconfigure group " +                        "cache."); +                goto out; +        } +          rpc_conf = conf->rpc;          if (!rpc_conf) {                  gf_log (this->name, GF_LOG_ERROR, "No rpc_conf !!!!"); @@ -865,6 +876,19 @@ init (xlator_t *this)                  goto out;          } +        ret = dict_get_str_boolean (this->options, "manage-gids", _gf_false); +        if (ret == -1) +                conf->server_manage_gids = _gf_false; +        else +                conf->server_manage_gids = ret; + +        GF_OPTION_INIT("gid-timeout", conf->gid_cache_timeout, int32, out); +        if (gid_cache_init (&conf->gid_cache, conf->gid_cache_timeout) < 0) { +                gf_log(this->name, GF_LOG_ERROR, "Failed to initialize " +                        "group cache."); +                goto out; +        } +          /* RPC related */          conf->rpc = rpcsvc_init (this, this->ctx, this->options, 0);          if (conf->rpc == NULL) { @@ -1112,6 +1136,16 @@ struct volume_options options[] = {                           "overrides the auth.allow option. By default, all"                           " connections are allowed."          }, +        { .key   = {"manage-gids"}, +          .type  = GF_OPTION_TYPE_BOOL, +          .default_value = "off", +          .description = "Resolve groups on the server-side." +        }, +        { .key = {"gid-timeout"}, +          .type = GF_OPTION_TYPE_INT, +          .default_value = "2", +          .description = "Timeout in seconds for the cached groups to expire." +        },          { .key   = {NULL} },  }; diff --git a/xlators/protocol/server/src/server.h b/xlators/protocol/server/src/server.h index 43e84921c8a..6e54ecf6d1a 100644 --- a/xlators/protocol/server/src/server.h +++ b/xlators/protocol/server/src/server.h @@ -22,6 +22,7 @@  #include "glusterfs3.h"  #include "timer.h"  #include "client_t.h" +#include "gidcache.h"  #define DEFAULT_BLOCK_SIZE         4194304   /* 4MB */  #define DEFAULT_VOLUME_FILE_PATH   CONFDIR "/glusterfs.vol" @@ -57,6 +58,10 @@ struct server_conf {          dict_t                 *auth_modules;          pthread_mutex_t         mutex;          struct list_head        xprt_list; + +        gf_boolean_t            server_manage_gids; /* resolve gids on brick */ +        gid_cache_t             gid_cache; +        int32_t                 gid_cache_timeout;  };  typedef struct server_conf server_conf_t;  | 
