diff options
author | Niels de Vos <ndevos@redhat.com> | 2014-07-02 11:11:43 +0200 |
---|---|---|
committer | Niels de Vos <ndevos@redhat.com> | 2014-07-02 04:28:21 -0700 |
commit | f25c549c959e06e70eefc5744dc5f93668411de2 (patch) | |
tree | f3b6071afd87194b2da56e59b2ec8c20011705db | |
parent | cc372dc0d0561b2995d89cab4e84dcebef0c346c (diff) |
gNFS: Support wildcard in RPC auth allow/reject
RFE: Support wildcard in "nfs.rpc-auth-allow" and
"nfs.rpc-auth-reject". e.g.
*.redhat.com
192.168.1[1-5].*
192.168.1[1-5].*, *.redhat.com, 192.168.21.9
Along with wildcard, support for subnetwork or IP range e.g.
192.168.10.23/24
The option will be validated for following categories:
1) Anonymous i.e. "*"
2) Wildcard pattern i.e. string containing any ('*', '?', '[')
3) IPv4 address
4) IPv6 address
5) FQDN
6) subnetwork or IPv4 range
Currently this does not support IPv6 subnetwork.
Cherry-picked from 00e247ee44067f2b3e7ca5f7e6dc2f7934c97181:
> Change-Id: Iac8caf5e490c8174d61111dad47fd547d4f67bf4
> BUG: 1086097
> Signed-off-by: Santosh Kumar Pradhan <spradhan@redhat.com>
> Reviewed-on: http://review.gluster.org/7485
> Reviewed-by: Poornima G <pgurusid@redhat.com>
> Reviewed-by: Harshavardhana <harsha@harshavardhana.net>
> Tested-by: Gluster Build System <jenkins@build.gluster.com>
> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Change-Id: I18ef0a914cd403c1f9e66d1b03ecd29465cbce95
BUG: 1115369
Signed-off-by: Niels de Vos <ndevos@redhat.com>
Reviewed-on: http://review.gluster.org/8223
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Santosh Pradhan <spradhan@redhat.com>
-rw-r--r-- | libglusterfs/src/common-utils.c | 59 | ||||
-rw-r--r-- | libglusterfs/src/common-utils.h | 5 | ||||
-rw-r--r-- | libglusterfs/src/options.c | 40 | ||||
-rw-r--r-- | libglusterfs/src/options.h | 1 | ||||
-rw-r--r-- | rpc/rpc-lib/src/rpcsvc.c | 17 | ||||
-rwxr-xr-x | tests/bugs/bug-822830.t | 24 | ||||
-rw-r--r-- | xlators/nfs/server/src/nfs.c | 8 |
7 files changed, 143 insertions, 11 deletions
diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 96319624361..d5df2b2fedf 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -2066,6 +2066,65 @@ out: } /** + * valid_mount_auth_address - Validate the rpc-auth.addr.allow/reject pattern + * + * @param address - Pattern to be validated + * + * @return _gf_true if "address" is "*" (anonymous) 'OR' + * if "address" is valid FQDN or valid IPv4/6 address 'OR' + * if "address" contains wildcard chars e.g. "'*' or '?' or '['" + * if "address" is valid ipv4 subnet pattern (xx.xx.xx.xx/n) + * _gf_false otherwise + * + * + * NB: If the user/admin set for wildcard pattern, then it does not have + * to be validated. Make it similar to the way exportfs (kNFS) works. + */ +gf_boolean_t +valid_mount_auth_address (char *address) +{ + int length = 0; + char *cp = NULL; + + /* 1. Check for "NULL and empty string */ + if ((address == NULL) || (address[0] == '\0')){ + gf_log_callingfn (THIS->name, + GF_LOG_WARNING, "argument invalid"); + return _gf_false; + } + + /* 2. Check for Anonymous */ + if (strcmp(address, "*") == 0) + return _gf_true; + + for (cp = address; *cp; cp++) { + /* 3. Check for wildcard pattern */ + if (*cp == '*' || *cp == '?' || *cp == '[') { + return _gf_true; + } + + /* + * 4. check for IPv4 subnetwork i.e. xx.xx.xx.xx/n + * TODO: check for IPv6 subnetwork + * NB: Wildcard must not be mixed with subnetwork. + */ + if (*cp == '/') { + return valid_ipv4_subnetwork (address); + } + } + + /* 5. Check for v4/v6 IP addr and FQDN/hostname */ + length = strlen (address); + if ((valid_ipv4_address (address, length, _gf_false)) || + (valid_ipv6_address (address, length, _gf_false)) || + (valid_host_name (address, length))) { + return _gf_true; + } + + return _gf_false; +} + +/** * gf_sock_union_equal_addr - check if two given gf_sock_unions have same addr * * @param a - first sock union diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index a0c0db170de..28b2836c925 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -579,9 +579,8 @@ char valid_host_name (char *address, int length); char valid_ipv4_address (char *address, int length, gf_boolean_t wildcard_acc); char valid_ipv6_address (char *address, int length, gf_boolean_t wildcard_acc); char valid_internet_address (char *address, gf_boolean_t wildcard_acc); -char valid_ipv4_wildcard_check (char *address); -char valid_ipv6_wildcard_check (char *address); -char valid_wildcard_internet_address (char *address); +gf_boolean_t valid_mount_auth_address (char *address); +gf_boolean_t valid_ipv4_subnetwork (const char *address); gf_boolean_t gf_sock_union_equal_addr (union gf_sock_union *a, union gf_sock_union *b); diff --git a/libglusterfs/src/options.c b/libglusterfs/src/options.c index 31e5a681d11..a0881b4ad91 100644 --- a/libglusterfs/src/options.c +++ b/libglusterfs/src/options.c @@ -574,6 +574,45 @@ out: return ret; } +static int +xlator_option_validate_mntauth (xlator_t *xl, const char *key, + const char *value, volume_option_t *opt, + char **op_errstr) +{ + int ret = -1; + char *dup_val = NULL; + char *addr_tok = NULL; + char *save_ptr = NULL; + char errstr[4096] = {0,}; + + dup_val = gf_strdup (value); + if (!dup_val) + goto out; + + addr_tok = strtok_r (dup_val, ",", &save_ptr); + if (addr_tok == NULL) + goto out; + while (addr_tok) { + if (!valid_mount_auth_address (addr_tok)) + goto out; + + addr_tok = strtok_r (NULL, ",", &save_ptr); + } + ret = 0; + +out: + if (ret) { + snprintf (errstr, sizeof (errstr), "option %s %s: '%s' is not " + "a valid mount-auth-address", key, value, value); + gf_log (xl->name, GF_LOG_ERROR, "%s", errstr); + if (op_errstr) + *op_errstr = gf_strdup (errstr); + } + GF_FREE (dup_val); + + return ret; +} + /*XXX: the rules to validate are as per block-size required for stripe xlator */ static int gf_validate_size (const char *sizestr, volume_option_t *opt) @@ -744,6 +783,7 @@ xlator_option_validate (xlator_t *xl, char *key, char *value, xlator_option_validate_priority_list, [GF_OPTION_TYPE_SIZE_LIST] = xlator_option_validate_size_list, [GF_OPTION_TYPE_ANY] = xlator_option_validate_any, + [GF_OPTION_TYPE_CLIENT_AUTH_ADDR] = xlator_option_validate_mntauth, [GF_OPTION_TYPE_MAX] = NULL, }; diff --git a/libglusterfs/src/options.h b/libglusterfs/src/options.h index 62f4ee92e91..134cc360293 100644 --- a/libglusterfs/src/options.h +++ b/libglusterfs/src/options.h @@ -38,6 +38,7 @@ typedef enum { GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, GF_OPTION_TYPE_PRIORITY_LIST, GF_OPTION_TYPE_SIZE_LIST, + GF_OPTION_TYPE_CLIENT_AUTH_ADDR, GF_OPTION_TYPE_MAX, } volume_option_type_t; diff --git a/rpc/rpc-lib/src/rpcsvc.c b/rpc/rpc-lib/src/rpcsvc.c index a751330a7c9..d6e9ee951c8 100644 --- a/rpc/rpc-lib/src/rpcsvc.c +++ b/rpc/rpc-lib/src/rpcsvc.c @@ -2392,8 +2392,20 @@ rpcsvc_auth_check (rpcsvc_t *svc, char *volname, ret = dict_get_str (options, srchstr, &reject_str); GF_FREE (srchstr); - if (reject_str == NULL && !strcmp ("*", allow_str)) - return RPCSVC_AUTH_ACCEPT; + + /* + * If "reject_str" is being set as '*' (anonymous), then NFS-server + * would reject everything. If the "reject_str" is not set and + * "allow_str" is set as '*' (anonymous), then NFS-server would + * accept mount requests from all clients. + */ + if (reject_str != NULL) { + if (!strcmp ("*", reject_str)) + return RPCSVC_AUTH_REJECT; + } else { + if (!strcmp ("*", allow_str)) + return RPCSVC_AUTH_ACCEPT; + } /* Non-default rule, authenticate */ if (!get_host_name (client_ip, &ip)) @@ -2577,6 +2589,7 @@ rpcsvc_match_subnet_v4 (const char *addrtok, const char *ipaddr) mask.sin_addr.s_addr)) { ret = 0; /* SUCCESS */ } + out: GF_FREE (netaddr); return ret; diff --git a/tests/bugs/bug-822830.t b/tests/bugs/bug-822830.t index 000d99f03cc..b7a5704cdba 100755 --- a/tests/bugs/bug-822830.t +++ b/tests/bugs/bug-822830.t @@ -18,18 +18,38 @@ EXPECT 'Created' volinfo_field $V0 'Status'; TEST $CLI volume start $V0; EXPECT 'Started' volinfo_field $V0 'Status'; -## Setting nfs.rpc-auth-reject as 192.*..* -TEST ! $CLI volume set $V0 nfs.rpc-auth-reject 192.*..* +## Setting nfs.rpc-auth-reject as 192.{}.1.2 +TEST ! $CLI volume set $V0 nfs.rpc-auth-reject 192.{}.1.2 EXPECT '' volinfo_field $V0 'nfs.rpc-auth-reject'; # Setting nfs.rpc-auth-allow as a.a. TEST ! $CLI volume set $V0 nfs.rpc-auth-allow a.a. EXPECT '' volinfo_field $V0 'nfs.rpc-auth-allow'; +## Setting nfs.rpc-auth-reject as 192.*..* +TEST $CLI volume set $V0 nfs.rpc-auth-reject 192.*..* +EXPECT '192.*..*' volinfo_field $V0 'nfs.rpc-auth-reject'; + # Setting nfs.rpc-auth-allow as a.a TEST $CLI volume set $V0 nfs.rpc-auth-allow a.a EXPECT 'a.a' volinfo_field $V0 'nfs.rpc-auth-allow'; +# Setting nfs.rpc-auth-allow as *.redhat.com +TEST $CLI volume set $V0 nfs.rpc-auth-allow *.redhat.com +EXPECT '\*.redhat.com' volinfo_field $V0 'nfs.rpc-auth-allow'; + +# Setting nfs.rpc-auth-allow as 192.168.10.[1-5] +TEST $CLI volume set $V0 nfs.rpc-auth-allow 192.168.10.[1-5] +EXPECT '192.168.10.\[1-5]' volinfo_field $V0 'nfs.rpc-auth-allow'; + +# Setting nfs.rpc-auth-allow as 192.168.70.? +TEST $CLI volume set $V0 nfs.rpc-auth-allow 192.168.70.? +EXPECT '192.168.70.?' volinfo_field $V0 'nfs.rpc-auth-allow'; + +# Setting nfs.rpc-auth-reject as 192.168.10.5/16 +TEST $CLI volume set $V0 nfs.rpc-auth-reject 192.168.10.5/16 +EXPECT '192.168.10.5/16' volinfo_field $V0 'nfs.rpc-auth-reject'; + ## Setting nfs.rpc-auth-reject as 192.*.* TEST $CLI volume set $V0 nfs.rpc-auth-reject 192.*.* EXPECT '192.*.*' volinfo_field $V0 'nfs.rpc-auth-reject'; diff --git a/xlators/nfs/server/src/nfs.c b/xlators/nfs/server/src/nfs.c index 4ecc5be0cd0..bd3e03fc947 100644 --- a/xlators/nfs/server/src/nfs.c +++ b/xlators/nfs/server/src/nfs.c @@ -1665,7 +1665,7 @@ struct volume_options options[] = { "unrecognized option warnings." }, { .key = {"rpc-auth.addr.allow"}, - .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .type = GF_OPTION_TYPE_CLIENT_AUTH_ADDR, .default_value = "all", .description = "Allow a comma separated list of addresses and/or" " hostnames to connect to the server. By default, all" @@ -1673,7 +1673,7 @@ struct volume_options options[] = { "define a general rule for all exported volumes." }, { .key = {"rpc-auth.addr.reject"}, - .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .type = GF_OPTION_TYPE_CLIENT_AUTH_ADDR, .default_value = "none", .description = "Reject a comma separated list of addresses and/or" " hostnames from connecting to the server. By default," @@ -1681,7 +1681,7 @@ struct volume_options options[] = { "define a general rule for all exported volumes." }, { .key = {"rpc-auth.addr.*.allow"}, - .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .type = GF_OPTION_TYPE_CLIENT_AUTH_ADDR, .default_value = "all", .description = "Allow a comma separated list of addresses and/or" " hostnames to connect to the server. By default, all" @@ -1689,7 +1689,7 @@ struct volume_options options[] = { "define a rule for a specific exported volume." }, { .key = {"rpc-auth.addr.*.reject"}, - .type = GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + .type = GF_OPTION_TYPE_CLIENT_AUTH_ADDR, .default_value = "none", .description = "Reject a comma separated list of addresses and/or" " hostnames from connecting to the server. By default," |