@ -139,17 +139,22 @@ static size_t nfs_parse_server_name(char *string, size_t len,
* @ server : NFS server struct
* @ flavors : List of security tuples returned by SECINFO procedure
*
* Return the pseudoflavor of the first security mechanism in
* " flavors " that is locally supported . The " flavors " array
* Return an rpc client that uses the first security mechanism in
* " flavors " that is locally supported . The " flavors " array
* is searched in the order returned from the server , per RFC 3530
* recommendation .
* recommendation and each flavor is checked for membership in the
* sec = mount option list if it exists .
*
* Return - EPERM if no matching flavor is found in the array .
*
* Please call rpc_shutdown_client ( ) when you are done with this rpc client .
*
*/
static rpc_authflavor_t nfs_find_best_sec ( struct nfs_server * server ,
static struct rpc_clnt * nfs_find_best_sec ( struct rpc_clnt * clnt ,
struct nfs_server * server ,
struct nfs4_secinfo_flavors * flavors )
{
rpc_authflavor_t pseudo flavor ;
rpc_authflavor_t pflavor ;
struct nfs4_secinfo4 * secinfo ;
unsigned int i ;
@ -160,58 +165,73 @@ static rpc_authflavor_t nfs_find_best_sec(struct nfs_server *server,
case RPC_AUTH_NULL :
case RPC_AUTH_UNIX :
case RPC_AUTH_GSS :
pseudo flavor = rpcauth_get_pseudoflavor ( secinfo - > flavor ,
pflavor = rpcauth_get_pseudoflavor ( secinfo - > flavor ,
& secinfo - > flavor_info ) ;
/* make sure pseudoflavor matches sec= mount opt */
if ( pseudoflavor ! = RPC_AUTH_MAXFLAVOR & &
nfs_auth_info_match ( & server - > auth_info ,
pseudoflavor ) )
return pseudoflavor ;
break ;
/* does the pseudoflavor match a sec= mount opt? */
if ( pflavor ! = RPC_AUTH_MAXFLAVOR & &
nfs_auth_info_match ( & server - > auth_info , pflavor ) ) {
struct rpc_clnt * new ;
struct rpc_cred * cred ;
/* Cloning creates an rpc_auth for the flavor */
new = rpc_clone_client_set_auth ( clnt , pflavor ) ;
if ( IS_ERR ( new ) )
continue ;
/**
* Check that the user actually can use the
* flavor . This is mostly for RPC_AUTH_GSS
* where cr_init obtains a gss context
*/
cred = rpcauth_lookupcred ( new - > cl_auth , 0 ) ;
if ( IS_ERR ( cred ) ) {
rpc_shutdown_client ( new ) ;
continue ;
}
put_rpccred ( cred ) ;
return new ;
}
}
}
return - EPERM ;
return ERR_PTR ( - EPERM ) ;
}
static rpc_authflavor_t nfs4_negotiate_security ( struct inode * inode , struct qstr * name )
/**
* nfs4_negotiate_security - in response to an NFS4ERR_WRONGSEC on lookup ,
* return an rpc_clnt that uses the best available security flavor with
* respect to the secinfo flavor list and the sec = mount options .
*
* @ clnt : RPC client to clone
* @ inode : directory inode
* @ name : lookup name
*
* Please call rpc_shutdown_client ( ) when you are done with this rpc client .
*/
struct rpc_clnt *
nfs4_negotiate_security ( struct rpc_clnt * clnt , struct inode * inode ,
struct qstr * name )
{
struct page * page ;
struct nfs4_secinfo_flavors * flavors ;
rpc_authflavor_t flavor ;
struct rpc_clnt * new ;
int err ;
page = alloc_page ( GFP_KERNEL ) ;
if ( ! page )
return - ENOMEM ;
return ERR_PTR ( - ENOMEM ) ;
flavors = page_address ( page ) ;
err = nfs4_proc_secinfo ( inode , name , flavors ) ;
if ( err < 0 ) {
flavor = err ;
new = ERR_PTR ( err ) ;
goto out ;
}
flavor = nfs_find_best_sec ( NFS_SERVER ( inode ) , flavors ) ;
new = nfs_find_best_sec ( clnt , NFS_SERVER ( inode ) , flavors ) ;
out :
put_page ( page ) ;
return flavor ;
}
/*
* Please call rpc_shutdown_client ( ) when you are done with this client .
*/
struct rpc_clnt * nfs4_create_sec_client ( struct rpc_clnt * clnt , struct inode * inode ,
struct qstr * name )
{
rpc_authflavor_t flavor ;
flavor = nfs4_negotiate_security ( inode , name ) ;
if ( ( int ) flavor < 0 )
return ERR_PTR ( ( int ) flavor ) ;
return rpc_clone_client_set_auth ( clnt , flavor ) ;
return new ;
}
static struct vfsmount * try_location ( struct nfs_clone_mount * mountdata ,
@ -394,14 +414,6 @@ struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
if ( client - > cl_auth - > au_flavor ! = flavor )
flavor = client - > cl_auth - > au_flavor ;
else {
rpc_authflavor_t new = nfs4_negotiate_security ( dir , name ) ;
if ( ( int ) new < 0 ) {
mnt = ERR_PTR ( ( int ) new ) ;
goto out ;
}
flavor = new ;
}
mnt = nfs_do_submount ( dentry , fh , fattr , flavor ) ;
out :
rpc_shutdown_client ( client ) ;