aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/super.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2013-06-27 15:54:41 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-06-28 15:52:37 -0400
commit9111c95b077a81573fb27df3ba8255d0a3a9ebdf (patch)
treec8ae18612cc3c6445f17d12d1860783f532fc175 /fs/nfs/super.c
parentfb9b02fda06798cfca975c8b7fae3e6188a30572 (diff)
nfs: have NFSv3 try server-specified auth flavors in turn
The current scheme is to try and pick the auth flavor that the server prefers. In some cases though, we may find that we're not actually able to use that auth flavor later. For instance, the server may prefer an AUTH_GSS flavor, but we may not be able to get GSSAPI creds. The current code just gives up at that point. Change it instead to try the ->create_server call using each of the different authflavors in the server's list if one was not specified at mount time. Once we have a successful ->create_server call, return the result. Only give up and return error if all attempts fail. Cc: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r--fs/nfs/super.c126
1 files changed, 69 insertions, 57 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index ceb60c78bfc0..8d51101771fc 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1608,16 +1608,13 @@ out_security_failure:
1608} 1608}
1609 1609
1610/* 1610/*
1611 * Select a security flavor for this mount. The selected flavor 1611 * Ensure that the specified authtype in args->auth_flavors[0] is supported by
1612 * is planted in args->auth_flavors[0]. 1612 * the server. Returns 0 if it's ok, and -EACCES if not.
1613 *
1614 * Returns 0 on success, -EACCES on failure.
1615 */ 1613 */
1616static int nfs_select_flavor(struct nfs_parsed_mount_data *args, 1614static int nfs_verify_authflavor(struct nfs_parsed_mount_data *args,
1617 struct nfs_mount_request *request) 1615 rpc_authflavor_t *server_authlist, unsigned int count)
1618{ 1616{
1619 unsigned int i, count = *(request->auth_flav_len); 1617 unsigned int i;
1620 rpc_authflavor_t flavor;
1621 1618
1622 /* 1619 /*
1623 * If the sec= mount option is used, the specified flavor or AUTH_NULL 1620 * If the sec= mount option is used, the specified flavor or AUTH_NULL
@@ -1627,60 +1624,19 @@ static int nfs_select_flavor(struct nfs_parsed_mount_data *args,
1627 * means that the server will ignore the rpc creds, so any flavor 1624 * means that the server will ignore the rpc creds, so any flavor
1628 * can be used. 1625 * can be used.
1629 */ 1626 */
1630 if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) {
1631 for (i = 0; i < count; i++) {
1632 if (args->auth_flavors[0] == request->auth_flavs[i] ||
1633 request->auth_flavs[i] == RPC_AUTH_NULL)
1634 goto out;
1635 }
1636 dfprintk(MOUNT, "NFS: auth flavor %d not supported by server\n",
1637 args->auth_flavors[0]);
1638 goto out_err;
1639 }
1640
1641 /*
1642 * RFC 2623, section 2.7 suggests we SHOULD prefer the
1643 * flavor listed first. However, some servers list
1644 * AUTH_NULL first. Avoid ever choosing AUTH_NULL.
1645 */
1646 for (i = 0; i < count; i++) { 1627 for (i = 0; i < count; i++) {
1647 struct rpcsec_gss_info info; 1628 if (args->auth_flavors[0] == server_authlist[i] ||
1648 1629 server_authlist[i] == RPC_AUTH_NULL)
1649 flavor = request->auth_flavs[i]; 1630 goto out;
1650 switch (flavor) {
1651 case RPC_AUTH_UNIX:
1652 goto out_set;
1653 case RPC_AUTH_NULL:
1654 continue;
1655 default:
1656 if (rpcauth_get_gssinfo(flavor, &info) == 0)
1657 goto out_set;
1658 }
1659 } 1631 }
1660 1632
1661 /* 1633 dfprintk(MOUNT, "NFS: auth flavor %u not supported by server\n",
1662 * As a last chance, see if the server list contains AUTH_NULL - 1634 args->auth_flavors[0]);
1663 * if it does, use the default flavor. 1635 return -EACCES;
1664 */
1665 for (i = 0; i < count; i++) {
1666 if (request->auth_flavs[i] == RPC_AUTH_NULL)
1667 goto out_default;
1668 }
1669
1670 dfprintk(MOUNT, "NFS: no auth flavors in common with server\n");
1671 goto out_err;
1672 1636
1673out_default:
1674 /* use default if flavor not already set */
1675 flavor = (args->auth_flavors[0] == RPC_AUTH_MAXFLAVOR) ?
1676 RPC_AUTH_UNIX : args->auth_flavors[0];
1677out_set:
1678 args->auth_flavors[0] = flavor;
1679out: 1637out:
1680 dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]); 1638 dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]);
1681 return 0; 1639 return 0;
1682out_err:
1683 return -EACCES;
1684} 1640}
1685 1641
1686/* 1642/*
@@ -1743,13 +1699,17 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args,
1743 return status; 1699 return status;
1744 } 1700 }
1745 1701
1746 return nfs_select_flavor(args, &request); 1702 return 0;
1747} 1703}
1748 1704
1749static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info, 1705static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info,
1750 struct nfs_subversion *nfs_mod) 1706 struct nfs_subversion *nfs_mod)
1751{ 1707{
1752 int status; 1708 int status;
1709 unsigned int i;
1710 bool tried_auth_unix = false;
1711 bool auth_null_in_list = false;
1712 struct nfs_server *server = ERR_PTR(-EACCES);
1753 struct nfs_parsed_mount_data *args = mount_info->parsed; 1713 struct nfs_parsed_mount_data *args = mount_info->parsed;
1754 rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS]; 1714 rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS];
1755 unsigned int authlist_len = ARRAY_SIZE(authlist); 1715 unsigned int authlist_len = ARRAY_SIZE(authlist);
@@ -1759,6 +1719,58 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
1759 if (status) 1719 if (status)
1760 return ERR_PTR(status); 1720 return ERR_PTR(status);
1761 1721
1722 /*
1723 * Was a sec= authflavor specified in the options? First, verify
1724 * whether the server supports it, and then just try to use it if so.
1725 */
1726 if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) {
1727 status = nfs_verify_authflavor(args, authlist, authlist_len);
1728 dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]);
1729 if (status)
1730 return ERR_PTR(status);
1731 return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
1732 }
1733
1734 /*
1735 * No sec= option was provided. RFC 2623, section 2.7 suggests we
1736 * SHOULD prefer the flavor listed first. However, some servers list
1737 * AUTH_NULL first. Avoid ever choosing AUTH_NULL.
1738 */
1739 for (i = 0; i < authlist_len; ++i) {
1740 rpc_authflavor_t flavor;
1741 struct rpcsec_gss_info info;
1742
1743 flavor = authlist[i];
1744 switch (flavor) {
1745 case RPC_AUTH_UNIX:
1746 tried_auth_unix = true;
1747 break;
1748 case RPC_AUTH_NULL:
1749 auth_null_in_list = true;
1750 continue;
1751 default:
1752 if (rpcauth_get_gssinfo(flavor, &info) != 0)
1753 continue;
1754 /* Fallthrough */
1755 }
1756 dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
1757 args->auth_flavors[0] = flavor;
1758 server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
1759 if (!IS_ERR(server))
1760 return server;
1761 }
1762
1763 /*
1764 * Nothing we tried so far worked. At this point, give up if we've
1765 * already tried AUTH_UNIX or if the server's list doesn't contain
1766 * AUTH_NULL
1767 */
1768 if (tried_auth_unix || !auth_null_in_list)
1769 return server;
1770
1771 /* Last chance! Try AUTH_UNIX */
1772 dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
1773 args->auth_flavors[0] = RPC_AUTH_UNIX;
1762 return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod); 1774 return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
1763} 1775}
1764 1776