diff options
Diffstat (limited to 'xlators/protocol/auth/addr/src')
| -rw-r--r-- | xlators/protocol/auth/addr/src/Makefile.am | 11 | ||||
| -rw-r--r-- | xlators/protocol/auth/addr/src/addr.c | 530 |
2 files changed, 320 insertions, 221 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 feb1bd38295..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-2010 Gluster, Inc. <http://www.gluster.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 Affero 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 - Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif + 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 <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 */ + +/* 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' -auth_result_t -gf_auth (dict_t *input_params, dict_t *config_params) +*/ + +int +compare_addr_and_update(char *option_str, char *peer_addr, char *subvol, + char *delimiter, auth_result_t *result, + auth_result_t status) { - int ret = 0; - char *name = NULL; - char *searchstr = NULL; - char peer_addr[UNIX_PATH_MAX]; - data_t *peer_info_data = NULL; - peer_info_t *peer_info = NULL; - data_t *allow_addr = NULL, *reject_addr = NULL; - char is_inet_sdp = 0; - 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_ERROR, - "remote-subvolume not specified"); - return AUTH_DONT_CARE; - } - - ret = asprintf (&searchstr, "auth.addr.%s.allow", name); - if (-1 == ret) { - gf_log ("auth/addr", GF_LOG_ERROR, - "asprintf failed while setting search string"); - return AUTH_DONT_CARE; - } - allow_addr = dict_get (config_params, - searchstr); - free (searchstr); - - ret = asprintf (&searchstr, "auth.addr.%s.reject", name); - if (-1 == ret) { - gf_log ("auth/addr", GF_LOG_ERROR, - "asprintf failed while setting search string"); - return AUTH_DONT_CARE; - } - reject_addr = dict_get (config_params, - searchstr); - free (searchstr); - - if (!allow_addr) { - /* TODO: backword compatibility */ - ret = asprintf (&searchstr, "auth.ip.%s.allow", name); - if (-1 == ret) { - gf_log ("auth/addr", GF_LOG_ERROR, - "asprintf failed while setting search string"); - return AUTH_DONT_CARE; - } - allow_addr = dict_get (config_params, searchstr); - 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); - return AUTH_DONT_CARE; - } - - peer_info_data = dict_get (input_params, "peer-info"); - if (!peer_info_data) { - gf_log ("authenticate/addr", - GF_LOG_ERROR, - "peer-info not present"); - return AUTH_DONT_CARE; - } - - peer_info = data_to_ptr (peer_info_data); - - 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; - - case AF_INET: - case AF_INET6: - { - char *service; - uint16_t peer_port; - 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); - return AUTH_DONT_CARE; + 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++; + } + + 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; } + } } - 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); - return AUTH_DONT_CARE; - } - break; - - case AF_UNIX: - 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); - return AUTH_DONT_CARE; - } + addr_str = strtok_r(NULL, delimiter, &tmp); } - if (reject_addr) { + ret = -1; +out: + return ret; +} + +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 *tmp; - char *addr_cpy = strdup (reject_addr->data); - - addr_str = strtok_r (addr_cpy, ADDR_DELIMITER, &tmp); - - while (addr_str) { - char negate = 0, match =0; - 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) { - free (addr_cpy); - return AUTH_REJECT; - } - addr_str = strtok_r (NULL, ADDR_DELIMITER, &tmp); + 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; } - free (addr_cpy); - } - if (allow_addr) { - char *addr_str = NULL; - char *tmp; - char *addr_cpy = strdup (allow_addr->data); - - addr_str = strtok_r (addr_cpy, ADDR_DELIMITER, &tmp); - - while (addr_str) { - char negate = 0, match = 0; - 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) { - free (addr_cpy); - return AUTH_ACCEPT; - } - addr_str = strtok_r (NULL, ADDR_DELIMITER, &tmp); + 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; + } + + 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; + } + + GF_FREE(addr); + addr = NULL; + + next_entry: + entry = strtok_r(NULL, ENTRY_DELIMITER, &tmp); + GF_FREE(entry_cpy); + entry_cpy = NULL; } - free (addr_cpy); - } - - return AUTH_DONT_CARE; + +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++; + + 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); + result = AUTH_REJECT; + goto out; + } + break; + + case AF_UNIX: + 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) { + 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: + 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}}}; |
