2005-04-17 02:20:36 +04:00
/*
* linux / net / sunrpc / auth_unix . c
*
* UNIX - style authentication ; no AUTH_SHORT support
*
* Copyright ( C ) 1996 , Olaf Kirch < okir @ monad . swb . de >
*/
# include <linux/types.h>
# include <linux/sched.h>
# include <linux/module.h>
# include <linux/sunrpc/clnt.h>
# include <linux/sunrpc/auth.h>
# define NFS_NGROUPS 16
struct unx_cred {
struct rpc_cred uc_base ;
gid_t uc_gid ;
gid_t uc_gids [ NFS_NGROUPS ] ;
} ;
# define uc_uid uc_base.cr_uid
# define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2))
# ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
# endif
static struct rpc_auth unix_auth ;
static struct rpc_cred_cache unix_cred_cache ;
2007-06-24 04:17:58 +04:00
static const struct rpc_credops unix_credops ;
2005-04-17 02:20:36 +04:00
static struct rpc_auth *
unx_create ( struct rpc_clnt * clnt , rpc_authflavor_t flavor )
{
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: creating UNIX authenticator for client %p \n " ,
clnt ) ;
2007-06-26 01:11:20 +04:00
atomic_inc ( & unix_auth . au_count ) ;
2005-04-17 02:20:36 +04:00
return & unix_auth ;
}
static void
unx_destroy ( struct rpc_auth * auth )
{
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: destroying UNIX authenticator %p \n " , auth ) ;
2007-06-09 23:41:42 +04:00
rpcauth_clear_credcache ( auth - > au_credcache ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Lookup AUTH_UNIX creds for current process
*/
static struct rpc_cred *
unx_lookup_cred ( struct rpc_auth * auth , struct auth_cred * acred , int flags )
{
return rpcauth_lookup_credcache ( auth , acred , flags ) ;
}
static struct rpc_cred *
unx_create_cred ( struct rpc_auth * auth , struct auth_cred * acred , int flags )
{
struct unx_cred * cred ;
2008-03-12 19:12:16 +03:00
unsigned int groups = 0 ;
unsigned int i ;
2005-04-17 02:20:36 +04:00
2007-01-31 20:14:08 +03:00
dprintk ( " RPC: allocating UNIX cred for uid %d gid %d \n " ,
acred - > uid , acred - > gid ) ;
2005-04-17 02:20:36 +04:00
2006-01-12 02:56:43 +03:00
if ( ! ( cred = kmalloc ( sizeof ( * cred ) , GFP_KERNEL ) ) )
2005-04-17 02:20:36 +04:00
return ERR_PTR ( - ENOMEM ) ;
2007-06-24 03:55:31 +04:00
rpcauth_init_cred ( & cred - > uc_base , acred , auth , & unix_credops ) ;
2007-06-25 18:15:15 +04:00
cred - > uc_base . cr_flags = 1UL < < RPCAUTH_CRED_UPTODATE ;
2008-03-12 19:12:16 +03:00
if ( acred - > group_info ! = NULL )
groups = acred - > group_info - > ngroups ;
if ( groups > NFS_NGROUPS )
groups = NFS_NGROUPS ;
cred - > uc_gid = acred - > gid ;
for ( i = 0 ; i < groups ; i + + )
cred - > uc_gids [ i ] = GROUP_AT ( acred - > group_info , i ) ;
if ( i < NFS_NGROUPS )
cred - > uc_gids [ i ] = NOGROUP ;
2005-04-17 02:20:36 +04:00
2007-06-25 17:48:25 +04:00
return & cred - > uc_base ;
2005-04-17 02:20:36 +04:00
}
static void
2007-06-24 23:55:26 +04:00
unx_free_cred ( struct unx_cred * unx_cred )
2005-04-17 02:20:36 +04:00
{
2007-06-24 23:55:26 +04:00
dprintk ( " RPC: unx_free_cred %p \n " , unx_cred ) ;
kfree ( unx_cred ) ;
}
2007-06-25 17:48:25 +04:00
2007-06-24 23:55:26 +04:00
static void
unx_free_cred_callback ( struct rcu_head * head )
{
struct unx_cred * unx_cred = container_of ( head , struct unx_cred , uc_base . cr_rcu ) ;
unx_free_cred ( unx_cred ) ;
}
static void
unx_destroy_cred ( struct rpc_cred * cred )
{
call_rcu ( & cred - > cr_rcu , unx_free_cred_callback ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Match credentials against current process creds .
* The root_override argument takes care of cases where the caller may
* request root creds ( e . g . for NFS swapping ) .
*/
static int
2006-02-01 20:18:36 +03:00
unx_match ( struct auth_cred * acred , struct rpc_cred * rcred , int flags )
2005-04-17 02:20:36 +04:00
{
2007-06-25 17:48:25 +04:00
struct unx_cred * cred = container_of ( rcred , struct unx_cred , uc_base ) ;
2008-03-12 19:12:16 +03:00
unsigned int groups = 0 ;
unsigned int i ;
2005-04-17 02:20:36 +04:00
2008-03-12 19:12:16 +03:00
if ( cred - > uc_uid ! = acred - > uid | | cred - > uc_gid ! = acred - > gid )
return 0 ;
2005-04-17 02:20:36 +04:00
2008-03-12 19:12:16 +03:00
if ( acred - > group_info ! = NULL )
2005-04-17 02:20:36 +04:00
groups = acred - > group_info - > ngroups ;
2008-03-12 19:12:16 +03:00
if ( groups > NFS_NGROUPS )
groups = NFS_NGROUPS ;
for ( i = 0 ; i < groups ; i + + )
if ( cred - > uc_gids [ i ] ! = GROUP_AT ( acred - > group_info , i ) )
return 0 ;
return 1 ;
2005-04-17 02:20:36 +04:00
}
/*
* Marshal credentials .
* Maybe we should keep a cached credential for performance reasons .
*/
2006-09-27 09:29:38 +04:00
static __be32 *
unx_marshal ( struct rpc_task * task , __be32 * p )
2005-04-17 02:20:36 +04:00
{
struct rpc_clnt * clnt = task - > tk_client ;
2007-06-25 17:48:25 +04:00
struct unx_cred * cred = container_of ( task - > tk_msg . rpc_cred , struct unx_cred , uc_base ) ;
2006-09-27 09:29:38 +04:00
__be32 * base , * hold ;
2005-04-17 02:20:36 +04:00
int i ;
* p + + = htonl ( RPC_AUTH_UNIX ) ;
base = p + + ;
* p + + = htonl ( jiffies / HZ ) ;
/*
* Copy the UTS nodename captured when the client was created .
*/
p = xdr_encode_array ( p , clnt - > cl_nodename , clnt - > cl_nodelen ) ;
* p + + = htonl ( ( u32 ) cred - > uc_uid ) ;
* p + + = htonl ( ( u32 ) cred - > uc_gid ) ;
hold = p + + ;
for ( i = 0 ; i < 16 & & cred - > uc_gids [ i ] ! = ( gid_t ) NOGROUP ; i + + )
* p + + = htonl ( ( u32 ) cred - > uc_gids [ i ] ) ;
* hold = htonl ( p - hold - 1 ) ; /* gid array length */
* base = htonl ( ( p - base - 1 ) < < 2 ) ; /* cred length */
* p + + = htonl ( RPC_AUTH_NULL ) ;
* p + + = htonl ( 0 ) ;
return p ;
}
/*
* Refresh credentials . This is a no - op for AUTH_UNIX
*/
static int
unx_refresh ( struct rpc_task * task )
{
2007-06-25 18:15:15 +04:00
set_bit ( RPCAUTH_CRED_UPTODATE , & task - > tk_msg . rpc_cred - > cr_flags ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-09-27 09:29:38 +04:00
static __be32 *
unx_validate ( struct rpc_task * task , __be32 * p )
2005-04-17 02:20:36 +04:00
{
rpc_authflavor_t flavor ;
u32 size ;
flavor = ntohl ( * p + + ) ;
if ( flavor ! = RPC_AUTH_NULL & &
flavor ! = RPC_AUTH_UNIX & &
flavor ! = RPC_AUTH_SHORT ) {
printk ( " RPC: bad verf flavor: %u \n " , flavor ) ;
return NULL ;
}
size = ntohl ( * p + + ) ;
if ( size > RPC_MAX_AUTH_SIZE ) {
printk ( " RPC: giant verf size: %u \n " , size ) ;
return NULL ;
}
2007-06-27 22:29:04 +04:00
task - > tk_msg . rpc_cred - > cr_auth - > au_rslack = ( size > > 2 ) + 2 ;
2005-04-17 02:20:36 +04:00
p + = ( size > > 2 ) ;
return p ;
}
2007-06-24 23:57:57 +04:00
void __init rpc_init_authunix ( void )
{
spin_lock_init ( & unix_cred_cache . lock ) ;
}
2007-06-24 04:17:58 +04:00
const struct rpc_authops authunix_ops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
. au_flavor = RPC_AUTH_UNIX ,
. au_name = " UNIX " ,
. create = unx_create ,
. destroy = unx_destroy ,
. lookup_cred = unx_lookup_cred ,
. crcreate = unx_create_cred ,
} ;
static
struct rpc_cred_cache unix_cred_cache = {
} ;
static
struct rpc_auth unix_auth = {
. au_cslack = UNX_WRITESLACK ,
. au_rslack = 2 , /* assume AUTH_NULL verf */
. au_ops = & authunix_ops ,
2006-06-09 17:34:34 +04:00
. au_flavor = RPC_AUTH_UNIX ,
2005-04-17 02:20:36 +04:00
. au_count = ATOMIC_INIT ( 0 ) ,
. au_credcache = & unix_cred_cache ,
} ;
static
2007-06-24 04:17:58 +04:00
const struct rpc_credops unix_credops = {
2005-04-17 02:20:36 +04:00
. cr_name = " AUTH_UNIX " ,
. crdestroy = unx_destroy_cred ,
2008-03-12 23:21:07 +03:00
. crbind = rpcauth_generic_bind_cred ,
2005-04-17 02:20:36 +04:00
. crmatch = unx_match ,
. crmarshal = unx_marshal ,
. crrefresh = unx_refresh ,
. crvalidate = unx_validate ,
} ;