aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/super.c
diff options
context:
space:
mode:
authorWeston Andros Adamson <dros@netapp.com>2013-10-18 15:15:19 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-10-28 15:38:02 -0400
commit4d4b69dd847a098cdca341c45326f6c6f61b8691 (patch)
treefdd1d7204d48f7af1f93f06844ee507e36dc917b /fs/nfs/super.c
parent5837f6dfcb00f764976ddc178933e612702cbf54 (diff)
NFS: add support for multiple sec= mount options
This patch adds support for multiple security options which can be specified using a colon-delimited list of security flavors (the same syntax as nfsd's exports file). This is useful, for instance, when NFSv4.x mounts cross SECINFO boundaries. With this patch a user can use "sec=krb5i,krb5p" to mount a remote filesystem using krb5i, but can still cross into krb5p-only exports. New mounts will try all security options before failing. NFSv4.x SECINFO results will be compared against the sec= flavors to find the first flavor in both lists or if no match is found will return -EPERM. Signed-off-by: Weston Andros Adamson <dros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r--fs/nfs/super.c160
1 files changed, 105 insertions, 55 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 3a4f8bf5e5a5..317d6fc2160e 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -497,7 +497,8 @@ static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
497 static const struct { 497 static const struct {
498 rpc_authflavor_t flavour; 498 rpc_authflavor_t flavour;
499 const char *str; 499 const char *str;
500 } sec_flavours[] = { 500 } sec_flavours[NFS_AUTH_INFO_MAX_FLAVORS] = {
501 /* update NFS_AUTH_INFO_MAX_FLAVORS when this list changes! */
501 { RPC_AUTH_NULL, "null" }, 502 { RPC_AUTH_NULL, "null" },
502 { RPC_AUTH_UNIX, "sys" }, 503 { RPC_AUTH_UNIX, "sys" },
503 { RPC_AUTH_GSS_KRB5, "krb5" }, 504 { RPC_AUTH_GSS_KRB5, "krb5" },
@@ -1019,6 +1020,52 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
1019} 1020}
1020 1021
1021/* 1022/*
1023 * Add 'flavor' to 'auth_info' if not already present.
1024 * Returns true if 'flavor' ends up in the list, false otherwise
1025 */
1026static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
1027 rpc_authflavor_t flavor)
1028{
1029 unsigned int i;
1030 unsigned int max_flavor_len = (sizeof(auth_info->flavors) /
1031 sizeof(auth_info->flavors[0]));
1032
1033 /* make sure this flavor isn't already in the list */
1034 for (i = 0; i < auth_info->flavor_len; i++) {
1035 if (flavor == auth_info->flavors[i])
1036 return true;
1037 }
1038
1039 if (auth_info->flavor_len + 1 >= max_flavor_len) {
1040 dfprintk(MOUNT, "NFS: too many sec= flavors\n");
1041 return false;
1042 }
1043
1044 auth_info->flavors[auth_info->flavor_len++] = flavor;
1045 return true;
1046}
1047
1048/*
1049 * Return true if 'match' is in auth_info or auth_info is empty.
1050 * Return false otherwise.
1051 */
1052bool nfs_auth_info_match(const struct nfs_auth_info *auth_info,
1053 rpc_authflavor_t match)
1054{
1055 int i;
1056
1057 if (!auth_info->flavor_len)
1058 return true;
1059
1060 for (i = 0; i < auth_info->flavor_len; i++) {
1061 if (auth_info->flavors[i] == match)
1062 return true;
1063 }
1064 return false;
1065}
1066EXPORT_SYMBOL_GPL(nfs_auth_info_match);
1067
1068/*
1022 * Parse the value of the 'sec=' option. 1069 * Parse the value of the 'sec=' option.
1023 */ 1070 */
1024static int nfs_parse_security_flavors(char *value, 1071static int nfs_parse_security_flavors(char *value,
@@ -1026,49 +1073,55 @@ static int nfs_parse_security_flavors(char *value,
1026{ 1073{
1027 substring_t args[MAX_OPT_ARGS]; 1074 substring_t args[MAX_OPT_ARGS];
1028 rpc_authflavor_t pseudoflavor; 1075 rpc_authflavor_t pseudoflavor;
1076 char *p;
1029 1077
1030 dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value); 1078 dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
1031 1079
1032 switch (match_token(value, nfs_secflavor_tokens, args)) { 1080 while ((p = strsep(&value, ":")) != NULL) {
1033 case Opt_sec_none: 1081 switch (match_token(p, nfs_secflavor_tokens, args)) {
1034 pseudoflavor = RPC_AUTH_NULL; 1082 case Opt_sec_none:
1035 break; 1083 pseudoflavor = RPC_AUTH_NULL;
1036 case Opt_sec_sys: 1084 break;
1037 pseudoflavor = RPC_AUTH_UNIX; 1085 case Opt_sec_sys:
1038 break; 1086 pseudoflavor = RPC_AUTH_UNIX;
1039 case Opt_sec_krb5: 1087 break;
1040 pseudoflavor = RPC_AUTH_GSS_KRB5; 1088 case Opt_sec_krb5:
1041 break; 1089 pseudoflavor = RPC_AUTH_GSS_KRB5;
1042 case Opt_sec_krb5i: 1090 break;
1043 pseudoflavor = RPC_AUTH_GSS_KRB5I; 1091 case Opt_sec_krb5i:
1044 break; 1092 pseudoflavor = RPC_AUTH_GSS_KRB5I;
1045 case Opt_sec_krb5p: 1093 break;
1046 pseudoflavor = RPC_AUTH_GSS_KRB5P; 1094 case Opt_sec_krb5p:
1047 break; 1095 pseudoflavor = RPC_AUTH_GSS_KRB5P;
1048 case Opt_sec_lkey: 1096 break;
1049 pseudoflavor = RPC_AUTH_GSS_LKEY; 1097 case Opt_sec_lkey:
1050 break; 1098 pseudoflavor = RPC_AUTH_GSS_LKEY;
1051 case Opt_sec_lkeyi: 1099 break;
1052 pseudoflavor = RPC_AUTH_GSS_LKEYI; 1100 case Opt_sec_lkeyi:
1053 break; 1101 pseudoflavor = RPC_AUTH_GSS_LKEYI;
1054 case Opt_sec_lkeyp: 1102 break;
1055 pseudoflavor = RPC_AUTH_GSS_LKEYP; 1103 case Opt_sec_lkeyp:
1056 break; 1104 pseudoflavor = RPC_AUTH_GSS_LKEYP;
1057 case Opt_sec_spkm: 1105 break;
1058 pseudoflavor = RPC_AUTH_GSS_SPKM; 1106 case Opt_sec_spkm:
1059 break; 1107 pseudoflavor = RPC_AUTH_GSS_SPKM;
1060 case Opt_sec_spkmi: 1108 break;
1061 pseudoflavor = RPC_AUTH_GSS_SPKMI; 1109 case Opt_sec_spkmi:
1062 break; 1110 pseudoflavor = RPC_AUTH_GSS_SPKMI;
1063 case Opt_sec_spkmp: 1111 break;
1064 pseudoflavor = RPC_AUTH_GSS_SPKMP; 1112 case Opt_sec_spkmp:
1065 break; 1113 pseudoflavor = RPC_AUTH_GSS_SPKMP;
1066 default: 1114 break;
1067 return 0; 1115 default:
1116 dfprintk(MOUNT,
1117 "NFS: sec= option '%s' not recognized\n", p);
1118 return 0;
1119 }
1120
1121 if (!nfs_auth_info_add(&mnt->auth_info, pseudoflavor))
1122 return 0;
1068 } 1123 }
1069 1124
1070 mnt->auth_info.flavors[0] = pseudoflavor;
1071 mnt->auth_info.flavor_len = 1;
1072 return 1; 1125 return 1;
1073} 1126}
1074 1127
@@ -1615,12 +1668,14 @@ out_security_failure:
1615} 1668}
1616 1669
1617/* 1670/*
1618 * Ensure that the specified authtype in args->auth_info is supported by 1671 * Ensure that a specified authtype in args->auth_info is supported by
1619 * the server. Returns 0 if it's ok, and -EACCES if not. 1672 * the server. Returns 0 and sets args->selected_flavor if it's ok, and
1673 * -EACCES if not.
1620 */ 1674 */
1621static int nfs_verify_authflavor(struct nfs_parsed_mount_data *args, 1675static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
1622 rpc_authflavor_t *server_authlist, unsigned int count) 1676 rpc_authflavor_t *server_authlist, unsigned int count)
1623{ 1677{
1678 rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
1624 unsigned int i; 1679 unsigned int i;
1625 1680
1626 /* 1681 /*
@@ -1632,17 +1687,19 @@ static int nfs_verify_authflavor(struct nfs_parsed_mount_data *args,
1632 * can be used. 1687 * can be used.
1633 */ 1688 */
1634 for (i = 0; i < count; i++) { 1689 for (i = 0; i < count; i++) {
1635 if (args->auth_info.flavors[0] == server_authlist[i] || 1690 flavor = server_authlist[i];
1636 server_authlist[i] == RPC_AUTH_NULL) 1691
1692 if (nfs_auth_info_match(&args->auth_info, flavor) ||
1693 flavor == RPC_AUTH_NULL)
1637 goto out; 1694 goto out;
1638 } 1695 }
1639 1696
1640 dfprintk(MOUNT, "NFS: auth flavor %u not supported by server\n", 1697 dfprintk(MOUNT,
1641 args->auth_info.flavors[0]); 1698 "NFS: specified auth flavors not supported by server\n");
1642 return -EACCES; 1699 return -EACCES;
1643 1700
1644out: 1701out:
1645 args->selected_flavor = args->auth_info.flavors[0]; 1702 args->selected_flavor = flavor;
1646 dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->selected_flavor); 1703 dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->selected_flavor);
1647 return 0; 1704 return 0;
1648} 1705}
@@ -1732,7 +1789,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
1732 * whether the server supports it, and then just try to use it if so. 1789 * whether the server supports it, and then just try to use it if so.
1733 */ 1790 */
1734 if (args->auth_info.flavor_len > 0) { 1791 if (args->auth_info.flavor_len > 0) {
1735 status = nfs_verify_authflavor(args, authlist, authlist_len); 1792 status = nfs_verify_authflavors(args, authlist, authlist_len);
1736 dfprintk(MOUNT, "NFS: using auth flavor %u\n", 1793 dfprintk(MOUNT, "NFS: using auth flavor %u\n",
1737 args->selected_flavor); 1794 args->selected_flavor);
1738 if (status) 1795 if (status)
@@ -2102,9 +2159,6 @@ static int nfs_validate_text_mount_data(void *options,
2102 2159
2103 nfs_set_port(sap, &args->nfs_server.port, port); 2160 nfs_set_port(sap, &args->nfs_server.port, port);
2104 2161
2105 if (args->auth_info.flavor_len > 1)
2106 goto out_bad_auth;
2107
2108 return nfs_parse_devname(dev_name, 2162 return nfs_parse_devname(dev_name,
2109 &args->nfs_server.hostname, 2163 &args->nfs_server.hostname,
2110 max_namelen, 2164 max_namelen,
@@ -2124,10 +2178,6 @@ out_invalid_transport_udp:
2124out_no_address: 2178out_no_address:
2125 dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); 2179 dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
2126 return -EINVAL; 2180 return -EINVAL;
2127
2128out_bad_auth:
2129 dfprintk(MOUNT, "NFS: Too many RPC auth flavours specified\n");
2130 return -EINVAL;
2131} 2181}
2132 2182
2133static int 2183static int