2005-04-17 02:20:36 +04:00
/*
* linux / net / sunrpc / auth . c
*
* Generic RPC client authentication API .
*
* Copyright ( C ) 1996 , Olaf Kirch < okir @ monad . swb . de >
*/
# include <linux/types.h>
# include <linux/sched.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/errno.h>
2008-03-12 21:40:14 +03:00
# include <linux/hash.h>
2005-04-17 02:20:36 +04:00
# include <linux/sunrpc/clnt.h>
# include <linux/spinlock.h>
# ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
# endif
2010-07-31 22:29:08 +04:00
# define RPC_CREDCACHE_DEFAULT_HASHBITS (4)
struct rpc_cred_cache {
struct hlist_head * hashtable ;
unsigned int hashbits ;
spinlock_t lock ;
} ;
static unsigned int auth_hashbits = RPC_CREDCACHE_DEFAULT_HASHBITS ;
2007-06-10 00:15:46 +04:00
static DEFINE_SPINLOCK ( rpc_authflavor_lock ) ;
2007-06-24 04:17:58 +04:00
static const struct rpc_authops * auth_flavors [ RPC_AUTH_MAXFLAVOR ] = {
2005-04-17 02:20:36 +04:00
& authnull_ops , /* AUTH_NULL */
& authunix_ops , /* AUTH_UNIX */
NULL , /* others can be loadable modules */
} ;
2007-06-24 03:45:36 +04:00
static LIST_HEAD ( cred_unused ) ;
2007-06-26 01:11:20 +04:00
static unsigned long number_cred_unused ;
2007-06-24 03:45:36 +04:00
2010-09-13 03:55:26 +04:00
# define MAX_HASHTABLE_BITS (14)
2010-08-04 06:11:22 +04:00
static int param_set_hashtbl_sz ( const char * val , const struct kernel_param * kp )
2010-07-31 22:29:08 +04:00
{
unsigned long num ;
unsigned int nbits ;
int ret ;
if ( ! val )
goto out_inval ;
ret = strict_strtoul ( val , 0 , & num ) ;
if ( ret = = - EINVAL )
goto out_inval ;
nbits = fls ( num ) ;
if ( num > ( 1U < < nbits ) )
nbits + + ;
if ( nbits > MAX_HASHTABLE_BITS | | nbits < 2 )
goto out_inval ;
* ( unsigned int * ) kp - > arg = nbits ;
return 0 ;
out_inval :
return - EINVAL ;
}
2010-08-04 06:11:22 +04:00
static int param_get_hashtbl_sz ( char * buffer , const struct kernel_param * kp )
2010-07-31 22:29:08 +04:00
{
unsigned int nbits ;
nbits = * ( unsigned int * ) kp - > arg ;
return sprintf ( buffer , " %u " , 1U < < nbits ) ;
}
# define param_check_hashtbl_sz(name, p) __param_check(name, p, unsigned int);
2010-08-04 06:11:22 +04:00
static struct kernel_param_ops param_ops_hashtbl_sz = {
. set = param_set_hashtbl_sz ,
. get = param_get_hashtbl_sz ,
} ;
2010-07-31 22:29:08 +04:00
module_param_named ( auth_hashtable_size , auth_hashbits , hashtbl_sz , 0644 ) ;
MODULE_PARM_DESC ( auth_hashtable_size , " RPC credential cache hashtable size " ) ;
2005-04-17 02:20:36 +04:00
static u32
pseudoflavor_to_flavor ( u32 flavor ) {
if ( flavor > = RPC_AUTH_MAXFLAVOR )
return RPC_AUTH_GSS ;
return flavor ;
}
int
2007-06-24 04:17:58 +04:00
rpcauth_register ( const struct rpc_authops * ops )
2005-04-17 02:20:36 +04:00
{
rpc_authflavor_t flavor ;
2007-06-10 00:15:46 +04:00
int ret = - EPERM ;
2005-04-17 02:20:36 +04:00
if ( ( flavor = ops - > au_flavor ) > = RPC_AUTH_MAXFLAVOR )
return - EINVAL ;
2007-06-10 00:15:46 +04:00
spin_lock ( & rpc_authflavor_lock ) ;
if ( auth_flavors [ flavor ] = = NULL ) {
auth_flavors [ flavor ] = ops ;
ret = 0 ;
}
spin_unlock ( & rpc_authflavor_lock ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpcauth_register ) ;
2005-04-17 02:20:36 +04:00
int
2007-06-24 04:17:58 +04:00
rpcauth_unregister ( const struct rpc_authops * ops )
2005-04-17 02:20:36 +04:00
{
rpc_authflavor_t flavor ;
2007-06-10 00:15:46 +04:00
int ret = - EPERM ;
2005-04-17 02:20:36 +04:00
if ( ( flavor = ops - > au_flavor ) > = RPC_AUTH_MAXFLAVOR )
return - EINVAL ;
2007-06-10 00:15:46 +04:00
spin_lock ( & rpc_authflavor_lock ) ;
if ( auth_flavors [ flavor ] = = ops ) {
auth_flavors [ flavor ] = NULL ;
ret = 0 ;
}
spin_unlock ( & rpc_authflavor_lock ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpcauth_unregister ) ;
2005-04-17 02:20:36 +04:00
struct rpc_auth *
rpcauth_create ( rpc_authflavor_t pseudoflavor , struct rpc_clnt * clnt )
{
struct rpc_auth * auth ;
2007-06-24 04:17:58 +04:00
const struct rpc_authops * ops ;
2005-04-17 02:20:36 +04:00
u32 flavor = pseudoflavor_to_flavor ( pseudoflavor ) ;
2006-03-20 21:44:08 +03:00
auth = ERR_PTR ( - EINVAL ) ;
if ( flavor > = RPC_AUTH_MAXFLAVOR )
goto out ;
if ( ( ops = auth_flavors [ flavor ] ) = = NULL )
request_module ( " rpc-auth-%u " , flavor ) ;
2007-06-10 00:15:46 +04:00
spin_lock ( & rpc_authflavor_lock ) ;
ops = auth_flavors [ flavor ] ;
if ( ops = = NULL | | ! try_module_get ( ops - > owner ) ) {
spin_unlock ( & rpc_authflavor_lock ) ;
2006-03-20 21:44:08 +03:00
goto out ;
2007-06-10 00:15:46 +04:00
}
spin_unlock ( & rpc_authflavor_lock ) ;
2005-04-17 02:20:36 +04:00
auth = ops - > create ( clnt , pseudoflavor ) ;
2007-06-10 00:15:46 +04:00
module_put ( ops - > owner ) ;
2005-06-22 21:16:23 +04:00
if ( IS_ERR ( auth ) )
return auth ;
2005-04-17 02:20:36 +04:00
if ( clnt - > cl_auth )
2007-06-23 18:46:47 +04:00
rpcauth_release ( clnt - > cl_auth ) ;
2005-04-17 02:20:36 +04:00
clnt - > cl_auth = auth ;
2006-03-20 21:44:08 +03:00
out :
2005-04-17 02:20:36 +04:00
return auth ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpcauth_create ) ;
2005-04-17 02:20:36 +04:00
void
2007-06-23 18:46:47 +04:00
rpcauth_release ( struct rpc_auth * auth )
2005-04-17 02:20:36 +04:00
{
if ( ! atomic_dec_and_test ( & auth - > au_count ) )
return ;
auth - > au_ops - > destroy ( auth ) ;
}
static DEFINE_SPINLOCK ( rpc_credcache_lock ) ;
2007-06-24 23:55:26 +04:00
static void
rpcauth_unhash_cred_locked ( struct rpc_cred * cred )
{
hlist_del_rcu ( & cred - > cr_hash ) ;
smp_mb__before_clear_bit ( ) ;
clear_bit ( RPCAUTH_CRED_HASHED , & cred - > cr_flags ) ;
}
2009-12-03 16:10:17 +03:00
static int
2007-06-24 23:57:57 +04:00
rpcauth_unhash_cred ( struct rpc_cred * cred )
{
spinlock_t * cache_lock ;
2009-12-03 16:10:17 +03:00
int ret ;
2007-06-24 23:57:57 +04:00
cache_lock = & cred - > cr_auth - > au_credcache - > lock ;
spin_lock ( cache_lock ) ;
2009-12-03 16:10:17 +03:00
ret = atomic_read ( & cred - > cr_count ) = = 0 ;
if ( ret )
2007-06-24 23:57:57 +04:00
rpcauth_unhash_cred_locked ( cred ) ;
spin_unlock ( cache_lock ) ;
2009-12-03 16:10:17 +03:00
return ret ;
2007-06-24 23:57:57 +04:00
}
2005-04-17 02:20:36 +04:00
/*
* Initialize RPC credential cache
*/
int
2007-06-26 01:11:20 +04:00
rpcauth_init_credcache ( struct rpc_auth * auth )
2005-04-17 02:20:36 +04:00
{
struct rpc_cred_cache * new ;
2010-07-31 22:29:07 +04:00
unsigned int hashsize ;
2005-04-17 02:20:36 +04:00
2006-01-12 02:56:43 +03:00
new = kmalloc ( sizeof ( * new ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! new )
2010-07-31 22:29:08 +04:00
goto out_nocache ;
new - > hashbits = auth_hashbits ;
2010-07-31 22:29:07 +04:00
hashsize = 1U < < new - > hashbits ;
2010-07-31 22:29:08 +04:00
new - > hashtable = kcalloc ( hashsize , sizeof ( new - > hashtable [ 0 ] ) , GFP_KERNEL ) ;
if ( ! new - > hashtable )
goto out_nohashtbl ;
2007-06-24 23:57:57 +04:00
spin_lock_init ( & new - > lock ) ;
2005-04-17 02:20:36 +04:00
auth - > au_credcache = new ;
return 0 ;
2010-07-31 22:29:08 +04:00
out_nohashtbl :
kfree ( new ) ;
out_nocache :
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpcauth_init_credcache ) ;
2005-04-17 02:20:36 +04:00
/*
* Destroy a list of credentials
*/
static inline
2007-06-24 03:45:36 +04:00
void rpcauth_destroy_credlist ( struct list_head * head )
2005-04-17 02:20:36 +04:00
{
struct rpc_cred * cred ;
2007-06-24 03:45:36 +04:00
while ( ! list_empty ( head ) ) {
cred = list_entry ( head - > next , struct rpc_cred , cr_lru ) ;
list_del_init ( & cred - > cr_lru ) ;
2005-04-17 02:20:36 +04:00
put_rpccred ( cred ) ;
}
}
/*
* Clear the RPC credential cache , and delete those credentials
* that are not referenced .
*/
void
2007-06-09 23:41:42 +04:00
rpcauth_clear_credcache ( struct rpc_cred_cache * cache )
2005-04-17 02:20:36 +04:00
{
2007-06-24 03:45:36 +04:00
LIST_HEAD ( free ) ;
struct hlist_head * head ;
2005-04-17 02:20:36 +04:00
struct rpc_cred * cred ;
2010-07-31 22:29:07 +04:00
unsigned int hashsize = 1U < < cache - > hashbits ;
2005-04-17 02:20:36 +04:00
int i ;
spin_lock ( & rpc_credcache_lock ) ;
2007-06-24 23:57:57 +04:00
spin_lock ( & cache - > lock ) ;
2010-07-31 22:29:07 +04:00
for ( i = 0 ; i < hashsize ; i + + ) {
2007-06-24 03:45:36 +04:00
head = & cache - > hashtable [ i ] ;
while ( ! hlist_empty ( head ) ) {
cred = hlist_entry ( head - > first , struct rpc_cred , cr_hash ) ;
get_rpccred ( cred ) ;
2007-06-26 01:11:20 +04:00
if ( ! list_empty ( & cred - > cr_lru ) ) {
list_del ( & cred - > cr_lru ) ;
number_cred_unused - - ;
}
list_add_tail ( & cred - > cr_lru , & free ) ;
2007-06-24 23:55:26 +04:00
rpcauth_unhash_cred_locked ( cred ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-06-24 23:57:57 +04:00
spin_unlock ( & cache - > lock ) ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & rpc_credcache_lock ) ;
rpcauth_destroy_credlist ( & free ) ;
}
2007-06-09 23:41:42 +04:00
/*
* Destroy the RPC credential cache
*/
void
rpcauth_destroy_credcache ( struct rpc_auth * auth )
{
struct rpc_cred_cache * cache = auth - > au_credcache ;
if ( cache ) {
auth - > au_credcache = NULL ;
rpcauth_clear_credcache ( cache ) ;
2010-07-31 22:29:08 +04:00
kfree ( cache - > hashtable ) ;
2007-06-09 23:41:42 +04:00
kfree ( cache ) ;
}
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpcauth_destroy_credcache ) ;
2007-06-09 23:41:42 +04:00
2008-04-15 02:13:37 +04:00
# define RPC_AUTH_EXPIRY_MORATORIUM (60 * HZ)
2007-06-24 03:45:36 +04:00
/*
* Remove stale credentials . Avoid sleeping inside the loop .
*/
2007-06-26 01:11:20 +04:00
static int
rpcauth_prune_expired ( struct list_head * free , int nr_to_scan )
2005-04-17 02:20:36 +04:00
{
2007-06-24 23:57:57 +04:00
spinlock_t * cache_lock ;
2008-10-28 22:21:41 +03:00
struct rpc_cred * cred , * next ;
2008-04-15 02:13:37 +04:00
unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM ;
2007-06-24 03:45:36 +04:00
2008-10-28 22:21:41 +03:00
list_for_each_entry_safe ( cred , next , & cred_unused , cr_lru ) {
2010-05-13 20:51:06 +04:00
if ( nr_to_scan - - = = 0 )
break ;
2010-05-13 20:51:06 +04:00
/*
* Enforce a 60 second garbage collection moratorium
* Note that the cred_unused list must be time - ordered .
*/
2010-04-22 23:35:55 +04:00
if ( time_in_range ( cred - > cr_expire , expired , jiffies ) & &
2008-10-28 22:21:41 +03:00
test_bit ( RPCAUTH_CRED_HASHED , & cred - > cr_flags ) ! = 0 )
2010-05-13 20:51:06 +04:00
return 0 ;
2008-10-28 22:21:41 +03:00
2007-06-24 03:45:36 +04:00
list_del_init ( & cred - > cr_lru ) ;
2007-06-26 01:11:20 +04:00
number_cred_unused - - ;
2007-06-24 03:45:36 +04:00
if ( atomic_read ( & cred - > cr_count ) ! = 0 )
continue ;
2008-10-28 22:21:41 +03:00
2007-06-24 23:57:57 +04:00
cache_lock = & cred - > cr_auth - > au_credcache - > lock ;
spin_lock ( cache_lock ) ;
if ( atomic_read ( & cred - > cr_count ) = = 0 ) {
get_rpccred ( cred ) ;
list_add_tail ( & cred - > cr_lru , free ) ;
rpcauth_unhash_cred_locked ( cred ) ;
}
spin_unlock ( cache_lock ) ;
2005-04-17 02:20:36 +04:00
}
2010-05-13 20:51:06 +04:00
return ( number_cred_unused / 100 ) * sysctl_vfs_cache_pressure ;
2005-04-17 02:20:36 +04:00
}
/*
2007-06-26 01:11:20 +04:00
* Run memory cache shrinker .
2005-04-17 02:20:36 +04:00
*/
2007-06-26 01:11:20 +04:00
static int
2010-07-21 09:33:01 +04:00
rpcauth_cache_shrinker ( struct shrinker * shrink , int nr_to_scan , gfp_t gfp_mask )
2005-04-17 02:20:36 +04:00
{
2007-06-26 01:11:20 +04:00
LIST_HEAD ( free ) ;
int res ;
2010-05-13 20:51:03 +04:00
if ( ( gfp_mask & GFP_KERNEL ) ! = GFP_KERNEL )
return ( nr_to_scan = = 0 ) ? 0 : - 1 ;
2007-06-26 01:11:20 +04:00
if ( list_empty ( & cred_unused ) )
return 0 ;
2007-06-24 23:55:26 +04:00
spin_lock ( & rpc_credcache_lock ) ;
2010-05-13 20:51:06 +04:00
res = rpcauth_prune_expired ( & free , nr_to_scan ) ;
2007-06-24 23:55:26 +04:00
spin_unlock ( & rpc_credcache_lock ) ;
2007-06-26 01:11:20 +04:00
rpcauth_destroy_credlist ( & free ) ;
return res ;
2005-04-17 02:20:36 +04:00
}
/*
* Look up a process ' credentials in the authentication cache
*/
struct rpc_cred *
rpcauth_lookup_credcache ( struct rpc_auth * auth , struct auth_cred * acred ,
2006-02-01 20:18:36 +03:00
int flags )
2005-04-17 02:20:36 +04:00
{
2007-06-24 03:45:36 +04:00
LIST_HEAD ( free ) ;
2005-04-17 02:20:36 +04:00
struct rpc_cred_cache * cache = auth - > au_credcache ;
2007-06-24 03:45:36 +04:00
struct hlist_node * pos ;
2007-06-24 23:55:26 +04:00
struct rpc_cred * cred = NULL ,
* entry , * new ;
2008-03-12 21:40:14 +03:00
unsigned int nr ;
2010-07-31 22:29:07 +04:00
nr = hash_long ( acred - > uid , cache - > hashbits ) ;
2005-04-17 02:20:36 +04:00
2007-06-24 23:55:26 +04:00
rcu_read_lock ( ) ;
hlist_for_each_entry_rcu ( entry , pos , & cache - > hashtable [ nr ] , cr_hash ) {
2007-06-24 03:45:36 +04:00
if ( ! entry - > cr_ops - > crmatch ( acred , entry , flags ) )
continue ;
2007-06-24 23:57:57 +04:00
spin_lock ( & cache - > lock ) ;
2007-06-24 23:55:26 +04:00
if ( test_bit ( RPCAUTH_CRED_HASHED , & entry - > cr_flags ) = = 0 ) {
2007-06-24 23:57:57 +04:00
spin_unlock ( & cache - > lock ) ;
2007-06-24 23:55:26 +04:00
continue ;
}
2007-06-24 03:45:36 +04:00
cred = get_rpccred ( entry ) ;
2007-06-24 23:57:57 +04:00
spin_unlock ( & cache - > lock ) ;
2007-06-24 03:45:36 +04:00
break ;
2005-04-17 02:20:36 +04:00
}
2007-06-24 23:55:26 +04:00
rcu_read_unlock ( ) ;
2007-06-24 23:57:57 +04:00
if ( cred ! = NULL )
2007-06-24 23:55:26 +04:00
goto found ;
2005-04-17 02:20:36 +04:00
2007-06-24 23:55:26 +04:00
new = auth - > au_ops - > crcreate ( auth , acred , flags ) ;
if ( IS_ERR ( new ) ) {
cred = new ;
goto out ;
}
2005-04-17 02:20:36 +04:00
2007-06-24 23:57:57 +04:00
spin_lock ( & cache - > lock ) ;
2007-06-24 23:55:26 +04:00
hlist_for_each_entry ( entry , pos , & cache - > hashtable [ nr ] , cr_hash ) {
if ( ! entry - > cr_ops - > crmatch ( acred , entry , flags ) )
continue ;
cred = get_rpccred ( entry ) ;
break ;
}
if ( cred = = NULL ) {
2007-06-24 03:55:31 +04:00
cred = new ;
2007-06-24 23:55:26 +04:00
set_bit ( RPCAUTH_CRED_HASHED , & cred - > cr_flags ) ;
hlist_add_head_rcu ( & cred - > cr_hash , & cache - > hashtable [ nr ] ) ;
} else
list_add_tail ( & new - > cr_lru , & free ) ;
2007-06-24 23:57:57 +04:00
spin_unlock ( & cache - > lock ) ;
2007-06-24 23:55:26 +04:00
found :
2009-11-30 03:55:45 +03:00
if ( test_bit ( RPCAUTH_CRED_NEW , & cred - > cr_flags ) & &
cred - > cr_ops - > cr_init ! = NULL & &
! ( flags & RPCAUTH_LOOKUP_NEW ) ) {
2006-02-01 20:19:27 +03:00
int res = cred - > cr_ops - > cr_init ( auth , cred ) ;
if ( res < 0 ) {
put_rpccred ( cred ) ;
cred = ERR_PTR ( res ) ;
}
2005-04-17 02:20:36 +04:00
}
2007-06-24 23:55:26 +04:00
rpcauth_destroy_credlist ( & free ) ;
out :
return cred ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpcauth_lookup_credcache ) ;
2005-04-17 02:20:36 +04:00
struct rpc_cred *
2006-02-01 20:18:36 +03:00
rpcauth_lookupcred ( struct rpc_auth * auth , int flags )
2005-04-17 02:20:36 +04:00
{
2008-11-14 02:39:18 +03:00
struct auth_cred acred ;
2005-04-17 02:20:36 +04:00
struct rpc_cred * ret ;
2008-11-14 02:39:18 +03:00
const struct cred * cred = current_cred ( ) ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: looking up %s cred \n " ,
2005-04-17 02:20:36 +04:00
auth - > au_ops - > au_name ) ;
2008-11-14 02:39:18 +03:00
memset ( & acred , 0 , sizeof ( acred ) ) ;
acred . uid = cred - > fsuid ;
acred . gid = cred - > fsgid ;
acred . group_info = get_group_info ( ( ( struct cred * ) cred ) - > group_info ) ;
2006-02-01 20:18:36 +03:00
ret = auth - > au_ops - > lookup_cred ( auth , & acred , flags ) ;
2005-04-17 02:20:36 +04:00
put_group_info ( acred . group_info ) ;
return ret ;
}
2007-06-24 03:55:31 +04:00
void
rpcauth_init_cred ( struct rpc_cred * cred , const struct auth_cred * acred ,
struct rpc_auth * auth , const struct rpc_credops * ops )
{
INIT_HLIST_NODE ( & cred - > cr_hash ) ;
2007-06-24 03:45:36 +04:00
INIT_LIST_HEAD ( & cred - > cr_lru ) ;
2007-06-24 03:55:31 +04:00
atomic_set ( & cred - > cr_count , 1 ) ;
cred - > cr_auth = auth ;
cred - > cr_ops = ops ;
cred - > cr_expire = jiffies ;
# ifdef RPC_DEBUG
cred - > cr_magic = RPCAUTH_CRED_MAGIC ;
# endif
cred - > cr_uid = acred - > uid ;
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( rpcauth_init_cred ) ;
2007-06-24 03:55:31 +04:00
2010-07-31 22:29:08 +04:00
struct rpc_cred *
2009-09-15 21:32:13 +04:00
rpcauth_generic_bind_cred ( struct rpc_task * task , struct rpc_cred * cred , int lookupflags )
2008-03-12 23:20:55 +03:00
{
dprintk ( " RPC: %5u holding %s cred %p \n " , task - > tk_pid ,
cred - > cr_auth - > au_ops - > au_name , cred ) ;
2010-07-31 22:29:08 +04:00
return get_rpccred ( cred ) ;
2008-03-12 23:20:55 +03:00
}
2008-03-12 23:21:07 +03:00
EXPORT_SYMBOL_GPL ( rpcauth_generic_bind_cred ) ;
2008-03-12 23:20:55 +03:00
2010-07-31 22:29:08 +04:00
static struct rpc_cred *
2009-09-15 21:32:13 +04:00
rpcauth_bind_root_cred ( struct rpc_task * task , int lookupflags )
2005-04-17 02:20:36 +04:00
{
2007-06-27 22:29:04 +04:00
struct rpc_auth * auth = task - > tk_client - > cl_auth ;
2005-04-17 02:20:36 +04:00
struct auth_cred acred = {
2008-03-12 19:12:16 +03:00
. uid = 0 ,
. gid = 0 ,
2005-04-17 02:20:36 +04:00
} ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u looking up %s cred \n " ,
2007-06-27 22:29:04 +04:00
task - > tk_pid , task - > tk_client - > cl_auth - > au_ops - > au_name ) ;
2010-07-31 22:29:08 +04:00
return auth - > au_ops - > lookup_cred ( auth , & acred , lookupflags ) ;
2008-03-12 19:12:16 +03:00
}
2010-07-31 22:29:08 +04:00
static struct rpc_cred *
2009-09-15 21:32:13 +04:00
rpcauth_bind_new_cred ( struct rpc_task * task , int lookupflags )
2008-03-12 19:12:16 +03:00
{
struct rpc_auth * auth = task - > tk_client - > cl_auth ;
dprintk ( " RPC: %5u looking up %s cred \n " ,
task - > tk_pid , auth - > au_ops - > au_name ) ;
2010-07-31 22:29:08 +04:00
return rpcauth_lookupcred ( auth , lookupflags ) ;
2005-04-17 02:20:36 +04:00
}
2010-07-31 22:29:08 +04:00
static int
2008-03-12 23:20:55 +03:00
rpcauth_bindcred ( struct rpc_task * task , struct rpc_cred * cred , int flags )
2005-04-17 02:20:36 +04:00
{
2010-07-31 22:29:08 +04:00
struct rpc_rqst * req = task - > tk_rqstp ;
2010-07-31 22:29:08 +04:00
struct rpc_cred * new ;
2009-09-15 21:32:13 +04:00
int lookupflags = 0 ;
if ( flags & RPC_TASK_ASYNC )
lookupflags | = RPCAUTH_LOOKUP_NEW ;
2008-03-12 23:20:55 +03:00
if ( cred ! = NULL )
2010-07-31 22:29:08 +04:00
new = cred - > cr_ops - > crbind ( task , cred , lookupflags ) ;
2008-03-12 23:20:55 +03:00
else if ( flags & RPC_TASK_ROOTCREDS )
2010-07-31 22:29:08 +04:00
new = rpcauth_bind_root_cred ( task , lookupflags ) ;
2008-03-12 23:20:55 +03:00
else
2010-07-31 22:29:08 +04:00
new = rpcauth_bind_new_cred ( task , lookupflags ) ;
if ( IS_ERR ( new ) )
return PTR_ERR ( new ) ;
2010-07-31 22:29:08 +04:00
if ( req - > rq_cred ! = NULL )
put_rpccred ( req - > rq_cred ) ;
req - > rq_cred = new ;
2010-07-31 22:29:08 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
void
put_rpccred ( struct rpc_cred * cred )
{
2007-06-24 03:45:36 +04:00
/* Fast path for unhashed credentials */
2009-12-03 16:10:17 +03:00
if ( test_bit ( RPCAUTH_CRED_HASHED , & cred - > cr_flags ) = = 0 ) {
if ( atomic_dec_and_test ( & cred - > cr_count ) )
cred - > cr_ops - > crdestroy ( cred ) ;
2005-04-17 02:20:36 +04:00
return ;
2009-12-03 16:10:17 +03:00
}
2007-06-24 03:45:36 +04:00
if ( ! atomic_dec_and_lock ( & cred - > cr_count , & rpc_credcache_lock ) )
return ;
2007-06-26 01:11:20 +04:00
if ( ! list_empty ( & cred - > cr_lru ) ) {
number_cred_unused - - ;
2007-06-24 03:45:36 +04:00
list_del_init ( & cred - > cr_lru ) ;
2007-06-26 01:11:20 +04:00
}
2008-10-28 22:21:42 +03:00
if ( test_bit ( RPCAUTH_CRED_HASHED , & cred - > cr_flags ) ! = 0 ) {
2009-12-03 16:10:17 +03:00
if ( test_bit ( RPCAUTH_CRED_UPTODATE , & cred - > cr_flags ) ! = 0 ) {
cred - > cr_expire = jiffies ;
list_add_tail ( & cred - > cr_lru , & cred_unused ) ;
number_cred_unused + + ;
goto out_nodestroy ;
}
if ( ! rpcauth_unhash_cred ( cred ) ) {
/* We were hashed and someone looked us up... */
goto out_nodestroy ;
}
2007-06-24 03:45:36 +04:00
}
spin_unlock ( & rpc_credcache_lock ) ;
2005-04-17 02:20:36 +04:00
cred - > cr_ops - > crdestroy ( cred ) ;
2009-12-03 16:10:17 +03:00
return ;
out_nodestroy :
spin_unlock ( & rpc_credcache_lock ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-14 23:39:59 +04:00
EXPORT_SYMBOL_GPL ( put_rpccred ) ;
2005-04-17 02:20:36 +04:00
2006-09-27 09:29:38 +04:00
__be32 *
rpcauth_marshcred ( struct rpc_task * task , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2010-07-31 22:29:08 +04:00
struct rpc_cred * cred = task - > tk_rqstp - > rq_cred ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u marshaling %s cred %p \n " ,
2007-06-27 22:29:04 +04:00
task - > tk_pid , cred - > cr_auth - > au_ops - > au_name , cred ) ;
2005-11-02 00:53:32 +03:00
2005-04-17 02:20:36 +04:00
return cred - > cr_ops - > crmarshal ( task , p ) ;
}
2006-09-27 09:29:38 +04:00
__be32 *
rpcauth_checkverf ( struct rpc_task * task , __be32 * p )
2005-04-17 02:20:36 +04:00
{
2010-07-31 22:29:08 +04:00
struct rpc_cred * cred = task - > tk_rqstp - > rq_cred ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u validating %s cred %p \n " ,
2007-06-27 22:29:04 +04:00
task - > tk_pid , cred - > cr_auth - > au_ops - > au_name , cred ) ;
2005-11-02 00:53:32 +03:00
2005-04-17 02:20:36 +04:00
return cred - > cr_ops - > crvalidate ( task , p ) ;
}
2010-12-14 17:59:18 +03:00
static void rpcauth_wrap_req_encode ( kxdreproc_t encode , struct rpc_rqst * rqstp ,
__be32 * data , void * obj )
{
struct xdr_stream xdr ;
xdr_init_encode ( & xdr , & rqstp - > rq_snd_buf , data ) ;
encode ( rqstp , & xdr , obj ) ;
}
2005-04-17 02:20:36 +04:00
int
2010-12-14 17:59:18 +03:00
rpcauth_wrap_req ( struct rpc_task * task , kxdreproc_t encode , void * rqstp ,
2006-09-27 09:29:38 +04:00
__be32 * data , void * obj )
2005-04-17 02:20:36 +04:00
{
2010-07-31 22:29:08 +04:00
struct rpc_cred * cred = task - > tk_rqstp - > rq_cred ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u using %s cred %p to wrap rpc data \n " ,
2005-04-17 02:20:36 +04:00
task - > tk_pid , cred - > cr_ops - > cr_name , cred ) ;
if ( cred - > cr_ops - > crwrap_req )
return cred - > cr_ops - > crwrap_req ( task , encode , rqstp , data , obj ) ;
/* By default, we encode the arguments normally. */
2010-12-14 17:59:18 +03:00
rpcauth_wrap_req_encode ( encode , rqstp , data , obj ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2010-12-14 17:59:29 +03:00
static int
rpcauth_unwrap_req_decode ( kxdrdproc_t decode , struct rpc_rqst * rqstp ,
__be32 * data , void * obj )
{
struct xdr_stream xdr ;
xdr_init_decode ( & xdr , & rqstp - > rq_rcv_buf , data ) ;
return decode ( rqstp , & xdr , obj ) ;
}
2005-04-17 02:20:36 +04:00
int
2010-12-14 17:59:29 +03:00
rpcauth_unwrap_resp ( struct rpc_task * task , kxdrdproc_t decode , void * rqstp ,
2006-09-27 09:29:38 +04:00
__be32 * data , void * obj )
2005-04-17 02:20:36 +04:00
{
2010-07-31 22:29:08 +04:00
struct rpc_cred * cred = task - > tk_rqstp - > rq_cred ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u using %s cred %p to unwrap rpc data \n " ,
2005-04-17 02:20:36 +04:00
task - > tk_pid , cred - > cr_ops - > cr_name , cred ) ;
if ( cred - > cr_ops - > crunwrap_resp )
return cred - > cr_ops - > crunwrap_resp ( task , decode , rqstp ,
data , obj ) ;
/* By default, we decode the arguments normally. */
2010-12-14 17:59:29 +03:00
return rpcauth_unwrap_req_decode ( decode , rqstp , data , obj ) ;
2005-04-17 02:20:36 +04:00
}
int
rpcauth_refreshcred ( struct rpc_task * task )
{
2010-10-25 02:00:46 +04:00
struct rpc_cred * cred ;
2005-04-17 02:20:36 +04:00
int err ;
2010-07-31 22:29:08 +04:00
cred = task - > tk_rqstp - > rq_cred ;
if ( cred = = NULL ) {
err = rpcauth_bindcred ( task , task - > tk_msg . rpc_cred , task - > tk_flags ) ;
if ( err < 0 )
goto out ;
cred = task - > tk_rqstp - > rq_cred ;
} ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u refreshing %s cred %p \n " ,
2007-06-27 22:29:04 +04:00
task - > tk_pid , cred - > cr_auth - > au_ops - > au_name , cred ) ;
2005-11-02 00:53:32 +03:00
2005-04-17 02:20:36 +04:00
err = cred - > cr_ops - > crrefresh ( task ) ;
2010-07-31 22:29:08 +04:00
out :
2005-04-17 02:20:36 +04:00
if ( err < 0 )
task - > tk_status = err ;
return err ;
}
void
rpcauth_invalcred ( struct rpc_task * task )
{
2010-07-31 22:29:08 +04:00
struct rpc_cred * cred = task - > tk_rqstp - > rq_cred ;
2007-06-25 18:15:15 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u invalidating %s cred %p \n " ,
2007-06-27 22:29:04 +04:00
task - > tk_pid , cred - > cr_auth - > au_ops - > au_name , cred ) ;
2007-06-25 18:15:15 +04:00
if ( cred )
clear_bit ( RPCAUTH_CRED_UPTODATE , & cred - > cr_flags ) ;
2005-04-17 02:20:36 +04:00
}
int
rpcauth_uptodatecred ( struct rpc_task * task )
{
2010-07-31 22:29:08 +04:00
struct rpc_cred * cred = task - > tk_rqstp - > rq_cred ;
2007-06-25 18:15:15 +04:00
return cred = = NULL | |
test_bit ( RPCAUTH_CRED_UPTODATE , & cred - > cr_flags ) ! = 0 ;
2005-04-17 02:20:36 +04:00
}
2007-06-26 01:11:20 +04:00
2007-07-17 15:03:17 +04:00
static struct shrinker rpc_cred_shrinker = {
. shrink = rpcauth_cache_shrinker ,
. seeks = DEFAULT_SEEKS ,
} ;
2007-06-26 01:11:20 +04:00
2010-07-31 22:29:07 +04:00
int __init rpcauth_init_module ( void )
2007-06-26 01:11:20 +04:00
{
2010-07-31 22:29:07 +04:00
int err ;
err = rpc_init_authunix ( ) ;
if ( err < 0 )
goto out1 ;
err = rpc_init_generic_auth ( ) ;
if ( err < 0 )
goto out2 ;
2007-07-17 15:03:17 +04:00
register_shrinker ( & rpc_cred_shrinker ) ;
2010-07-31 22:29:07 +04:00
return 0 ;
out2 :
rpc_destroy_authunix ( ) ;
out1 :
return err ;
2007-06-26 01:11:20 +04:00
}
2010-09-29 08:16:57 +04:00
void rpcauth_remove_module ( void )
2007-06-26 01:11:20 +04:00
{
2010-07-31 22:29:07 +04:00
rpc_destroy_authunix ( ) ;
rpc_destroy_generic_auth ( ) ;
2007-07-17 15:03:17 +04:00
unregister_shrinker ( & rpc_cred_shrinker ) ;
2007-06-26 01:11:20 +04:00
}