2005-04-17 02:20:36 +04:00
/*
* fs / nfs / idmap . c
*
* UID and GID to name mapping for clients .
*
* Copyright ( c ) 2002 The Regents of the University of Michigan .
* All rights reserved .
*
* Marius Aamodt Eriksen < marius @ umich . edu >
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR
* BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING
* NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2011-02-23 02:44:31 +03:00
# include <linux/types.h>
2012-02-24 23:14:51 +04:00
# include <linux/parser.h>
# include <linux/fs.h>
# include <net/net_namespace.h>
# include <linux/sunrpc/rpc_pipe_fs.h>
2012-01-07 22:22:46 +04:00
# include <linux/nfs_fs.h>
2012-01-27 01:54:24 +04:00
# include <linux/nfs_fs_sb.h>
2012-02-24 23:14:51 +04:00
# include <linux/key.h>
2012-01-27 01:54:24 +04:00
# include <linux/keyctl.h>
# include <linux/key-type.h>
# include <keys/user-type.h>
# include <linux/module.h>
2012-02-24 23:14:51 +04:00
2012-01-27 01:54:24 +04:00
# include "internal.h"
2012-01-26 15:11:41 +04:00
# include "netns.h"
2015-04-15 20:00:05 +03:00
# include "nfs4idmap.h"
2013-08-13 19:34:01 +04:00
# include "nfs4trace.h"
2012-01-27 01:54:24 +04:00
# define NFS_UINT_MAXLEN 11
2012-03-11 21:11:00 +04:00
static const struct cred * id_resolver_cache ;
static struct key_type key_type_id_resolver_legacy ;
2012-01-27 01:54:24 +04:00
2012-08-09 22:05:49 +04:00
struct idmap_legacy_upcalldata {
struct rpc_pipe_msg pipe_msg ;
struct idmap_msg idmap_msg ;
2012-09-28 00:15:00 +04:00
struct key_construction * key_cons ;
2012-08-09 22:05:49 +04:00
struct idmap * idmap ;
} ;
2012-09-28 00:15:00 +04:00
struct idmap {
2013-08-27 01:16:17 +04:00
struct rpc_pipe_dir_object idmap_pdo ;
2012-09-28 00:15:00 +04:00
struct rpc_pipe * idmap_pipe ;
struct idmap_legacy_upcalldata * idmap_upcall_data ;
struct mutex idmap_mutex ;
} ;
2012-01-07 22:22:46 +04:00
/**
* nfs_fattr_init_names - initialise the nfs_fattr owner_name / group_name fields
* @ fattr : fully initialised struct nfs_fattr
* @ owner_name : owner name string cache
* @ group_name : group name string cache
*/
void nfs_fattr_init_names ( struct nfs_fattr * fattr ,
struct nfs4_string * owner_name ,
struct nfs4_string * group_name )
{
fattr - > owner_name = owner_name ;
fattr - > group_name = group_name ;
}
static void nfs_fattr_free_owner_name ( struct nfs_fattr * fattr )
{
fattr - > valid & = ~ NFS_ATTR_FATTR_OWNER_NAME ;
kfree ( fattr - > owner_name - > data ) ;
}
static void nfs_fattr_free_group_name ( struct nfs_fattr * fattr )
{
fattr - > valid & = ~ NFS_ATTR_FATTR_GROUP_NAME ;
kfree ( fattr - > group_name - > data ) ;
}
static bool nfs_fattr_map_owner_name ( struct nfs_server * server , struct nfs_fattr * fattr )
{
struct nfs4_string * owner = fattr - > owner_name ;
2013-02-01 15:21:47 +04:00
kuid_t uid ;
2012-01-07 22:22:46 +04:00
if ( ! ( fattr - > valid & NFS_ATTR_FATTR_OWNER_NAME ) )
return false ;
if ( nfs_map_name_to_uid ( server , owner - > data , owner - > len , & uid ) = = 0 ) {
fattr - > uid = uid ;
fattr - > valid | = NFS_ATTR_FATTR_OWNER ;
}
return true ;
}
static bool nfs_fattr_map_group_name ( struct nfs_server * server , struct nfs_fattr * fattr )
{
struct nfs4_string * group = fattr - > group_name ;
2013-02-01 15:21:47 +04:00
kgid_t gid ;
2012-01-07 22:22:46 +04:00
if ( ! ( fattr - > valid & NFS_ATTR_FATTR_GROUP_NAME ) )
return false ;
if ( nfs_map_group_to_gid ( server , group - > data , group - > len , & gid ) = = 0 ) {
fattr - > gid = gid ;
fattr - > valid | = NFS_ATTR_FATTR_GROUP ;
}
return true ;
}
/**
* nfs_fattr_free_names - free up the NFSv4 owner and group strings
* @ fattr : a fully initialised nfs_fattr structure
*/
void nfs_fattr_free_names ( struct nfs_fattr * fattr )
{
if ( fattr - > valid & NFS_ATTR_FATTR_OWNER_NAME )
nfs_fattr_free_owner_name ( fattr ) ;
if ( fattr - > valid & NFS_ATTR_FATTR_GROUP_NAME )
nfs_fattr_free_group_name ( fattr ) ;
}
/**
* nfs_fattr_map_and_free_names - map owner / group strings into uid / gid and free
* @ server : pointer to the filesystem nfs_server structure
* @ fattr : a fully initialised nfs_fattr structure
*
* This helper maps the cached NFSv4 owner / group strings in fattr into
* their numeric uid / gid equivalents , and then frees the cached strings .
*/
void nfs_fattr_map_and_free_names ( struct nfs_server * server , struct nfs_fattr * fattr )
{
if ( nfs_fattr_map_owner_name ( server , fattr ) )
nfs_fattr_free_owner_name ( fattr ) ;
if ( nfs_fattr_map_group_name ( server , fattr ) )
nfs_fattr_free_group_name ( fattr ) ;
}
2011-02-23 02:44:31 +03:00
2014-12-12 01:02:04 +03:00
int nfs_map_string_to_numeric ( const char * name , size_t namelen , __u32 * res )
2011-02-23 02:44:31 +03:00
{
unsigned long val ;
char buf [ 16 ] ;
if ( memchr ( name , ' @ ' , namelen ) ! = NULL | | namelen > = sizeof ( buf ) )
return 0 ;
memcpy ( buf , name , namelen ) ;
buf [ namelen ] = ' \0 ' ;
2012-09-26 23:51:46 +04:00
if ( kstrtoul ( buf , 0 , & val ) ! = 0 )
2011-02-23 02:44:31 +03:00
return 0 ;
* res = val ;
return 1 ;
}
2014-12-12 01:02:04 +03:00
EXPORT_SYMBOL_GPL ( nfs_map_string_to_numeric ) ;
2005-04-17 02:20:36 +04:00
2011-02-23 02:44:31 +03:00
static int nfs_map_numeric_to_string ( __u32 id , char * buf , size_t buflen )
{
return snprintf ( buf , buflen , " %u " , id ) ;
}
2012-03-11 21:11:00 +04:00
static struct key_type key_type_id_resolver = {
2010-09-29 23:41:49 +04:00
. name = " id_resolver " ,
2014-07-18 21:56:35 +04:00
. preparse = user_preparse ,
. free_preparse = user_free_preparse ,
. instantiate = generic_key_instantiate ,
2010-09-29 23:41:49 +04:00
. revoke = user_revoke ,
. destroy = user_destroy ,
. describe = user_describe ,
. read = user_read ,
} ;
2012-01-27 01:54:23 +04:00
static int nfs_idmap_init_keyring ( void )
2010-09-29 23:41:49 +04:00
{
struct cred * cred ;
struct key * keyring ;
int ret = 0 ;
2012-01-26 22:32:22 +04:00
printk ( KERN_NOTICE " NFS: Registering the %s key type \n " ,
key_type_id_resolver . name ) ;
2010-09-29 23:41:49 +04:00
cred = prepare_kernel_cred ( NULL ) ;
if ( ! cred )
return - ENOMEM ;
2013-02-01 15:03:16 +04:00
keyring = keyring_alloc ( " .id_resolver " ,
GLOBAL_ROOT_UID , GLOBAL_ROOT_GID , cred ,
2012-10-02 22:24:56 +04:00
( KEY_POS_ALL & ~ KEY_POS_SETATTR ) |
KEY_USR_VIEW | KEY_USR_READ ,
KEY_ALLOC_NOT_IN_QUOTA , NULL ) ;
2010-09-29 23:41:49 +04:00
if ( IS_ERR ( keyring ) ) {
ret = PTR_ERR ( keyring ) ;
goto failed_put_cred ;
}
ret = register_key_type ( & key_type_id_resolver ) ;
if ( ret < 0 )
goto failed_put_key ;
2012-07-25 19:53:36 +04:00
ret = register_key_type ( & key_type_id_resolver_legacy ) ;
if ( ret < 0 )
goto failed_reg_legacy ;
2012-01-18 19:31:45 +04:00
set_bit ( KEY_FLAG_ROOT_CAN_CLEAR , & keyring - > flags ) ;
2010-09-29 23:41:49 +04:00
cred - > thread_keyring = keyring ;
cred - > jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING ;
id_resolver_cache = cred ;
return 0 ;
2012-07-25 19:53:36 +04:00
failed_reg_legacy :
unregister_key_type ( & key_type_id_resolver ) ;
2010-09-29 23:41:49 +04:00
failed_put_key :
key_put ( keyring ) ;
failed_put_cred :
put_cred ( cred ) ;
return ret ;
}
2012-01-27 01:54:23 +04:00
static void nfs_idmap_quit_keyring ( void )
2010-09-29 23:41:49 +04:00
{
key_revoke ( id_resolver_cache - > thread_keyring ) ;
unregister_key_type ( & key_type_id_resolver ) ;
2012-07-25 19:53:36 +04:00
unregister_key_type ( & key_type_id_resolver_legacy ) ;
2010-09-29 23:41:49 +04:00
put_cred ( id_resolver_cache ) ;
}
/*
* Assemble the description to pass to request_key ( )
* This function will allocate a new string and update dest to point
* at it . The caller is responsible for freeing dest .
*
* On error 0 is returned . Otherwise , the length of dest is returned .
*/
static ssize_t nfs_idmap_get_desc ( const char * name , size_t namelen ,
const char * type , size_t typelen , char * * desc )
{
char * cp ;
size_t desclen = typelen + namelen + 2 ;
* desc = kmalloc ( desclen , GFP_KERNEL ) ;
2010-10-28 10:05:57 +04:00
if ( ! * desc )
2010-09-29 23:41:49 +04:00
return - ENOMEM ;
cp = * desc ;
memcpy ( cp , type , typelen ) ;
cp + = typelen ;
* cp + + = ' : ' ;
memcpy ( cp , name , namelen ) ;
cp + = namelen ;
* cp = ' \0 ' ;
return desclen ;
}
2013-06-26 22:09:46 +04:00
static struct key * nfs_idmap_request_key ( const char * name , size_t namelen ,
const char * type , struct idmap * idmap )
2010-09-29 23:41:49 +04:00
{
char * desc ;
2013-06-26 22:09:46 +04:00
struct key * rkey ;
2010-09-29 23:41:49 +04:00
ssize_t ret ;
ret = nfs_idmap_get_desc ( name , namelen , type , strlen ( type ) , & desc ) ;
if ( ret < = 0 )
2013-06-26 22:09:46 +04:00
return ERR_PTR ( ret ) ;
rkey = request_key ( & key_type_id_resolver , desc , " " ) ;
if ( IS_ERR ( rkey ) ) {
mutex_lock ( & idmap - > idmap_mutex ) ;
rkey = request_key_with_auxdata ( & key_type_id_resolver_legacy ,
desc , " " , 0 , idmap ) ;
mutex_unlock ( & idmap - > idmap_mutex ) ;
}
2014-07-17 23:45:08 +04:00
if ( ! IS_ERR ( rkey ) )
set_bit ( KEY_FLAG_ROOT_CAN_INVAL , & rkey - > flags ) ;
2013-06-26 22:09:46 +04:00
kfree ( desc ) ;
return rkey ;
}
static ssize_t nfs_idmap_get_key ( const char * name , size_t namelen ,
const char * type , void * data ,
size_t data_size , struct idmap * idmap )
{
const struct cred * saved_cred ;
struct key * rkey ;
struct user_key_payload * payload ;
ssize_t ret ;
2010-09-29 23:41:49 +04:00
saved_cred = override_creds ( id_resolver_cache ) ;
2013-06-26 22:09:46 +04:00
rkey = nfs_idmap_request_key ( name , namelen , type , idmap ) ;
2010-09-29 23:41:49 +04:00
revert_creds ( saved_cred ) ;
2012-02-24 23:14:51 +04:00
2010-09-29 23:41:49 +04:00
if ( IS_ERR ( rkey ) ) {
ret = PTR_ERR ( rkey ) ;
goto out ;
}
rcu_read_lock ( ) ;
rkey - > perm | = KEY_USR_VIEW ;
ret = key_validate ( rkey ) ;
if ( ret < 0 )
goto out_up ;
2013-08-22 04:06:11 +04:00
payload = rcu_dereference ( rkey - > payload . rcudata ) ;
2010-09-29 23:41:49 +04:00
if ( IS_ERR_OR_NULL ( payload ) ) {
ret = PTR_ERR ( payload ) ;
goto out_up ;
}
ret = payload - > datalen ;
if ( ret > 0 & & ret < = data_size )
memcpy ( data , payload - > data , ret ) ;
else
ret = - EINVAL ;
out_up :
rcu_read_unlock ( ) ;
key_put ( rkey ) ;
out :
return ret ;
}
/* ID -> Name */
2012-02-24 23:14:51 +04:00
static ssize_t nfs_idmap_lookup_name ( __u32 id , const char * type , char * buf ,
size_t buflen , struct idmap * idmap )
2010-09-29 23:41:49 +04:00
{
char id_str [ NFS_UINT_MAXLEN ] ;
int id_len ;
ssize_t ret ;
id_len = snprintf ( id_str , sizeof ( id_str ) , " %u " , id ) ;
2012-02-24 23:14:51 +04:00
ret = nfs_idmap_get_key ( id_str , id_len , type , buf , buflen , idmap ) ;
2010-09-29 23:41:49 +04:00
if ( ret < 0 )
return - EINVAL ;
return ret ;
}
/* Name -> ID */
2012-02-24 23:14:51 +04:00
static int nfs_idmap_lookup_id ( const char * name , size_t namelen , const char * type ,
__u32 * id , struct idmap * idmap )
2010-09-29 23:41:49 +04:00
{
char id_str [ NFS_UINT_MAXLEN ] ;
long id_long ;
ssize_t data_size ;
int ret = 0 ;
2012-02-24 23:14:51 +04:00
data_size = nfs_idmap_get_key ( name , namelen , type , id_str , NFS_UINT_MAXLEN , idmap ) ;
2010-09-29 23:41:49 +04:00
if ( data_size < = 0 ) {
ret = - EINVAL ;
} else {
2012-09-26 23:51:46 +04:00
ret = kstrtol ( id_str , 10 , & id_long ) ;
2010-09-29 23:41:49 +04:00
* id = ( __u32 ) id_long ;
}
return ret ;
}
2012-01-27 01:54:23 +04:00
/* idmap classic begins here */
2011-02-23 02:44:31 +03:00
2012-02-24 23:14:51 +04:00
enum {
Opt_find_uid , Opt_find_gid , Opt_find_user , Opt_find_group , Opt_find_err
2005-04-17 02:20:36 +04:00
} ;
2012-02-24 23:14:51 +04:00
static const match_table_t nfs_idmap_tokens = {
{ Opt_find_uid , " uid:%s " } ,
{ Opt_find_gid , " gid:%s " } ,
{ Opt_find_user , " user:%s " } ,
{ Opt_find_group , " group:%s " } ,
{ Opt_find_err , NULL }
2005-04-17 02:20:36 +04:00
} ;
2012-02-24 23:14:51 +04:00
static int nfs_idmap_legacy_upcall ( struct key_construction * , const char * , void * ) ;
2007-12-20 22:54:35 +03:00
static ssize_t idmap_pipe_downcall ( struct file * , const char __user * ,
size_t ) ;
2012-08-09 22:05:49 +04:00
static void idmap_release_pipe ( struct inode * ) ;
2007-12-20 22:54:35 +03:00
static void idmap_pipe_destroy_msg ( struct rpc_pipe_msg * ) ;
2005-04-17 02:20:36 +04:00
2009-08-09 23:14:15 +04:00
static const struct rpc_pipe_ops idmap_upcall_ops = {
2011-09-23 05:50:10 +04:00
. upcall = rpc_pipe_generic_upcall ,
2007-12-20 22:54:35 +03:00
. downcall = idmap_pipe_downcall ,
2012-08-09 22:05:49 +04:00
. release_pipe = idmap_release_pipe ,
2007-12-20 22:54:35 +03:00
. destroy_msg = idmap_pipe_destroy_msg ,
2005-04-17 02:20:36 +04:00
} ;
2012-03-11 21:11:00 +04:00
static struct key_type key_type_id_resolver_legacy = {
2012-07-25 19:53:36 +04:00
. name = " id_legacy " ,
2014-07-18 21:56:35 +04:00
. preparse = user_preparse ,
. free_preparse = user_free_preparse ,
. instantiate = generic_key_instantiate ,
2012-02-24 23:14:51 +04:00
. revoke = user_revoke ,
. destroy = user_destroy ,
. describe = user_describe ,
. read = user_read ,
. request_key = nfs_idmap_legacy_upcall ,
} ;
2013-08-27 01:16:17 +04:00
static void nfs_idmap_pipe_destroy ( struct dentry * dir ,
struct rpc_pipe_dir_object * pdo )
2012-01-10 16:13:11 +04:00
{
2013-08-27 01:16:17 +04:00
struct idmap * idmap = pdo - > pdo_data ;
struct rpc_pipe * pipe = idmap - > idmap_pipe ;
2013-08-27 01:26:51 +04:00
if ( pipe - > dentry ) {
2012-01-10 16:13:11 +04:00
rpc_unlink ( pipe - > dentry ) ;
2013-08-27 01:26:51 +04:00
pipe - > dentry = NULL ;
}
2012-01-10 16:13:11 +04:00
}
2013-08-27 01:16:17 +04:00
static int nfs_idmap_pipe_create ( struct dentry * dir ,
struct rpc_pipe_dir_object * pdo )
2012-01-10 16:13:11 +04:00
{
2013-08-27 01:16:17 +04:00
struct idmap * idmap = pdo - > pdo_data ;
struct rpc_pipe * pipe = idmap - > idmap_pipe ;
2012-01-10 16:13:11 +04:00
struct dentry * dentry ;
dentry = rpc_mkpipe_dentry ( dir , " idmap " , idmap , pipe ) ;
if ( IS_ERR ( dentry ) )
return PTR_ERR ( dentry ) ;
pipe - > dentry = dentry ;
return 0 ;
}
2013-08-27 01:16:17 +04:00
static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = {
. create = nfs_idmap_pipe_create ,
. destroy = nfs_idmap_pipe_destroy ,
} ;
2012-01-10 16:13:11 +04:00
2006-08-23 04:06:09 +04:00
int
2006-08-23 04:06:08 +04:00
nfs_idmap_new ( struct nfs_client * clp )
2005-04-17 02:20:36 +04:00
{
struct idmap * idmap ;
2011-12-26 16:44:06 +04:00
struct rpc_pipe * pipe ;
2006-08-23 04:06:09 +04:00
int error ;
2005-04-17 02:20:36 +04:00
2007-12-20 22:54:35 +03:00
idmap = kzalloc ( sizeof ( * idmap ) , GFP_KERNEL ) ;
if ( idmap = = NULL )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2013-08-27 01:16:17 +04:00
rpc_init_pipe_dir_object ( & idmap - > idmap_pdo ,
& nfs_idmap_pipe_dir_object_ops ,
idmap ) ;
2011-12-26 16:44:06 +04:00
pipe = rpc_mkpipe_data ( & idmap_upcall_ops , 0 ) ;
if ( IS_ERR ( pipe ) ) {
error = PTR_ERR ( pipe ) ;
2013-08-27 01:16:17 +04:00
goto err ;
2011-12-26 16:44:06 +04:00
}
idmap - > idmap_pipe = pipe ;
2012-06-20 22:35:28 +04:00
mutex_init ( & idmap - > idmap_mutex ) ;
2005-04-17 02:20:36 +04:00
2013-08-27 01:16:17 +04:00
error = rpc_add_pipe_dir_object ( clp - > cl_net ,
& clp - > cl_rpcclient - > cl_pipedir_objects ,
& idmap - > idmap_pdo ) ;
if ( error )
goto err_destroy_pipe ;
2005-04-17 02:20:36 +04:00
clp - > cl_idmap = idmap ;
2006-08-23 04:06:09 +04:00
return 0 ;
2013-08-27 01:16:17 +04:00
err_destroy_pipe :
rpc_destroy_pipe_data ( idmap - > idmap_pipe ) ;
err :
kfree ( idmap ) ;
return error ;
2005-04-17 02:20:36 +04:00
}
void
2006-08-23 04:06:08 +04:00
nfs_idmap_delete ( struct nfs_client * clp )
2005-04-17 02:20:36 +04:00
{
struct idmap * idmap = clp - > cl_idmap ;
if ( ! idmap )
return ;
clp - > cl_idmap = NULL ;
2013-08-27 01:16:17 +04:00
rpc_remove_pipe_dir_object ( clp - > cl_net ,
& clp - > cl_rpcclient - > cl_pipedir_objects ,
& idmap - > idmap_pdo ) ;
rpc_destroy_pipe_data ( idmap - > idmap_pipe ) ;
2005-04-17 02:20:36 +04:00
kfree ( idmap ) ;
}
2012-01-10 16:13:19 +04:00
int nfs_idmap_init ( void )
2005-04-17 02:20:36 +04:00
{
2012-01-27 01:54:23 +04:00
int ret ;
ret = nfs_idmap_init_keyring ( ) ;
if ( ret ! = 0 )
goto out ;
out :
return ret ;
2005-04-17 02:20:36 +04:00
}
2012-01-10 16:13:19 +04:00
void nfs_idmap_quit ( void )
2005-04-17 02:20:36 +04:00
{
2012-01-27 01:54:23 +04:00
nfs_idmap_quit_keyring ( ) ;
2005-04-17 02:20:36 +04:00
}
2012-08-09 22:05:49 +04:00
static int nfs_idmap_prepare_message ( char * desc , struct idmap * idmap ,
struct idmap_msg * im ,
2012-02-24 23:14:51 +04:00
struct rpc_pipe_msg * msg )
2005-04-17 02:20:36 +04:00
{
2012-02-24 23:14:51 +04:00
substring_t substr ;
int token , ret ;
2005-04-17 02:20:36 +04:00
2012-02-24 23:14:51 +04:00
im - > im_type = IDMAP_TYPE_GROUP ;
token = match_token ( desc , nfs_idmap_tokens , & substr ) ;
2005-04-17 02:20:36 +04:00
2012-02-24 23:14:51 +04:00
switch ( token ) {
case Opt_find_uid :
im - > im_type = IDMAP_TYPE_USER ;
case Opt_find_gid :
im - > im_conv = IDMAP_CONV_NAMETOID ;
ret = match_strlcpy ( im - > im_name , & substr , IDMAP_NAMESZ ) ;
break ;
2005-04-17 02:20:36 +04:00
2012-02-24 23:14:51 +04:00
case Opt_find_user :
im - > im_type = IDMAP_TYPE_USER ;
case Opt_find_group :
im - > im_conv = IDMAP_CONV_IDTONAME ;
ret = match_int ( & substr , & im - > im_id ) ;
break ;
2005-04-17 02:20:36 +04:00
2012-02-24 23:14:51 +04:00
default :
ret = - EINVAL ;
2005-04-17 02:20:36 +04:00
goto out ;
}
2012-02-24 23:14:51 +04:00
msg - > data = im ;
msg - > len = sizeof ( struct idmap_msg ) ;
2005-04-17 02:20:36 +04:00
2012-02-24 23:14:51 +04:00
out :
2007-12-20 22:54:35 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2012-09-27 23:44:19 +04:00
static bool
nfs_idmap_prepare_pipe_upcall ( struct idmap * idmap ,
2012-09-28 00:15:00 +04:00
struct idmap_legacy_upcalldata * data )
2012-09-27 23:44:19 +04:00
{
2012-09-28 00:15:00 +04:00
if ( idmap - > idmap_upcall_data ! = NULL ) {
2012-09-27 23:44:19 +04:00
WARN_ON_ONCE ( 1 ) ;
return false ;
}
2012-09-28 00:15:00 +04:00
idmap - > idmap_upcall_data = data ;
2012-09-27 23:44:19 +04:00
return true ;
}
static void
nfs_idmap_complete_pipe_upcall_locked ( struct idmap * idmap , int ret )
{
2012-09-28 00:15:00 +04:00
struct key_construction * cons = idmap - > idmap_upcall_data - > key_cons ;
2012-09-27 23:44:19 +04:00
2012-09-28 00:15:00 +04:00
kfree ( idmap - > idmap_upcall_data ) ;
idmap - > idmap_upcall_data = NULL ;
2012-09-27 23:44:19 +04:00
complete_request_key ( cons , ret ) ;
}
static void
nfs_idmap_abort_pipe_upcall ( struct idmap * idmap , int ret )
{
2012-09-28 00:15:00 +04:00
if ( idmap - > idmap_upcall_data ! = NULL )
2012-09-27 23:44:19 +04:00
nfs_idmap_complete_pipe_upcall_locked ( idmap , ret ) ;
}
2012-02-24 23:14:51 +04:00
static int nfs_idmap_legacy_upcall ( struct key_construction * cons ,
const char * op ,
void * aux )
2005-04-17 02:20:36 +04:00
{
2012-08-09 22:05:49 +04:00
struct idmap_legacy_upcalldata * data ;
2012-02-24 23:14:51 +04:00
struct rpc_pipe_msg * msg ;
2005-04-17 02:20:36 +04:00
struct idmap_msg * im ;
2012-02-24 23:14:51 +04:00
struct idmap * idmap = ( struct idmap * ) aux ;
struct key * key = cons - > key ;
2012-05-14 23:45:28 +04:00
int ret = - ENOMEM ;
2005-04-17 02:20:36 +04:00
2012-02-24 23:14:51 +04:00
/* msg and im are freed in idmap_pipe_destroy_msg */
2012-08-09 22:05:51 +04:00
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
2012-08-09 22:05:49 +04:00
if ( ! data )
2012-02-24 23:14:51 +04:00
goto out1 ;
2005-04-17 02:20:36 +04:00
2012-08-09 22:05:49 +04:00
msg = & data - > pipe_msg ;
im = & data - > idmap_msg ;
data - > idmap = idmap ;
2012-10-03 00:01:38 +04:00
data - > key_cons = cons ;
2012-08-09 22:05:49 +04:00
ret = nfs_idmap_prepare_message ( key - > description , idmap , im , msg ) ;
2012-02-24 23:14:51 +04:00
if ( ret < 0 )
goto out2 ;
2005-04-17 02:20:36 +04:00
2012-09-27 23:44:19 +04:00
ret = - EAGAIN ;
2012-09-28 00:15:00 +04:00
if ( ! nfs_idmap_prepare_pipe_upcall ( idmap , data ) )
2012-09-28 20:03:09 +04:00
goto out2 ;
2005-04-17 02:20:36 +04:00
2012-03-12 19:33:00 +04:00
ret = rpc_queue_upcall ( idmap - > idmap_pipe , msg ) ;
if ( ret < 0 )
2012-09-27 23:44:19 +04:00
nfs_idmap_abort_pipe_upcall ( idmap , ret ) ;
2005-04-17 02:20:36 +04:00
2012-03-12 19:33:00 +04:00
return ret ;
2012-02-24 23:14:51 +04:00
out2 :
2012-08-09 22:05:49 +04:00
kfree ( data ) ;
2012-02-24 23:14:51 +04:00
out1 :
2012-07-25 19:53:36 +04:00
complete_request_key ( cons , ret ) ;
2007-12-20 22:54:35 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2013-03-08 21:56:37 +04:00
static int nfs_idmap_instantiate ( struct key * key , struct key * authkey , char * data , size_t datalen )
2005-04-17 02:20:36 +04:00
{
2013-03-08 21:56:37 +04:00
return key_instantiate_and_link ( key , data , datalen ,
2012-02-24 23:14:51 +04:00
id_resolver_cache - > thread_keyring ,
authkey ) ;
}
2005-04-17 02:20:36 +04:00
2012-09-28 00:15:00 +04:00
static int nfs_idmap_read_and_verify_message ( struct idmap_msg * im ,
struct idmap_msg * upcall ,
struct key * key , struct key * authkey )
2012-02-24 23:14:51 +04:00
{
char id_str [ NFS_UINT_MAXLEN ] ;
2013-03-08 21:56:37 +04:00
size_t len ;
2012-09-28 00:15:00 +04:00
int ret = - ENOKEY ;
2005-04-17 02:20:36 +04:00
2012-09-28 00:15:00 +04:00
/* ret = -ENOKEY */
if ( upcall - > im_type ! = im - > im_type | | upcall - > im_conv ! = im - > im_conv )
goto out ;
2012-02-24 23:14:51 +04:00
switch ( im - > im_conv ) {
case IDMAP_CONV_NAMETOID :
2012-09-28 00:15:00 +04:00
if ( strcmp ( upcall - > im_name , im - > im_name ) ! = 0 )
break ;
2013-03-08 21:56:37 +04:00
/* Note: here we store the NUL terminator too */
len = sprintf ( id_str , " %d " , im - > im_id ) + 1 ;
ret = nfs_idmap_instantiate ( key , authkey , id_str , len ) ;
2012-02-24 23:14:51 +04:00
break ;
case IDMAP_CONV_IDTONAME :
2012-09-28 00:15:00 +04:00
if ( upcall - > im_id ! = im - > im_id )
break ;
2013-03-08 21:56:37 +04:00
len = strlen ( im - > im_name ) ;
ret = nfs_idmap_instantiate ( key , authkey , im - > im_name , len ) ;
2012-02-24 23:14:51 +04:00
break ;
2012-09-28 00:15:00 +04:00
default :
ret = - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2012-09-28 00:15:00 +04:00
out :
2005-04-17 02:20:36 +04:00
return ret ;
}
static ssize_t
idmap_pipe_downcall ( struct file * filp , const char __user * src , size_t mlen )
{
2013-01-24 02:07:38 +04:00
struct rpc_inode * rpci = RPC_I ( file_inode ( filp ) ) ;
2005-04-17 02:20:36 +04:00
struct idmap * idmap = ( struct idmap * ) rpci - > private ;
2012-07-25 19:53:36 +04:00
struct key_construction * cons ;
2012-02-24 23:14:51 +04:00
struct idmap_msg im ;
2007-12-20 22:54:49 +03:00
size_t namelen_in ;
2012-09-27 23:44:19 +04:00
int ret = - ENOKEY ;
2005-04-17 02:20:36 +04:00
2012-07-25 19:53:36 +04:00
/* If instantiation is successful, anyone waiting for key construction
* will have been woken up and someone else may now have used
* idmap_key_cons - so after this point we may no longer touch it .
*/
2012-09-28 00:15:00 +04:00
if ( idmap - > idmap_upcall_data = = NULL )
2012-09-27 23:44:19 +04:00
goto out_noupcall ;
2012-07-25 19:53:36 +04:00
2012-09-28 00:15:00 +04:00
cons = idmap - > idmap_upcall_data - > key_cons ;
2012-07-25 19:53:36 +04:00
2012-02-24 23:14:51 +04:00
if ( mlen ! = sizeof ( im ) ) {
ret = - ENOSPC ;
2005-04-17 02:20:36 +04:00
goto out ;
}
2012-02-24 23:14:51 +04:00
if ( copy_from_user ( & im , src , mlen ) ! = 0 ) {
ret = - EFAULT ;
2005-04-17 02:20:36 +04:00
goto out ;
2012-02-24 23:14:51 +04:00
}
2005-04-17 02:20:36 +04:00
2012-02-24 23:14:51 +04:00
if ( ! ( im . im_status & IDMAP_STATUS_SUCCESS ) ) {
2012-08-09 22:05:50 +04:00
ret = - ENOKEY ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2012-02-24 23:14:51 +04:00
namelen_in = strnlen ( im . im_name , IDMAP_NAMESZ ) ;
if ( namelen_in = = 0 | | namelen_in = = IDMAP_NAMESZ ) {
ret = - EINVAL ;
2005-04-17 02:20:36 +04:00
goto out ;
2012-09-28 00:15:00 +04:00
}
2005-04-17 02:20:36 +04:00
2012-09-28 00:15:00 +04:00
ret = nfs_idmap_read_and_verify_message ( & im ,
& idmap - > idmap_upcall_data - > idmap_msg ,
cons - > key , cons - > authkey ) ;
2012-02-24 23:14:51 +04:00
if ( ret > = 0 ) {
key_set_timeout ( cons - > key , nfs_idmap_cache_timeout ) ;
ret = mlen ;
}
2005-04-17 02:20:36 +04:00
out :
2012-09-27 23:44:19 +04:00
nfs_idmap_complete_pipe_upcall_locked ( idmap , ret ) ;
out_noupcall :
2005-04-17 02:20:36 +04:00
return ret ;
}
2005-05-06 03:16:09 +04:00
static void
2005-04-17 02:20:36 +04:00
idmap_pipe_destroy_msg ( struct rpc_pipe_msg * msg )
{
2012-08-09 22:05:49 +04:00
struct idmap_legacy_upcalldata * data = container_of ( msg ,
struct idmap_legacy_upcalldata ,
pipe_msg ) ;
struct idmap * idmap = data - > idmap ;
2012-09-27 23:44:19 +04:00
if ( msg - > errno )
nfs_idmap_abort_pipe_upcall ( idmap , msg - > errno ) ;
2012-08-09 22:05:49 +04:00
}
static void
idmap_release_pipe ( struct inode * inode )
{
struct rpc_inode * rpci = RPC_I ( inode ) ;
struct idmap * idmap = ( struct idmap * ) rpci - > private ;
2012-09-27 23:44:19 +04:00
nfs_idmap_abort_pipe_upcall ( idmap , - EPIPE ) ;
2005-04-17 02:20:36 +04:00
}
2013-02-01 15:21:47 +04:00
int nfs_map_name_to_uid ( const struct nfs_server * server , const char * name , size_t namelen , kuid_t * uid )
2005-04-17 02:20:36 +04:00
{
2011-02-23 02:44:31 +03:00
struct idmap * idmap = server - > nfs_client - > cl_idmap ;
2013-02-01 15:21:47 +04:00
__u32 id = - 1 ;
int ret = 0 ;
2005-04-17 02:20:36 +04:00
2013-02-01 15:21:47 +04:00
if ( ! nfs_map_string_to_numeric ( name , namelen , & id ) )
ret = nfs_idmap_lookup_id ( name , namelen , " uid " , & id , idmap ) ;
if ( ret = = 0 ) {
* uid = make_kuid ( & init_user_ns , id ) ;
if ( ! uid_valid ( * uid ) )
ret = - ERANGE ;
}
2013-08-13 19:34:01 +04:00
trace_nfs4_map_name_to_uid ( name , namelen , id , ret ) ;
2013-02-01 15:21:47 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2013-02-01 15:21:47 +04:00
int nfs_map_group_to_gid ( const struct nfs_server * server , const char * name , size_t namelen , kgid_t * gid )
2005-04-17 02:20:36 +04:00
{
2011-02-23 02:44:31 +03:00
struct idmap * idmap = server - > nfs_client - > cl_idmap ;
2013-02-01 15:21:47 +04:00
__u32 id = - 1 ;
int ret = 0 ;
2005-04-17 02:20:36 +04:00
2013-02-01 15:21:47 +04:00
if ( ! nfs_map_string_to_numeric ( name , namelen , & id ) )
ret = nfs_idmap_lookup_id ( name , namelen , " gid " , & id , idmap ) ;
if ( ret = = 0 ) {
* gid = make_kgid ( & init_user_ns , id ) ;
if ( ! gid_valid ( * gid ) )
ret = - ERANGE ;
}
2013-08-13 19:34:01 +04:00
trace_nfs4_map_group_to_gid ( name , namelen , id , ret ) ;
2013-02-01 15:21:47 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2013-02-01 15:21:47 +04:00
int nfs_map_uid_to_name ( const struct nfs_server * server , kuid_t uid , char * buf , size_t buflen )
2005-04-17 02:20:36 +04:00
{
2011-02-23 02:44:31 +03:00
struct idmap * idmap = server - > nfs_client - > cl_idmap ;
2011-02-23 02:44:32 +03:00
int ret = - EINVAL ;
2013-02-01 15:21:47 +04:00
__u32 id ;
2005-04-17 02:20:36 +04:00
2013-02-01 15:21:47 +04:00
id = from_kuid ( & init_user_ns , uid ) ;
2011-02-23 02:44:32 +03:00
if ( ! ( server - > caps & NFS_CAP_UIDGID_NOMAP ) )
2013-02-01 15:21:47 +04:00
ret = nfs_idmap_lookup_name ( id , " user " , buf , buflen , idmap ) ;
2011-02-23 02:44:31 +03:00
if ( ret < 0 )
2013-02-01 15:21:47 +04:00
ret = nfs_map_numeric_to_string ( id , buf , buflen ) ;
2013-08-13 19:34:01 +04:00
trace_nfs4_map_uid_to_name ( buf , ret , id , ret ) ;
2011-02-23 02:44:31 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2013-02-01 15:21:47 +04:00
int nfs_map_gid_to_group ( const struct nfs_server * server , kgid_t gid , char * buf , size_t buflen )
2005-04-17 02:20:36 +04:00
{
2011-02-23 02:44:31 +03:00
struct idmap * idmap = server - > nfs_client - > cl_idmap ;
2011-02-23 02:44:32 +03:00
int ret = - EINVAL ;
2013-02-01 15:21:47 +04:00
__u32 id ;
2005-04-17 02:20:36 +04:00
2013-02-01 15:21:47 +04:00
id = from_kgid ( & init_user_ns , gid ) ;
2011-02-23 02:44:32 +03:00
if ( ! ( server - > caps & NFS_CAP_UIDGID_NOMAP ) )
2013-02-01 15:21:47 +04:00
ret = nfs_idmap_lookup_name ( id , " group " , buf , buflen , idmap ) ;
2011-02-23 02:44:31 +03:00
if ( ret < 0 )
2013-02-01 15:21:47 +04:00
ret = nfs_map_numeric_to_string ( id , buf , buflen ) ;
2013-08-13 19:34:01 +04:00
trace_nfs4_map_gid_to_group ( buf , ret , id , ret ) ;
2011-02-23 02:44:31 +03:00
return ret ;
2005-04-17 02:20:36 +04:00
}