From 28209283a67f13802cc0c1d3df07c676926810a2 Mon Sep 17 00:00:00 2001 From: Raghavendra Bhat Date: Fri, 19 Apr 2013 12:27:03 +0530 Subject: protocol/server: do not do root-squashing for trusted clients * As of now clients mounting within the storage pool using that machine's ip/hostname are trusted clients (i.e clients local to the glusterd). * Be careful when the request itself comes in as nfsnobody (ex: posix tests). So move the squashing part to protocol/server when it creates a new frame for the request, instead of auth part of rpc layer. * For nfs servers do root-squashing without checking if it is trusted client, as all the nfs servers would be running within the storage pool, hence will be trusted clients for the bricks. * Provide one more option for mounting which actually says root-squash should/should not happen. This value is given priority only for the trusted clients. For non trusted clients, the volume option takes the priority. But for trusted clients if root-squash should not happen, then they have to be mounted with root-squash=no option. (This is done because by default blocking root-squashing for the trusted clients will cause problems for smb and UFO clients for which the requests have to be squashed if the option is enabled). * For geo-replication and defrag clients do not do root-squashing. * Introduce a new option in open-behind for doing read after successful open. Change-Id: I8a8359840313dffc34824f3ea80a9c48375067f0 BUG: 954057 Signed-off-by: Raghavendra Bhat Reviewed-on: http://review.gluster.org/4863 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- xlators/mgmt/glusterd/src/glusterd-volgen.c | 91 ++++++++++++- xlators/mgmt/glusterd/src/glusterd-volume-set.c | 6 + xlators/mount/fuse/src/fuse-bridge.c | 22 +++ xlators/mount/fuse/src/fuse-bridge.h | 8 ++ xlators/mount/fuse/utils/mount.glusterfs.in | 13 +- xlators/performance/open-behind/src/open-behind.c | 23 +++- xlators/protocol/server/src/server-handshake.c | 2 + xlators/protocol/server/src/server-helpers.c | 157 ++++++++++++++++++++++ xlators/protocol/server/src/server-helpers.h | 2 + 9 files changed, 320 insertions(+), 4 deletions(-) (limited to 'xlators') diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index b26a7ef3d95..3bb2f9a6334 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -2517,6 +2517,9 @@ client_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo, xlator_t *xl = NULL; char *volname = NULL; glusterd_conf_t *conf = THIS->private; + char *tmp = NULL; + gf_boolean_t var = _gf_false; + gf_boolean_t ob = _gf_false; GF_ASSERT (conf); @@ -2582,7 +2585,93 @@ client_graph_builder (volgen_graph_t *graph, glusterd_volinfo_t *volinfo, } } - ret = client_graph_set_perf_options(graph, volinfo, set_dict); + /* Do not allow changing read-after-open option if root-squash is + enabled. + */ + ret = dict_get_str (set_dict, "performance.read-after-open", &tmp); + if (!ret) { + ret = dict_get_str (volinfo->dict, "server.root-squash", &tmp); + if (!ret) { + ob = _gf_false; + ret = gf_string2boolean (tmp, &ob); + if (!ret && ob) { + gf_log (THIS->name, GF_LOG_WARNING, + "root-squash is enabled. Please turn it" + " off to change read-after-open " + "option"); + ret = -1; + goto out; + } + } + } + + /* open behind causes problems when root-squash is enabled + (by allowing reads to happen even though the squashed user + does not have permissions to do so) as it fakes open to be + successful and later sends reads on anonymous fds. So when + root-squash is enabled, open-behind's option to read after + open is done is also enabled. + */ + ret = dict_get_str (set_dict, "server.root-squash", &tmp); + if (!ret) { + ret = gf_string2boolean (tmp, &var); + if (ret) + goto out; + + if (var) { + ret = dict_get_str (volinfo->dict, + "performance.read-after-open", + &tmp); + if (!ret) { + ret = gf_string2boolean (tmp, &ob); + /* go ahead with turning read-after-open on + even if string2boolean conversion fails, + OR if read-after-open option is turned off + */ + if (ret || !ob) + ret = dict_set_str (set_dict, + "performance.read-after-open", + "yes"); + } else { + ret = dict_set_str (set_dict, + "performance.read-after-open", + "yes"); + } + } else { + /* When root-squash has to be turned off, open-behind's + read-after-open option should be reset to what was + there before root-squash was turned on. If the option + cannot be found in volinfo's dict, it means that + option was not set before turning on root-squash. + */ + ob = _gf_false; + ret = dict_get_str (volinfo->dict, + "performance.read-after-open", + &tmp); + if (!ret) { + ret = gf_string2boolean (tmp, &ob); + + if (!ret && ob) { + ret = dict_set_str (set_dict, + "performance.read-after-open", + "yes"); + } + } + /* consider operation is failure only if read-after-open + option is enabled and could not set into set_dict + */ + if (!ob) + ret = 0; + } + if (ret) { + gf_log (THIS->name, GF_LOG_WARNING, "setting " + "open behind option as part of root " + "squash failed"); + goto out; + } + } + + 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 db0a6374a30..ab8cefeddad 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c @@ -711,6 +711,12 @@ struct volopt_map_entry glusterd_volopt_map[] = { .op_version = 3, .flags = OPT_FLAG_CLIENT_OPT }, + { .key = "performance.read-after-open", + .voltype = "performance/open-behind", + .option = "read-after-open", + .op_version = 3, + .flags = OPT_FLAG_CLIENT_OPT + }, { .key = "performance.read-ahead-page-count", .voltype = "performance/read-ahead", .option = "page-count", diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c index 315259ece7b..d9055468e43 100644 --- a/xlators/mount/fuse/src/fuse-bridge.c +++ b/xlators/mount/fuse/src/fuse-bridge.c @@ -5323,6 +5323,18 @@ init (xlator_t *this_xl) GF_OPTION_INIT ("congestion-threshold", priv->congestion_threshold, int32, cleanup_exit); + GF_OPTION_INIT("no-root-squash", priv->no_root_squash, bool, + cleanup_exit); + /* change the client_pid to no-root-squash pid only if the + client is none of defrag process, hadoop access and gsyncd process. + */ + if (!priv->client_pid_set) { + if (priv->no_root_squash == _gf_true) { + priv->client_pid_set = _gf_true; + priv->client_pid = GF_CLIENT_PID_NO_ROOT_SQUASH; + } + } + /* user has set only background-qlen, not congestion-threshold, use the fuse kernel driver formula to set congestion. ie, 75% */ if (dict_get (this_xl->options, "background-qlen") && @@ -5563,5 +5575,15 @@ struct volume_options options[] = { .type = GF_OPTION_TYPE_BOOL, .default_value = "yes" }, + { .key = {"no-root-squash"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "false", + .description = "This is the mount option for disabling the " + "root squash for the client irrespective of whether the root-squash " + "option for the volume is set or not. But this option is honoured " + "only for the trusted clients. For non trusted clients this value " + "does not have any affect and the volume option for root-squash is " + "honoured.", + }, { .key = {NULL} }, }; diff --git a/xlators/mount/fuse/src/fuse-bridge.h b/xlators/mount/fuse/src/fuse-bridge.h index 34794b6ea45..f1c4cb3f0d8 100644 --- a/xlators/mount/fuse/src/fuse-bridge.h +++ b/xlators/mount/fuse/src/fuse-bridge.h @@ -104,6 +104,14 @@ struct fuse_private { int32_t fopen_keep_cache; int32_t gid_cache_timeout; gf_boolean_t enable_ino32; + /* This is the mount option for disabling the root-squash for the + mount irrespective of whether the root-squash option for the + volume is set or not. But this option is honoured only for + thr trusted clients. For non trusted clients this value does + not have any affect and the volume option for root-squash is + honoured. + */ + gf_boolean_t no_root_squash; fdtable_t *fdtable; gid_cache_t gid_cache; char *fuse_mountopts; diff --git a/xlators/mount/fuse/utils/mount.glusterfs.in b/xlators/mount/fuse/utils/mount.glusterfs.in index ff6b524605a..d22f6a69b1e 100755 --- a/xlators/mount/fuse/utils/mount.glusterfs.in +++ b/xlators/mount/fuse/utils/mount.glusterfs.in @@ -171,7 +171,11 @@ start_glusterfs () cmd_line=$(echo "$cmd_line --aux-gfid-mount"); fi - # options with values start here + if [ -n "$no_root_squash" ]; then + cmd_line=$(echo "$cmd_line --no-root-squash"); + fi + +#options with values start here if [ -n "$log_level" ]; then cmd_line=$(echo "$cmd_line --log-level=$log_level"); fi @@ -442,6 +446,13 @@ with_options() "use-readdirp") use_readdirp=$value ;; + "root-squash") + if [ $value == "no" ] || + [ $value == "off" ] || + [ $value == "disable" ] || + [ $value == "false" ] ; then + no_root_squash=1; + fi ;; *) echo "Invalid option: $key" exit 0 diff --git a/xlators/performance/open-behind/src/open-behind.c b/xlators/performance/open-behind/src/open-behind.c index 29ef64364dc..742e4df3fdf 100644 --- a/xlators/performance/open-behind/src/open-behind.c +++ b/xlators/performance/open-behind/src/open-behind.c @@ -23,6 +23,11 @@ typedef struct ob_conf { like mandatory locks */ gf_boolean_t lazy_open; /* delay backend open as much as possible */ + gf_boolean_t read_after_open; /* instead of sending readvs on + anonymous fds, open the file + first and then send readv i.e + similar to what writev does + */ } ob_conf_t; @@ -367,8 +372,14 @@ ob_readv (call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, { call_stub_t *stub = NULL; fd_t *wind_fd = NULL; + ob_conf_t *conf = NULL; - wind_fd = ob_get_wind_fd (this, fd); + conf = this->private; + + if (!conf->read_after_open) + wind_fd = ob_get_wind_fd (this, fd); + else + wind_fd = fd_ref (fd); stub = fop_readv_stub (frame, default_readv_resume, wind_fd, size, offset, flags, xdata); @@ -894,6 +905,8 @@ reconfigure (xlator_t *this, dict_t *options) bool, out); GF_OPTION_RECONF ("lazy-open", conf->lazy_open, options, bool, out); + GF_OPTION_RECONF ("read-after-open", conf->read_after_open, options, + bool, out); ret = 0; out: @@ -924,7 +937,7 @@ init (xlator_t *this) GF_OPTION_INIT ("use-anonymous-fd", conf->use_anonymous_fd, bool, err); GF_OPTION_INIT ("lazy-open", conf->lazy_open, bool, err); - + GF_OPTION_INIT ("read-after-open", conf->read_after_open, bool, err); this->private = conf; return 0; @@ -996,6 +1009,12 @@ struct volume_options options[] = { "FOP arrives (e.g writev on the FD, unlink of the file). When option " "is disabled, perform backend open right after unwinding open().", }, + { .key = {"read-after-open"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "no", + .description = "read is sent only after actual open happens and real " + "fd is obtained, instead of doing on anonymous fd (similar to write)", + }, { .key = {NULL} } }; diff --git a/xlators/protocol/server/src/server-handshake.c b/xlators/protocol/server/src/server-handshake.c index d4941011da9..708acd936d9 100644 --- a/xlators/protocol/server/src/server-handshake.c +++ b/xlators/protocol/server/src/server-handshake.c @@ -448,6 +448,8 @@ server_setvolume (rpcsvc_request_t *req) if (req->trans->xl_private != client) req->trans->xl_private = client; + auth_set_username_passwd (params, config_params, client); + ret = dict_get_int32 (params, "fops-version", &fop_version); if (ret < 0) { ret = dict_set_str (reply, "ERROR", diff --git a/xlators/protocol/server/src/server-helpers.c b/xlators/protocol/server/src/server-helpers.c index b2b6c486fe1..c11011abf9f 100644 --- a/xlators/protocol/server/src/server-helpers.c +++ b/xlators/protocol/server/src/server-helpers.c @@ -302,6 +302,11 @@ get_frame_from_request (rpcsvc_request_t *req) { call_frame_t *frame = NULL; client_t *client = NULL; + client_t *tmp_client = NULL; + xlator_t *this = NULL; + server_conf_t *priv = NULL; + clienttable_t *clienttable = NULL; + unsigned int i = 0; GF_VALIDATE_OR_GOTO ("server", req, out); @@ -315,6 +320,57 @@ get_frame_from_request (rpcsvc_request_t *req) frame->root->unique = req->xid; + client = req->trans->xl_private; + this = req->trans->xl; + priv = this->private; + clienttable = this->ctx->clienttable; + + for (i = 0; i < clienttable->max_clients; i++) { + tmp_client = clienttable->cliententries[i].client; + if (client == tmp_client) { + /* for non trusted clients username and password + would not have been set. So for non trusted clients + (i.e clients not from the same machine as the brick, + and clients from outside the storage pool) + do the root-squashing. + TODO: If any client within the storage pool (i.e + mounting within a machine from the pool but using + other machine's ip/hostname from the same pool) + is present treat it as a trusted client + */ + if (!client->auth.username && req->pid != NFS_PID) + RPC_AUTH_ROOT_SQUASH (req); + + /* Problem: If we just check whether the client is + trusted client and do not do root squashing for + them, then for smb clients and UFO clients root + squashing will never happen as they use the fuse + mounts done within the trusted pool (i.e they are + trusted clients). + Solution: To fix it, do root squashing for trusted + clients also. If one wants to have a client within + the storage pool for which root-squashing does not + happen, then the client has to be mounted with + --no-root-squash option. But for defrag client and + gsyncd client do not do root-squashing. + */ + if (client->auth.username && + req->pid != GF_CLIENT_PID_NO_ROOT_SQUASH && + req->pid != GF_CLIENT_PID_GSYNCD && + req->pid != GF_CLIENT_PID_DEFRAG) + RPC_AUTH_ROOT_SQUASH (req); + + /* For nfs clients the server processes will be running + within the trusted storage pool machines. So if we + do not do root-squashing for nfs servers, thinking + that its a trusted client, then root-squashing wont + work for nfs clients. + */ + if (req->pid == NFS_PID) + RPC_AUTH_ROOT_SQUASH (req); + } + } + frame->root->uid = req->uid; frame->root->gid = req->gid; frame->root->pid = req->pid; @@ -935,3 +991,104 @@ server_ctx_get (client_t *client, xlator_t *xlator) out: return ctx; } + +int +auth_set_username_passwd (dict_t *input_params, dict_t *config_params, + client_t *client) +{ + int ret = 0; + data_t *allow_user = NULL; + data_t *passwd_data = NULL; + char *username = NULL; + char *password = NULL; + char *brick_name = NULL; + char *searchstr = NULL; + char *username_str = NULL; + char *tmp = NULL; + char *username_cpy = NULL; + + ret = dict_get_str (input_params, "username", &username); + if (ret) { + gf_log ("auth/login", GF_LOG_DEBUG, + "username not found, returning DONT-CARE"); + /* For non trusted clients username and password + will not be there. So dont reject the client. + */ + ret = 0; + goto out; + } + + ret = dict_get_str (input_params, "password", &password); + if (ret) { + gf_log ("auth/login", GF_LOG_WARNING, + "password not found, returning DONT-CARE"); + goto out; + } + + ret = dict_get_str (input_params, "remote-subvolume", &brick_name); + if (ret) { + gf_log ("auth/login", GF_LOG_ERROR, + "remote-subvolume not specified"); + ret = -1; + goto out; + } + + ret = gf_asprintf (&searchstr, "auth.login.%s.allow", brick_name); + if (-1 == ret) { + ret = 0; + goto out; + } + + allow_user = dict_get (config_params, searchstr); + GF_FREE (searchstr); + + if (allow_user) { + username_cpy = gf_strdup (allow_user->data); + if (!username_cpy) + goto out; + + username_str = strtok_r (username_cpy, " ,", &tmp); + + while (username_str) { + if (!fnmatch (username_str, username, 0)) { + ret = gf_asprintf (&searchstr, + "auth.login.%s.password", + username); + if (-1 == ret) + goto out; + + passwd_data = dict_get (config_params, + searchstr); + GF_FREE (searchstr); + + if (!passwd_data) { + gf_log ("auth/login", GF_LOG_ERROR, + "wrong username/password " + "combination"); + ret = -1; + goto out; + } + + ret = !((strcmp (data_to_str (passwd_data), + password))?0: -1); + if (!ret) { + client->auth.username = + gf_strdup (username); + client->auth.passwd = + gf_strdup (password); + } + if (ret == -1) + gf_log ("auth/login", GF_LOG_ERROR, + "wrong password for user %s", + username); + break; + } + username_str = strtok_r (NULL, " ,", &tmp); + } + } + +out: + GF_FREE (username_cpy); + + return ret; +} diff --git a/xlators/protocol/server/src/server-helpers.h b/xlators/protocol/server/src/server-helpers.h index 93ea3585102..3c257b3bcef 100644 --- a/xlators/protocol/server/src/server-helpers.h +++ b/xlators/protocol/server/src/server-helpers.h @@ -53,6 +53,8 @@ int serialize_rsp_dirent (gf_dirent_t *entries, gfs3_readdir_rsp *rsp); int serialize_rsp_direntp (gf_dirent_t *entries, gfs3_readdirp_rsp *rsp); int readdirp_rsp_cleanup (gfs3_readdirp_rsp *rsp); int readdir_rsp_cleanup (gfs3_readdir_rsp *rsp); +int auth_set_username_passwd (dict_t *input_params, dict_t *config_params, + struct _client_t *client); server_ctx_t *server_ctx_get (client_t *client, xlator_t *xlator); -- cgit