diff options
Diffstat (limited to 'rpc/rpc-lib/src/rpcsvc-auth.c')
| -rw-r--r-- | rpc/rpc-lib/src/rpcsvc-auth.c | 561 |
1 files changed, 561 insertions, 0 deletions
diff --git a/rpc/rpc-lib/src/rpcsvc-auth.c b/rpc/rpc-lib/src/rpcsvc-auth.c new file mode 100644 index 00000000000..8e76b4188bb --- /dev/null +++ b/rpc/rpc-lib/src/rpcsvc-auth.c @@ -0,0 +1,561 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "rpcsvc.h" +#include <glusterfs/dict.h> + +extern rpcsvc_auth_t * +rpcsvc_auth_null_init(rpcsvc_t *svc, dict_t *options); + +extern rpcsvc_auth_t * +rpcsvc_auth_unix_init(rpcsvc_t *svc, dict_t *options); + +extern rpcsvc_auth_t * +rpcsvc_auth_glusterfs_init(rpcsvc_t *svc, dict_t *options); +extern rpcsvc_auth_t * +rpcsvc_auth_glusterfs_v2_init(rpcsvc_t *svc, dict_t *options); +extern rpcsvc_auth_t * +rpcsvc_auth_glusterfs_v3_init(rpcsvc_t *svc, dict_t *options); + +int +rpcsvc_auth_add_initer(struct list_head *list, char *idfier, + rpcsvc_auth_initer_t init) +{ + struct rpcsvc_auth_list *new = NULL; + + if ((!list) || (!init) || (!idfier)) + return -1; + + new = GF_CALLOC(1, sizeof(*new), gf_common_mt_rpcsvc_auth_list); + if (!new) { + return -1; + } + + new->init = init; + strncpy(new->name, idfier, sizeof(new->name) - 1); + INIT_LIST_HEAD(&new->authlist); + list_add_tail(&new->authlist, list); + return 0; +} + +int +rpcsvc_auth_add_initers(rpcsvc_t *svc) +{ + int ret = -1; + + ret = rpcsvc_auth_add_initer( + &svc->authschemes, "auth-glusterfs", + (rpcsvc_auth_initer_t)rpcsvc_auth_glusterfs_init); + if (ret == -1) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_GLUSTERFS"); + goto err; + } + + ret = rpcsvc_auth_add_initer( + &svc->authschemes, "auth-glusterfs-v2", + (rpcsvc_auth_initer_t)rpcsvc_auth_glusterfs_v2_init); + if (ret == -1) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_GLUSTERFS-v2"); + goto err; + } + + ret = rpcsvc_auth_add_initer( + &svc->authschemes, "auth-glusterfs-v3", + (rpcsvc_auth_initer_t)rpcsvc_auth_glusterfs_v3_init); + if (ret == -1) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_GLUSTERFS-v3"); + goto err; + } + + ret = rpcsvc_auth_add_initer(&svc->authschemes, "auth-unix", + (rpcsvc_auth_initer_t)rpcsvc_auth_unix_init); + if (ret == -1) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_UNIX"); + goto err; + } + + ret = rpcsvc_auth_add_initer(&svc->authschemes, "auth-null", + (rpcsvc_auth_initer_t)rpcsvc_auth_null_init); + if (ret == -1) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_NULL"); + goto err; + } + + ret = 0; +err: + return ret; +} + +int +rpcsvc_auth_init_auth(rpcsvc_t *svc, dict_t *options, + struct rpcsvc_auth_list *authitem) +{ + int ret = -1; + + if ((!svc) || (!options) || (!authitem)) + return -1; + + if (!authitem->init) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "No init function defined"); + ret = -1; + goto err; + } + + authitem->auth = authitem->init(svc, options); + if (!authitem->auth) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, + "Registration of auth failed:" + " %s", + authitem->name); + ret = -1; + goto err; + } + + authitem->enable = 1; + gf_log(GF_RPCSVC, GF_LOG_TRACE, "Authentication enabled: %s", + authitem->auth->authname); + + ret = 0; +err: + return ret; +} + +int +rpcsvc_auth_init_auths(rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; + struct rpcsvc_auth_list *auth = NULL; + struct rpcsvc_auth_list *tmp = NULL; + + if (!svc) + return -1; + + if (list_empty(&svc->authschemes)) { + gf_log(GF_RPCSVC, GF_LOG_WARNING, "No authentication!"); + ret = 0; + goto err; + } + + /* If auth null and sys are not disabled by the user, we must enable + * it by default. This is a globally default rule, the user is still + * allowed to disable the two for particular subvolumes. + */ + if (!dict_get(options, "rpc-auth.auth-null")) { + ret = dict_set_str(options, "rpc-auth.auth-null", "on"); + if (ret) + gf_log("rpc-auth", GF_LOG_DEBUG, "dict_set failed for 'auth-nill'"); + } + + if (!dict_get(options, "rpc-auth.auth-unix")) { + ret = dict_set_str(options, "rpc-auth.auth-unix", "on"); + if (ret) + gf_log("rpc-auth", GF_LOG_DEBUG, "dict_set failed for 'auth-unix'"); + } + + if (!dict_get(options, "rpc-auth.auth-glusterfs")) { + ret = dict_set_str(options, "rpc-auth.auth-glusterfs", "on"); + if (ret) + gf_log("rpc-auth", GF_LOG_DEBUG, "dict_set failed for 'auth-unix'"); + } + + list_for_each_entry_safe(auth, tmp, &svc->authschemes, authlist) + { + ret = rpcsvc_auth_init_auth(svc, options, auth); + if (ret == -1) + goto err; + } + + ret = 0; +err: + return ret; +} + +int +rpcsvc_set_addr_namelookup(rpcsvc_t *svc, dict_t *options) +{ + int ret; + static char *addrlookup_key = "rpc-auth.addr.namelookup"; + + if (!svc || !options) + return (-1); + + /* By default it's disabled */ + ret = dict_get_str_boolean(options, addrlookup_key, _gf_false); + if (ret < 0) { + svc->addr_namelookup = _gf_false; + } else { + svc->addr_namelookup = ret; + } + + if (svc->addr_namelookup) + gf_log(GF_RPCSVC, GF_LOG_DEBUG, "Addr-Name lookup enabled"); + + return (0); +} + +int +rpcsvc_set_allow_insecure(rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; + char *allow_insecure_str = NULL; + gf_boolean_t is_allow_insecure = _gf_false; + + GF_ASSERT(svc); + GF_ASSERT(options); + + ret = dict_get_str(options, "rpc-auth-allow-insecure", &allow_insecure_str); + if (0 == ret) { + ret = gf_string2boolean(allow_insecure_str, &is_allow_insecure); + if (0 == ret) { + if (_gf_true == is_allow_insecure) + svc->allow_insecure = 1; + else + svc->allow_insecure = 0; + } + } else { + /* By default set allow-insecure to true */ + svc->allow_insecure = 1; + + /* setting in options for the sake of functions that look + * configuration params for allow insecure, eg: gf_auth + */ + ret = dict_set_str(options, "rpc-auth-allow-insecure", "on"); + if (ret < 0) + gf_log("rpc-auth", GF_LOG_DEBUG, + "dict_set failed for 'allow-insecure'"); + } + + return ret; +} + +int +rpcsvc_set_root_squash(rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; + uid_t anonuid = -1; + gid_t anongid = -1; + + GF_ASSERT(svc); + GF_ASSERT(options); + + ret = dict_get_str_boolean(options, "root-squash", 0); + if (ret != -1) + svc->root_squash = ret; + else + svc->root_squash = _gf_false; + + ret = dict_get_uint32(options, "anonuid", &anonuid); + if (!ret) + svc->anonuid = anonuid; + else + svc->anonuid = RPC_NOBODY_UID; + + ret = dict_get_uint32(options, "anongid", &anongid); + if (!ret) + svc->anongid = anongid; + else + svc->anongid = RPC_NOBODY_GID; + + if (svc->root_squash) + gf_log(GF_RPCSVC, GF_LOG_DEBUG, + "root squashing enabled " + "(uid=%d, gid=%d)", + svc->anonuid, svc->anongid); + + return 0; +} + +int +rpcsvc_set_all_squash(rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; + + uid_t anonuid = -1; + gid_t anongid = -1; + + GF_ASSERT(svc); + GF_ASSERT(options); + + ret = dict_get_str_boolean(options, "all-squash", 0); + if (ret != -1) + svc->all_squash = ret; + else + svc->all_squash = _gf_false; + + ret = dict_get_uint32(options, "anonuid", &anonuid); + if (!ret) + svc->anonuid = anonuid; + else + svc->anonuid = RPC_NOBODY_UID; + + ret = dict_get_uint32(options, "anongid", &anongid); + if (!ret) + svc->anongid = anongid; + else + svc->anongid = RPC_NOBODY_GID; + + if (svc->all_squash) + gf_log(GF_RPCSVC, GF_LOG_DEBUG, + "all squashing enabled " + "(uid=%d, gid=%d)", + svc->anonuid, svc->anongid); + + return 0; +} + +int +rpcsvc_auth_init(rpcsvc_t *svc, dict_t *options) +{ + int ret = -1; + + if ((!svc) || (!options)) + return -1; + + (void)rpcsvc_set_allow_insecure(svc, options); + (void)rpcsvc_set_root_squash(svc, options); + (void)rpcsvc_set_all_squash(svc, options); + (void)rpcsvc_set_addr_namelookup(svc, options); + ret = rpcsvc_auth_add_initers(svc); + if (ret == -1) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "Failed to add initers"); + goto out; + } + + ret = rpcsvc_auth_init_auths(svc, options); + if (ret == -1) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "Failed to init auth schemes"); + goto out; + } + +out: + return ret; +} + +int +rpcsvc_auth_reconf(rpcsvc_t *svc, dict_t *options) +{ + int ret = 0; + + if ((!svc) || (!options)) + return (-1); + + ret = rpcsvc_set_allow_insecure(svc, options); + if (ret) + return (-1); + + ret = rpcsvc_set_root_squash(svc, options); + if (ret) + return (-1); + + ret = rpcsvc_set_all_squash(svc, options); + if (ret) + return (-1); + + return rpcsvc_set_addr_namelookup(svc, options); +} + +rpcsvc_auth_t * +__rpcsvc_auth_get_handler(rpcsvc_request_t *req) +{ + struct rpcsvc_auth_list *auth = NULL; + struct rpcsvc_auth_list *tmp = NULL; + rpcsvc_t *svc = NULL; + + if (!req) + return NULL; + + svc = req->svc; + if (!svc) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "!svc"); + goto err; + } + + if (list_empty(&svc->authschemes)) { + gf_log(GF_RPCSVC, GF_LOG_WARNING, "No authentication!"); + goto err; + } + + list_for_each_entry_safe(auth, tmp, &svc->authschemes, authlist) + { + if (!auth->enable) + continue; + if (auth->auth->authnum == req->cred.flavour) + goto err; + } + + auth = NULL; +err: + if (auth) + return auth->auth; + else + return NULL; +} + +rpcsvc_auth_t * +rpcsvc_auth_get_handler(rpcsvc_request_t *req) +{ + rpcsvc_auth_t *auth = NULL; + + auth = __rpcsvc_auth_get_handler(req); + if (auth) + goto ret; + + gf_log(GF_RPCSVC, GF_LOG_TRACE, "No auth handler: %d", req->cred.flavour); + + /* The requested scheme was not available so fall back the to one + * scheme that will always be present. + */ + req->cred.flavour = AUTH_NULL; + req->verf.flavour = AUTH_NULL; + auth = __rpcsvc_auth_get_handler(req); +ret: + return auth; +} + +int +rpcsvc_auth_request_init(rpcsvc_request_t *req, struct rpc_msg *callmsg) +{ + int32_t ret = 0; + rpcsvc_auth_t *auth = NULL; + + if (!req || !callmsg) { + ret = -1; + goto err; + } + + req->cred.flavour = rpc_call_cred_flavour(callmsg); + req->cred.datalen = rpc_call_cred_len(callmsg); + req->verf.flavour = rpc_call_verf_flavour(callmsg); + req->verf.datalen = rpc_call_verf_len(callmsg); + + auth = rpcsvc_auth_get_handler(req); + if (!auth) { + ret = -1; + goto err; + } + + gf_log(GF_RPCSVC, GF_LOG_TRACE, "Auth handler: %s", auth->authname); + + if (auth->authops->request_init) + ret = auth->authops->request_init(req, auth->authprivate); + + /* reset to auxgidlarge during + unsersialize if necessary */ + req->auxgids = req->auxgidsmall; + req->auxgidlarge = NULL; +err: + return ret; +} + +int +rpcsvc_authenticate(rpcsvc_request_t *req) +{ + int ret = RPCSVC_AUTH_REJECT; + rpcsvc_auth_t *auth = NULL; + int minauth = 0; + + if (!req) + return ret; + + /* FIXME use rpcsvc_request_prog_minauth() */ + minauth = 0; + if (minauth > rpcsvc_request_cred_flavour(req)) { + gf_log(GF_RPCSVC, GF_LOG_WARNING, "Auth too weak"); + rpcsvc_request_set_autherr(req, AUTH_TOOWEAK); + goto err; + } + + auth = rpcsvc_auth_get_handler(req); + if (!auth) { + gf_log(GF_RPCSVC, GF_LOG_WARNING, "No auth handler found"); + goto err; + } + + if (auth->authops->authenticate) + ret = auth->authops->authenticate(req, auth->authprivate); + +err: + return ret; +} + +int +rpcsvc_auth_array(rpcsvc_t *svc, char *volname, int *autharr, int arrlen) +{ + int count = 0; + int result = RPCSVC_AUTH_REJECT; + char *srchstr = NULL; + int ret = 0; + + struct rpcsvc_auth_list *auth = NULL; + struct rpcsvc_auth_list *tmp = NULL; + + if ((!svc) || (!autharr) || (!volname)) + return -1; + + memset(autharr, 0, arrlen * sizeof(int)); + if (list_empty(&svc->authschemes)) { + gf_log(GF_RPCSVC, GF_LOG_ERROR, "No authentication!"); + goto err; + } + + list_for_each_entry_safe(auth, tmp, &svc->authschemes, authlist) + { + if (count >= arrlen) + break; + + result = gf_asprintf(&srchstr, "rpc-auth.%s.%s", auth->name, volname); + if (result == -1) { + count = -1; + goto err; + } + + ret = dict_get_str_boolean(svc->options, srchstr, 0xC00FFEE); + GF_FREE(srchstr); + + switch (ret) { + case _gf_true: + autharr[count] = auth->auth->authnum; + ++count; + break; + + default: + /* nothing to do */ + break; + } + } + +err: + return count; +} + +gid_t * +rpcsvc_auth_unix_auxgids(rpcsvc_request_t *req, int *arrlen) +{ + if ((!req) || (!arrlen)) + return NULL; + + /* In case of AUTH_NULL auxgids are not used */ + switch (req->cred.flavour) { + case AUTH_UNIX: + case AUTH_GLUSTERFS: + case AUTH_GLUSTERFS_v2: + case AUTH_GLUSTERFS_v3: + break; + default: + gf_log("rpc", GF_LOG_DEBUG, "auth type not unix or glusterfs"); + return NULL; + } + + *arrlen = req->auxgidcount; + if (*arrlen == 0) + return NULL; + + return &req->auxgids[0]; +} |
