diff options
Diffstat (limited to 'xlators/protocol/auth')
| -rw-r--r-- | xlators/protocol/auth/addr/src/Makefile.am | 11 | ||||
| -rw-r--r-- | xlators/protocol/auth/addr/src/addr.c | 500 | ||||
| -rw-r--r-- | xlators/protocol/auth/login/src/Makefile.am | 10 | ||||
| -rw-r--r-- | xlators/protocol/auth/login/src/login.c | 302 |
4 files changed, 498 insertions, 325 deletions
diff --git a/xlators/protocol/auth/addr/src/Makefile.am b/xlators/protocol/auth/addr/src/Makefile.am index 7f1dd7445bf..4694d254f12 100644 --- a/xlators/protocol/auth/addr/src/Makefile.am +++ b/xlators/protocol/auth/addr/src/Makefile.am @@ -1,11 +1,14 @@ auth_LTLIBRARIES = addr.la authdir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/auth -addr_la_LDFLAGS = -module -avoidversion +addr_la_LDFLAGS = -module $(GF_XLATOR_LDFLAGS) addr_la_SOURCES = addr.c addr_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la -AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\ - -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS) \ - -I$(top_srcdir)/xlators/protocol/server/src +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \ + -I$(top_srcdir)/xlators/protocol/server/src \ + -I$(top_srcdir)/rpc/xdr/src/ -I$(top_builddir)/rpc/xdr/src/ \ + -I$(top_srcdir)/rpc/rpc-lib/src/ + +AM_CFLAGS = -Wall $(GF_CFLAGS) diff --git a/xlators/protocol/auth/addr/src/addr.c b/xlators/protocol/auth/addr/src/addr.c index 0035d55bad9..bf12c455d7c 100644 --- a/xlators/protocol/auth/addr/src/addr.c +++ b/xlators/protocol/auth/addr/src/addr.c @@ -1,245 +1,341 @@ /* - Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - #include <fnmatch.h> #include <sys/socket.h> #include <netdb.h> #include "authenticate.h" -#include "dict.h" +#include <glusterfs/dict.h> +#include "rpc-transport.h" -#define ADDR_DELIMITER " ," +#define ENTRY_DELIMITER "," +#define ADDR_DELIMITER "|" #define PRIVILEGED_PORT_CEILING 1024 #ifndef AF_INET_SDP #define AF_INET_SDP 27 #endif -/* TODO: duplicate declaration */ -typedef struct peer_info { - struct sockaddr_storage sockaddr; - socklen_t sockaddr_len; - char identifier[UNIX_PATH_MAX]; -}peer_info_t; +/* An option for subdir validation be like below */ -auth_result_t -gf_auth (dict_t *input_params, dict_t *config_params) +/* 1. '*' + 2. '192.168.*' + 3. ' + 4. '!10.10.1*' (Today as per the code, if negate is set on one entry, its + never reset) + 5. '192.168.1.*, 10.1.10.*';168.168.2.* =/dir;* =/another-dir' + +*/ + +int +compare_addr_and_update(char *option_str, char *peer_addr, char *subvol, + char *delimiter, auth_result_t *result, + auth_result_t status) { - auth_result_t result = AUTH_DONT_CARE; - int ret = 0; - char *name = NULL; - char *searchstr = NULL; - peer_info_t *peer_info = NULL; - data_t *peer_info_data = NULL; - data_t *allow_addr = NULL; - data_t *reject_addr = NULL; - char *addr_str = NULL; - char *tmp = NULL; - char *addr_cpy = NULL; - char *service = NULL; - uint16_t peer_port = 0; - char is_inet_sdp = 0; - char negate = 0; - char match = 0; - char peer_addr[UNIX_PATH_MAX]; - char *type = NULL; - gf_boolean_t allow_insecure = _gf_false; - - name = data_to_str (dict_get (input_params, "remote-subvolume")); - if (!name) { - gf_log ("authenticate/addr", GF_LOG_DEBUG, - "remote-subvolume not specified"); - goto out; + char *addr_str = NULL; + char *tmp = NULL; + char negate = 0; + char match = 0; + int length = 0; + int ret = 0; + + addr_str = strtok_r(option_str, delimiter, &tmp); + + while (addr_str) { + gf_log(subvol, GF_LOG_INFO, "%s = \"%s\", received addr = \"%s\"", + (status == AUTH_ACCEPT) ? "allowed" : "rejected", addr_str, + peer_addr); + if (addr_str[0] == '!') { + negate = 1; + addr_str++; } - ret = gf_asprintf (&searchstr, "auth.addr.%s.allow", name); - if (-1 == ret) { - gf_log ("auth/addr", GF_LOG_DEBUG, - "asprintf failed while setting search string"); + length = strlen(addr_str); + if ((addr_str[0] != '*') && valid_host_name(addr_str, length)) { + match = gf_is_same_address(addr_str, peer_addr); + if (match) { + *result = status; goto out; + } + } else { + if (strstr(addr_str, "/")) { + match = gf_is_ip_in_net(addr_str, peer_addr); + if (negate ? !match : match) { + *result = status; + goto out; + } + } else { + match = fnmatch(addr_str, peer_addr, 0); + if (negate ? match : !match) { + *result = status; + goto out; + } + } } - allow_addr = dict_get (config_params, searchstr); - GF_FREE (searchstr); + addr_str = strtok_r(NULL, delimiter, &tmp); + } - ret = gf_asprintf (&searchstr, "auth.addr.%s.reject", name); - if (-1 == ret) { - gf_log ("auth/addr", GF_LOG_ERROR, - "asprintf failed while setting search string"); - goto out; - } - reject_addr = dict_get (config_params, searchstr); - GF_FREE (searchstr); - - if (!allow_addr) { - /* TODO: backword compatibility */ - ret = gf_asprintf (&searchstr, "auth.ip.%s.allow", name); - if (-1 == ret) { - gf_log ("auth/addr", GF_LOG_ERROR, - "asprintf failed while setting search string"); - goto out; - } - allow_addr = dict_get (config_params, searchstr); - GF_FREE (searchstr); - } + ret = -1; +out: + return ret; +} - if (!(allow_addr || reject_addr)) { - gf_log ("auth/addr", GF_LOG_DEBUG, - "none of the options auth.addr.%s.allow or " - "auth.addr.%s.reject specified, returning auth_dont_care", - name, name); - goto out; +void +parse_entries_and_compare(char *option_str, char *peer_addr, char *subvol, + char *subdir, auth_result_t *result, + auth_result_t status) +{ + char *entry = NULL; + char *entry_cpy = NULL; + char *directory = NULL; + char *entries = NULL; + char *addr_str = NULL; + char *addr = NULL; + char *tmp = NULL; + char *tmpdir = NULL; + int ret = 0; + + if (!subdir) { + gf_log(subvol, GF_LOG_WARNING, + "subdir entry not present, not performing any operation."); + goto out; + } + + entries = gf_strdup(option_str); + if (!entries) + goto out; + + if (entries[0] != '/' && !strchr(entries, '(')) { + /* Backward compatible option */ + ret = compare_addr_and_update(entries, peer_addr, subvol, ",", result, + status); + goto out; + } + + entry = strtok_r(entries, ENTRY_DELIMITER, &tmp); + while (entry) { + entry_cpy = gf_strdup(entry); + if (!entry_cpy) { + goto out; } - peer_info_data = dict_get (input_params, "peer-info"); - if (!peer_info_data) { - gf_log ("auth/addr", GF_LOG_ERROR, - "peer-info not present"); - goto out; + directory = strtok_r(entry_cpy, "(", &tmpdir); + if (directory[0] != '/') + goto out; + + /* send second portion, after ' =' if directory matches */ + if (strcmp(subdir, directory)) + goto next_entry; + + addr_str = strtok_r(NULL, ")", &tmpdir); + if (!addr_str) + goto out; + + addr = gf_strdup(addr_str); + if (!addr) + goto out; + + gf_log(subvol, GF_LOG_INFO, + "Found an entry for dir %s (%s)," + " performing validation", + subdir, addr); + + ret = compare_addr_and_update(addr, peer_addr, subvol, ADDR_DELIMITER, + result, status); + if (ret == 0) { + break; } - peer_info = data_to_ptr (peer_info_data); + GF_FREE(addr); + addr = NULL; - switch (((struct sockaddr *) &peer_info->sockaddr)->sa_family) - { - case AF_INET_SDP: - is_inet_sdp = 1; - ((struct sockaddr *) &peer_info->sockaddr)->sa_family = AF_INET; + next_entry: + entry = strtok_r(NULL, ENTRY_DELIMITER, &tmp); + GF_FREE(entry_cpy); + entry_cpy = NULL; + } +out: + GF_FREE(entries); + GF_FREE(entry_cpy); + GF_FREE(addr); +} + +auth_result_t +gf_auth(dict_t *input_params, dict_t *config_params) +{ + auth_result_t result = AUTH_DONT_CARE; + int ret = 0; + char *name = NULL; + char *searchstr = NULL; + peer_info_t *peer_info = NULL; + data_t *peer_info_data = NULL; + data_t *allow_addr = NULL; + data_t *reject_addr = NULL; + char *service = NULL; + uint16_t peer_port = 0; + char peer_addr[UNIX_PATH_MAX] = { + 0, + }; + char *type = NULL; + gf_boolean_t allow_insecure = _gf_false; + char *subdir = NULL; + + name = data_to_str(dict_get(input_params, "remote-subvolume")); + if (!name) { + gf_log("authenticate/addr", GF_LOG_DEBUG, + "remote-subvolume not specified"); + goto out; + } + + ret = gf_asprintf(&searchstr, "auth.addr.%s.allow", name); + if (-1 == ret) { + gf_log("auth/addr", GF_LOG_DEBUG, + "asprintf failed while setting search string"); + goto out; + } + + allow_addr = dict_get(config_params, searchstr); + GF_FREE(searchstr); + + ret = gf_asprintf(&searchstr, "auth.addr.%s.reject", name); + if (-1 == ret) { + gf_log("auth/addr", GF_LOG_ERROR, + "asprintf failed while setting search string"); + goto out; + } + reject_addr = dict_get(config_params, searchstr); + GF_FREE(searchstr); + + if (!allow_addr) { + /* TODO: backward compatibility */ + ret = gf_asprintf(&searchstr, "auth.ip.%s.allow", name); + if (-1 == ret) { + gf_log("auth/addr", GF_LOG_ERROR, + "asprintf failed while setting search string"); + goto out; + } + allow_addr = dict_get(config_params, searchstr); + GF_FREE(searchstr); + } + + if (!(allow_addr || reject_addr)) { + gf_log("auth/addr", GF_LOG_DEBUG, + "none of the options auth.addr.%s.allow or " + "auth.addr.%s.reject specified, returning auth_dont_care", + name, name); + goto out; + } + + peer_info_data = dict_get(input_params, "peer-info"); + if (!peer_info_data) { + gf_log("auth/addr", GF_LOG_ERROR, "peer-info not present"); + goto out; + } + + ret = dict_get_str(input_params, "subdir-mount", &subdir); + if (ret) { + subdir = "/"; + } + + peer_info = data_to_ptr(peer_info_data); + + switch (((struct sockaddr *)&peer_info->sockaddr)->sa_family) { + case AF_INET_SDP: case AF_INET: case AF_INET6: - { - strcpy (peer_addr, peer_info->identifier); - service = strrchr (peer_addr, ':'); - *service = '\0'; - service ++; - - if (is_inet_sdp) { - ((struct sockaddr *) &peer_info->sockaddr)->sa_family = AF_INET_SDP; - } - - ret = dict_get_str (config_params, "rpc-auth-allow-insecure", - &type); - if (ret == 0) { - ret = gf_string2boolean (type, &allow_insecure); - if (ret < 0) { - gf_log ("auth/addr", GF_LOG_WARNING, - "rpc-auth-allow-insecure option %s " - "is not a valid bool option", type); - goto out; - } + strcpy(peer_addr, peer_info->identifier); + service = strrchr(peer_addr, ':'); + *service = '\0'; + service++; + + ret = dict_get_str(config_params, "rpc-auth-allow-insecure", &type); + if (ret == 0) { + ret = gf_string2boolean(type, &allow_insecure); + if (ret < 0) { + gf_log("auth/addr", GF_LOG_WARNING, + "rpc-auth-allow-insecure option %s " + "is not a valid bool option", + type); + goto out; } - - peer_port = atoi (service); - if (peer_port >= PRIVILEGED_PORT_CEILING && !allow_insecure) { - gf_log ("auth/addr", GF_LOG_ERROR, - "client is bound to port %d which is not privileged", - peer_port); - goto out; - } - break; + } + + peer_port = atoi(service); + if (peer_port >= PRIVILEGED_PORT_CEILING && !allow_insecure) { + gf_log("auth/addr", GF_LOG_ERROR, + "client is bound to port %d which is not privileged", + peer_port); + result = AUTH_REJECT; + goto out; + } + break; case AF_UNIX: - strcpy (peer_addr, peer_info->identifier); - break; + strcpy(peer_addr, peer_info->identifier); + break; default: - gf_log ("authenticate/addr", GF_LOG_ERROR, - "unknown address family %d", - ((struct sockaddr *) &peer_info->sockaddr)->sa_family); - goto out; - } - } - - if (reject_addr) { - addr_cpy = gf_strdup (reject_addr->data); - if (!addr_cpy) - goto out; - - addr_str = strtok_r (addr_cpy, ADDR_DELIMITER, &tmp); - - while (addr_str) { - gf_log (name, GF_LOG_DEBUG, - "rejected = \"%s\", received addr = \"%s\"", - addr_str, peer_addr); - if (addr_str[0] == '!') { - negate = 1; - addr_str++; - } - - match = fnmatch (addr_str, peer_addr, 0); - if (negate ? match : !match) { - result = AUTH_REJECT; - goto out; - } - addr_str = strtok_r (NULL, ADDR_DELIMITER, &tmp); - } - GF_FREE (addr_cpy); - } - - if (allow_addr) { - addr_cpy = gf_strdup (allow_addr->data); - if (!addr_cpy) - goto out; - - addr_str = strtok_r (addr_cpy, ADDR_DELIMITER, &tmp); - - while (addr_str) { - gf_log (name, GF_LOG_DEBUG, - "allowed = \"%s\", received addr = \"%s\"", - addr_str, peer_addr); - if (addr_str[0] == '!') { - negate = 1; - addr_str++; - } - - match = fnmatch (addr_str, peer_addr, 0); - if (negate ? match : !match) { - result = AUTH_ACCEPT; - goto out; - } - addr_str = strtok_r (NULL, ADDR_DELIMITER, &tmp); - } - } + gf_log("authenticate/addr", GF_LOG_ERROR, + "unknown address family %d", + ((struct sockaddr *)&peer_info->sockaddr)->sa_family); + goto out; + } + + if (reject_addr) { + parse_entries_and_compare(reject_addr->data, peer_addr, name, subdir, + &result, AUTH_REJECT); + if (result == AUTH_REJECT) + goto out; + } + + if (allow_addr) { + parse_entries_and_compare(allow_addr->data, peer_addr, name, subdir, + &result, AUTH_ACCEPT); + } out: - if (addr_cpy) - GF_FREE (addr_cpy); - - return result; + return result; } struct volume_options options[] = { - { .key = {"auth.addr.*.allow"}, - .type = GF_OPTION_TYPE_ANY - }, - { .key = {"auth.addr.*.reject"}, - .type = GF_OPTION_TYPE_ANY - }, - /* Backword compatibility */ - { .key = {"auth.ip.*.allow"}, - .type = GF_OPTION_TYPE_ANY - }, - { .key = {NULL} } -}; + { + .key = {"auth.addr.*.allow"}, + .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .default_value = "*", + .description = "List of addresses to be allowed to access volume", + .op_version = {1}, + .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC, + .tags = {}, + /* option_validation_fn validate_fn; */ + }, + { + .key = {"auth.addr.*.reject"}, + .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .default_value = "*", + .description = "List of addresses to be rejected to access volume", + .op_version = {1}, + .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC, + .tags = {}, + /* option_validation_fn validate_fn; */ + }, + /* Backward compatibility */ + { + .key = {"auth.ip.*.allow"}, + .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .default_value = "*", + .description = "List of addresses to be allowed to access volume", + .op_version = {1}, + .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC, + .tags = {}, + /* option_validation_fn validate_fn; */ + }, + {.key = {NULL}}}; diff --git a/xlators/protocol/auth/login/src/Makefile.am b/xlators/protocol/auth/login/src/Makefile.am index b4719d1a72f..9837437b11e 100644 --- a/xlators/protocol/auth/login/src/Makefile.am +++ b/xlators/protocol/auth/login/src/Makefile.am @@ -1,11 +1,13 @@ auth_LTLIBRARIES = login.la authdir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/auth -login_la_LDFLAGS = -module -avoidversion +login_la_LDFLAGS = -module $(GF_XLATOR_LDFLAGS) login_la_SOURCES = login.c login_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la -AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\ - -I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS) \ - -I$(top_srcdir)/xlators/protocol/server/src +AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \ + -I$(top_srcdir)/xlators/protocol/server/src \ + -I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src + +AM_CFLAGS = -Wall $(GF_CFLAGS) diff --git a/xlators/protocol/auth/login/src/login.c b/xlators/protocol/auth/login/src/login.c index 87ee77fcf27..64521267bfe 100644 --- a/xlators/protocol/auth/login/src/login.c +++ b/xlators/protocol/auth/login/src/login.c @@ -1,138 +1,210 @@ /* - Copyright (c) 2007-2011 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - #include <fnmatch.h> #include "authenticate.h" -auth_result_t gf_auth (dict_t *input_params, dict_t *config_params) +/* Note on strict_auth + * - Strict auth kicks in when authentication is using the username, password + * in the volfile to login + * - If enabled, auth is rejected if the username and password is not matched + * or is not present + * - When using SSL names, this is automatically strict, and allows only those + * names that are present in the allow list, IOW strict auth checking has no + * implication when using SSL names + */ + +auth_result_t +gf_auth(dict_t *input_params, dict_t *config_params) { - auth_result_t result = AUTH_DONT_CARE; - int ret = 0; - data_t *allow_user = NULL; - data_t *username_data = NULL; - data_t *passwd_data = NULL; - data_t *password_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; - - username_data = dict_get (input_params, "username"); + auth_result_t result = AUTH_DONT_CARE; + int ret = 0; + data_t *allow_user = NULL; + data_t *username_data = NULL; + data_t *passwd_data = NULL; + data_t *password_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; + gf_boolean_t using_ssl = _gf_false; + gf_boolean_t strict_auth = _gf_false; + + username_data = dict_get(input_params, "ssl-name"); + if (username_data) { + gf_log("auth/login", GF_LOG_INFO, "connecting user name: %s", + username_data->data); + using_ssl = _gf_true; + } else { + ret = dict_get_str_boolean(config_params, "strict-auth-accept", + _gf_false); + if (ret == -1) + strict_auth = _gf_false; + else + strict_auth = ret; + + username_data = dict_get(input_params, "username"); if (!username_data) { - gf_log ("auth/login", GF_LOG_DEBUG, - "username not found, returning DONT-CARE"); - goto out; + if (strict_auth) { + gf_log("auth/login", GF_LOG_DEBUG, + "username not found, strict auth" + " configured returning REJECT"); + result = AUTH_REJECT; + } else { + gf_log("auth/login", GF_LOG_DEBUG, + "username not found, returning" + " DONT-CARE"); + } + goto out; } - - username = data_to_str (username_data); - - password_data = dict_get (input_params, "password"); + password_data = dict_get(input_params, "password"); if (!password_data) { - gf_log ("auth/login", GF_LOG_WARNING, - "password not found, returning DONT-CARE"); - goto out; - } - - password = data_to_str (password_data); - - brick_name = data_to_str (dict_get (input_params, "remote-subvolume")); - if (!brick_name) { - gf_log ("auth/login", GF_LOG_ERROR, - "remote-subvolume not specified"); + if (strict_auth) { + gf_log("auth/login", GF_LOG_DEBUG, + "password not found, strict auth" + " configured returning REJECT"); result = AUTH_REJECT; - goto out; + } else { + gf_log("auth/login", GF_LOG_WARNING, + "password not found, returning" + " DONT-CARE"); + } + goto out; } - - ret = gf_asprintf (&searchstr, "auth.login.%s.allow", brick_name); - if (-1 == ret) { - gf_log ("auth/login", GF_LOG_WARNING, - "asprintf failed while setting search string, " - "returning DONT-CARE"); - goto out; + password = data_to_str(password_data); + } + username = data_to_str(username_data); + + brick_name = data_to_str(dict_get(input_params, "remote-subvolume")); + if (!brick_name) { + gf_log("auth/login", GF_LOG_ERROR, "remote-subvolume not specified"); + result = AUTH_REJECT; + goto out; + } + + ret = gf_asprintf(&searchstr, "auth.login.%s.%s", brick_name, + using_ssl ? "ssl-allow" : "allow"); + if (-1 == ret) { + gf_log("auth/login", GF_LOG_ERROR, + "asprintf failed while setting search string, " + "returning REJECT"); + result = AUTH_REJECT; + goto out; + } + + allow_user = dict_get(config_params, searchstr); + GF_FREE(searchstr); + + if (allow_user) { + gf_log("auth/login", GF_LOG_INFO, "allowed user names: %s", + allow_user->data); + /* + * There's a subtle difference between SSL and non-SSL behavior + * if we can't match anything in the "while" loop below. + * Intuitively, we should AUTH_REJECT if there's no match. + * However, existing code depends on allowing untrusted users + * to connect with *no credentials at all* by falling through + * the loop. They're still distinguished from trusted users + * who do provide a valid username and password (in fact that's + * pretty much the only thing we use non-SSL login auth for), + * but they are allowed to connect. It's wrong, but it's not + * worth changing elsewhere. Therefore, we do the sane thing + * only for SSL here. + * + * For SSL, if there's a list *you must be on it*. Note that + * if there's no list we don't care. In that case (and the + * ssl-allow=* case as well) authorization is effectively + * disabled, though authentication and encryption are still + * active. + * + * Read NOTE on strict_auth above. + */ + if (using_ssl || strict_auth) { + result = AUTH_REJECT; } - - 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) { - gf_log ("auth/login", GF_LOG_WARNING, - "asprintf failed while setting search string"); - 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"); - result = AUTH_REJECT; - goto out; - } - - result = !((strcmp (data_to_str (passwd_data), - password)) ? - AUTH_ACCEPT : - AUTH_REJECT); - if (result == AUTH_REJECT) - gf_log ("auth/login", GF_LOG_ERROR, - "wrong password for user %s", - username); - - break; - } - username_str = strtok_r (NULL, " ,", &tmp); + username_cpy = gf_strdup(allow_user->data); + if (!username_cpy) + goto out; + + username_str = strtok_r(username_cpy, " ,", &tmp); + + /* + * We have to match a user's *authenticated* name to one in the + * list. If we're using SSL, they're already authenticated. + * Otherwise, they need a matching password to complete the + * process. + */ + while (username_str) { + if (!fnmatch(username_str, username, 0)) { + if (using_ssl) { + result = AUTH_ACCEPT; + break; + } + ret = gf_asprintf(&searchstr, "auth.login.%s.password", + username); + if (-1 == ret) { + gf_log("auth/login", GF_LOG_WARNING, + "asprintf failed while setting search string"); + 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"); + result = AUTH_REJECT; + goto out; + } + + result = !((strcmp(data_to_str(passwd_data), password)) + ? AUTH_ACCEPT + : AUTH_REJECT); + if (result == AUTH_REJECT) + gf_log("auth/login", GF_LOG_ERROR, + "wrong password for user %s", username); + + break; + } + username_str = strtok_r(NULL, " ,", &tmp); } + } out: - if (username_cpy) - GF_FREE (username_cpy); + GF_FREE(username_cpy); - return result; + return result; } struct volume_options options[] = { - { .key = {"auth.login.*.allow"}, - .type = GF_OPTION_TYPE_ANY - }, - { .key = {"auth.login.*.password"}, - .type = GF_OPTION_TYPE_ANY - }, - { .key = {NULL} } -}; + { + .key = {"auth.login.*.allow"}, + .type = GF_OPTION_TYPE_ANY, + .default_value = "*", + .description = "Username to be allowed access to the volume", + .op_version = {1}, + .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC, + .tags = {}, + /* option_validation_fn validate_fn; */ + }, + { + .key = {"auth.login.*.password"}, + .type = GF_OPTION_TYPE_ANY, + .default_value = "*", + .description = "Password for the allowed username", + .op_version = {1}, + .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC, + .tags = {}, + /* option_validation_fn validate_fn; */ + }, + {.key = {NULL}}}; |
