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
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
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 ;
int i ;
2006-01-12 02:56:43 +03:00
new = kmalloc ( sizeof ( * new ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! new )
return - ENOMEM ;
for ( i = 0 ; i < RPC_CREDCACHE_NR ; i + + )
INIT_HLIST_HEAD ( & new - > hashtable [ i ] ) ;
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 ;
}
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 ;
int i ;
spin_lock ( & rpc_credcache_lock ) ;
2007-06-24 23:57:57 +04:00
spin_lock ( & cache - > lock ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < RPC_CREDCACHE_NR ; 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 ) ;
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
rpcauth_cache_shrinker ( 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 ;
nr = hash_long ( acred - > uid , RPC_CREDCACHE_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
2008-03-12 23:21:07 +03:00
void
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
{
task - > tk_msg . rpc_cred = get_rpccred ( cred ) ;
dprintk ( " RPC: %5u holding %s cred %p \n " , task - > tk_pid ,
cred - > cr_auth - > au_ops - > au_name , cred ) ;
}
2008-03-12 23:21:07 +03:00
EXPORT_SYMBOL_GPL ( rpcauth_generic_bind_cred ) ;
2008-03-12 23:20:55 +03:00
static void
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
} ;
struct rpc_cred * ret ;
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 ) ;
2009-09-15 21:32:13 +04:00
ret = auth - > au_ops - > lookup_cred ( auth , & acred , lookupflags ) ;
2008-03-12 19:12:16 +03:00
if ( ! IS_ERR ( ret ) )
task - > tk_msg . rpc_cred = ret ;
else
task - > tk_status = PTR_ERR ( ret ) ;
}
2008-03-12 23:20:55 +03:00
static void
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 ;
struct rpc_cred * ret ;
dprintk ( " RPC: %5u looking up %s cred \n " ,
task - > tk_pid , auth - > au_ops - > au_name ) ;
2009-09-15 21:32:13 +04:00
ret = rpcauth_lookupcred ( auth , lookupflags ) ;
2005-04-17 02:20:36 +04:00
if ( ! IS_ERR ( ret ) )
task - > tk_msg . rpc_cred = ret ;
else
task - > tk_status = PTR_ERR ( ret ) ;
}
void
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
{
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 )
2009-09-15 21:32:13 +04:00
cred - > cr_ops - > crbind ( task , cred , lookupflags ) ;
2008-03-12 23:20:55 +03:00
else if ( flags & RPC_TASK_ROOTCREDS )
2009-09-15 21:32:13 +04:00
rpcauth_bind_root_cred ( task , lookupflags ) ;
2008-03-12 23:20:55 +03:00
else
2009-09-15 21:32:13 +04:00
rpcauth_bind_new_cred ( task , lookupflags ) ;
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
void
rpcauth_unbindcred ( struct rpc_task * task )
{
struct rpc_cred * cred = task - > tk_msg . rpc_cred ;
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: %5u releasing %s cred %p \n " ,
2007-06-27 22:29:04 +04:00
task - > tk_pid , cred - > cr_auth - > au_ops - > au_name , cred ) ;
2005-04-17 02:20:36 +04:00
put_rpccred ( cred ) ;
task - > tk_msg . rpc_cred = NULL ;
}
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
{
struct rpc_cred * cred = task - > tk_msg . rpc_cred ;
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
{
struct rpc_cred * cred = task - > tk_msg . rpc_cred ;
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 ) ;
}
int
rpcauth_wrap_req ( struct rpc_task * task , kxdrproc_t encode , void * rqstp ,
2006-09-27 09:29:38 +04:00
__be32 * data , void * obj )
2005-04-17 02:20:36 +04:00
{
struct rpc_cred * cred = task - > tk_msg . rpc_cred ;
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. */
2008-12-23 23:21:31 +03:00
return encode ( rqstp , data , obj ) ;
2005-04-17 02:20:36 +04:00
}
int
rpcauth_unwrap_resp ( struct rpc_task * task , kxdrproc_t decode , void * rqstp ,
2006-09-27 09:29:38 +04:00
__be32 * data , void * obj )
2005-04-17 02:20:36 +04:00
{
struct rpc_cred * cred = task - > tk_msg . rpc_cred ;
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. */
2008-12-23 23:21:31 +03:00
return decode ( rqstp , data , obj ) ;
2005-04-17 02:20:36 +04:00
}
int
rpcauth_refreshcred ( struct rpc_task * task )
{
struct rpc_cred * cred = task - > tk_msg . rpc_cred ;
int err ;
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 ) ;
if ( err < 0 )
task - > tk_status = err ;
return err ;
}
void
rpcauth_invalcred ( struct rpc_task * task )
{
2007-06-25 18:15:15 +04:00
struct rpc_cred * cred = task - > tk_msg . rpc_cred ;
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 )
{
2007-06-25 18:15:15 +04:00
struct rpc_cred * cred = task - > tk_msg . rpc_cred ;
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
void __init rpcauth_init_module ( void )
{
rpc_init_authunix ( ) ;
2008-03-12 19:24:49 +03:00
rpc_init_generic_auth ( ) ;
2007-07-17 15:03:17 +04:00
register_shrinker ( & rpc_cred_shrinker ) ;
2007-06-26 01:11:20 +04:00
}
void __exit rpcauth_remove_module ( void )
{
2007-07-17 15:03:17 +04:00
unregister_shrinker ( & rpc_cred_shrinker ) ;
2007-06-26 01:11:20 +04:00
}