0001-01-01 02:30:17 +02:30
/*
Unix SMB / Netbios implementation .
Version 1.9 .
uid / user handling
Copyright ( C ) Tim Potter 2000
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
extern int DEBUGLEVEL ;
extern struct current_user current_user ;
struct sec_ctx {
uid_t uid ;
uid_t gid ;
int ngroups ;
gid_t * groups ;
0001-01-01 02:30:17 +02:30
NT_USER_TOKEN * token ;
0001-01-01 02:30:17 +02:30
} ;
/* A stack of security contexts. We include the current context as being
the first one , so there is room for another MAX_SEC_CTX_DEPTH more . */
static struct sec_ctx sec_ctx_stack [ MAX_SEC_CTX_DEPTH + 1 ] ;
static int sec_ctx_stack_ndx ;
0001-01-01 02:30:17 +02:30
/****************************************************************************
Become the specified uid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static BOOL become_uid ( uid_t uid )
{
/* Check for dodgy uid values */
if ( uid = = ( uid_t ) - 1 | |
( ( sizeof ( uid_t ) = = 2 ) & & ( uid = = ( uid_t ) 65535 ) ) ) {
static int done ;
if ( ! done ) {
DEBUG ( 1 , ( " WARNING: using uid %d is a security risk \n " ,
( int ) uid ) ) ;
done = 1 ;
}
}
/* Set effective user id */
set_effective_uid ( uid ) ;
current_user . uid = uid ;
# ifdef WITH_PROFILE
profile_p - > uid_changes + + ;
# endif
return True ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Become the specified gid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static BOOL become_gid ( gid_t gid )
{
/* Check for dodgy gid values */
if ( gid = = ( gid_t ) - 1 | | ( ( sizeof ( gid_t ) = = 2 ) & &
( gid = = ( gid_t ) 65535 ) ) ) {
static int done ;
if ( ! done ) {
DEBUG ( 1 , ( " WARNING: using gid %d is a security risk \n " ,
( int ) gid ) ) ;
done = 1 ;
}
}
/* Set effective group id */
set_effective_gid ( gid ) ;
current_user . gid = gid ;
return True ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Become the specified uid and gid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static BOOL become_id ( uid_t uid , gid_t gid )
{
return become_gid ( gid ) & & become_uid ( uid ) ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Drop back to root privileges in order to change to another user .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static void gain_root ( void )
{
if ( geteuid ( ) ! = 0 ) {
set_effective_uid ( 0 ) ;
if ( geteuid ( ) ! = 0 ) {
DEBUG ( 0 ,
( " Warning: You appear to have a trapdoor "
" uid system \n " ) ) ;
}
}
if ( getegid ( ) ! = 0 ) {
set_effective_gid ( 0 ) ;
if ( getegid ( ) ! = 0 ) {
DEBUG ( 0 ,
( " Warning: You appear to have a trapdoor "
" gid system \n " ) ) ;
}
}
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Get the list of current groups .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
int get_current_groups ( int * p_ngroups , gid_t * * p_groups )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
int i ;
gid_t grp ;
int ngroups = sys_getgroups ( 0 , & grp ) ;
gid_t * groups ;
( * p_ngroups ) = 0 ;
( * p_groups ) = NULL ;
if ( ngroups < = 0 )
return - 1 ;
if ( ( groups = ( gid_t * ) malloc ( sizeof ( gid_t ) * ngroups ) ) = = NULL ) {
DEBUG ( 0 , ( " setup_groups malloc fail ! \n " ) ) ;
return - 1 ;
}
if ( ( ngroups = sys_getgroups ( ngroups , groups ) ) = = - 1 )
return - 1 ;
( * p_ngroups ) = ngroups ;
( * p_groups ) = groups ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
DEBUG ( 3 , ( " get_current_groups: uid %u is in %u groups: " , ( unsigned int ) getuid ( ) , ngroups ) ) ;
for ( i = 0 ; i < ngroups ; i + + ) {
DEBUG ( 3 , ( " %s%d " , ( i ? " , " : " " ) , ( int ) groups [ i ] ) ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
DEBUG ( 3 , ( " \n " ) ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
return ngroups ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Delete a SID token .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void delete_nt_token ( NT_USER_TOKEN * * pptoken )
{
if ( * pptoken ) {
NT_USER_TOKEN * ptoken = * pptoken ;
safe_free ( ptoken - > user_sids ) ;
ZERO_STRUCTP ( ptoken ) ;
}
safe_free ( * pptoken ) ;
* pptoken = NULL ;
}
/****************************************************************************
Duplicate a SID token .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NT_USER_TOKEN * dup_nt_token ( NT_USER_TOKEN * ptoken )
{
NT_USER_TOKEN * token ;
if ( ! ptoken )
return NULL ;
if ( ( token = ( NT_USER_TOKEN * ) malloc ( sizeof ( NT_USER_TOKEN ) ) ) = = NULL )
return NULL ;
ZERO_STRUCTP ( token ) ;
if ( ( token - > user_sids = ( DOM_SID * ) memdup ( ptoken - > user_sids , sizeof ( DOM_SID ) * ptoken - > num_sids ) ) = = NULL ) {
free ( token ) ;
return NULL ;
}
token - > num_sids = ptoken - > num_sids ;
return token ;
}
/****************************************************************************
Create a new security context on the stack . It is the same as the old
one . User changes are done using the set_sec_ctx ( ) function .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
BOOL push_sec_ctx ( void )
{
0001-01-01 02:30:17 +02:30
struct sec_ctx * ctx_p ;
0001-01-01 02:30:17 +02:30
/* Check we don't overflow our stack */
if ( sec_ctx_stack_ndx = = ( MAX_SEC_CTX_DEPTH ) ) {
DEBUG ( 0 , ( " Security context stack overflow! \n " ) ) ;
return False ;
}
/* Store previous user context */
sec_ctx_stack_ndx + + ;
0001-01-01 02:30:17 +02:30
ctx_p = & sec_ctx_stack [ sec_ctx_stack_ndx ] ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
ctx_p - > uid = geteuid ( ) ;
ctx_p - > gid = getegid ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
ctx_p - > token = dup_nt_token ( sec_ctx_stack [ sec_ctx_stack_ndx - 1 ] . token ) ;
0001-01-01 02:30:17 +02:30
ctx_p - > ngroups = sys_getgroups ( 0 , NULL ) ;
if ( ctx_p - > ngroups ! = 0 ) {
if ( ! ( ctx_p - > groups = malloc ( ctx_p - > ngroups * sizeof ( gid_t ) ) ) ) {
DEBUG ( 0 , ( " Out of memory in push_sec_ctx() \n " ) ) ;
0001-01-01 02:30:17 +02:30
delete_nt_token ( & ctx_p - > token ) ;
0001-01-01 02:30:17 +02:30
return False ;
}
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
sys_getgroups ( ctx_p - > ngroups , ctx_p - > groups ) ;
} else {
ctx_p - > groups = NULL ;
}
0001-01-01 02:30:17 +02:30
return True ;
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Set the current security context to a given user .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
void set_sec_ctx ( uid_t uid , gid_t gid , int ngroups , gid_t * groups , NT_USER_TOKEN * token )
0001-01-01 02:30:17 +02:30
{
0001-01-01 02:30:17 +02:30
struct sec_ctx * ctx_p = & sec_ctx_stack [ sec_ctx_stack_ndx ] ;
0001-01-01 02:30:17 +02:30
/* Set the security context */
DEBUG ( 3 , ( " setting sec ctx (%d, %d) \n " , uid , gid ) ) ;
gain_root ( ) ;
# ifdef HAVE_SETGROUPS
sys_setgroups ( ngroups , groups ) ;
0001-01-01 02:30:17 +02:30
# endif
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
ctx_p - > ngroups = ngroups ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
safe_free ( ctx_p - > groups ) ;
0001-01-01 02:30:17 +02:30
delete_nt_token ( & ctx_p - > token ) ;
0001-01-01 02:30:17 +02:30
ctx_p - > groups = memdup ( groups , sizeof ( gid_t ) * ngroups ) ;
0001-01-01 02:30:17 +02:30
ctx_p - > token = dup_nt_token ( token ) ;
0001-01-01 02:30:17 +02:30
become_id ( uid , gid ) ;
0001-01-01 02:30:17 +02:30
ctx_p - > uid = uid ;
ctx_p - > gid = gid ;
0001-01-01 02:30:17 +02:30
/* Update current_user stuff */
current_user . uid = uid ;
current_user . gid = gid ;
current_user . ngroups = ngroups ;
current_user . groups = groups ;
0001-01-01 02:30:17 +02:30
current_user . nt_user_token = token ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Become root context .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
void set_root_sec_ctx ( void )
{
/* May need to worry about supplementary groups at some stage */
0001-01-01 02:30:17 +02:30
set_sec_ctx ( 0 , 0 , 0 , NULL , NULL ) ;
0001-01-01 02:30:17 +02:30
}
0001-01-01 02:30:17 +02:30
/****************************************************************************
Pop a security context from the stack .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
BOOL pop_sec_ctx ( void )
{
0001-01-01 02:30:17 +02:30
struct sec_ctx * ctx_p ;
struct sec_ctx * prev_ctx_p ;
0001-01-01 02:30:17 +02:30
/* Check for stack underflow */
if ( sec_ctx_stack_ndx = = 0 ) {
DEBUG ( 0 , ( " Security context stack underflow! \n " ) ) ;
return False ;
}
0001-01-01 02:30:17 +02:30
ctx_p = & sec_ctx_stack [ sec_ctx_stack_ndx ] ;
0001-01-01 02:30:17 +02:30
/* Clear previous user info */
0001-01-01 02:30:17 +02:30
ctx_p - > uid = ( uid_t ) - 1 ;
ctx_p - > gid = ( gid_t ) - 1 ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
safe_free ( ctx_p - > groups ) ;
ctx_p - > ngroups = 0 ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
delete_nt_token ( & ctx_p - > token ) ;
0001-01-01 02:30:17 +02:30
/* Pop back previous user */
sec_ctx_stack_ndx - - ;
gain_root ( ) ;
0001-01-01 02:30:17 +02:30
prev_ctx_p = & sec_ctx_stack [ sec_ctx_stack_ndx ] ;
0001-01-01 02:30:17 +02:30
# ifdef HAVE_SETGROUPS
0001-01-01 02:30:17 +02:30
sys_setgroups ( prev_ctx_p - > ngroups , prev_ctx_p - > groups ) ;
0001-01-01 02:30:17 +02:30
# endif
0001-01-01 02:30:17 +02:30
become_id ( prev_ctx_p - > uid , prev_ctx_p - > gid ) ;
0001-01-01 02:30:17 +02:30
/* Update current_user stuff */
0001-01-01 02:30:17 +02:30
current_user . uid = prev_ctx_p - > uid ;
current_user . gid = prev_ctx_p - > gid ;
current_user . ngroups = prev_ctx_p - > ngroups ;
current_user . groups = prev_ctx_p - > groups ;
0001-01-01 02:30:17 +02:30
current_user . nt_user_token = prev_ctx_p - > token ;
0001-01-01 02:30:17 +02:30
DEBUG ( 3 , ( " popped off to sec ctx (%d, %d) \n " , geteuid ( ) , getegid ( ) ) ) ;
return True ;
}
/* Initialise the security context system */
void init_sec_ctx ( void )
{
int i ;
0001-01-01 02:30:17 +02:30
struct sec_ctx * ctx_p ;
0001-01-01 02:30:17 +02:30
/* Initialise security context stack */
memset ( sec_ctx_stack , 0 , sizeof ( struct sec_ctx ) * MAX_SEC_CTX_DEPTH ) ;
for ( i = 0 ; i < MAX_SEC_CTX_DEPTH ; i + + ) {
sec_ctx_stack [ i ] . uid = ( uid_t ) - 1 ;
sec_ctx_stack [ i ] . gid = ( gid_t ) - 1 ;
}
/* Initialise first level of stack. It is the current context */
0001-01-01 02:30:17 +02:30
ctx_p = & sec_ctx_stack [ 0 ] ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
ctx_p - > uid = geteuid ( ) ;
ctx_p - > gid = getegid ( ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
get_current_groups ( & ctx_p - > ngroups , & ctx_p - > groups ) ;
0001-01-01 02:30:17 +02:30
0001-01-01 02:30:17 +02:30
ctx_p - > token = NULL ; /* Maps to guest user. */
0001-01-01 02:30:17 +02:30
/* Initialise current_user global */
0001-01-01 02:30:17 +02:30
current_user . uid = ctx_p - > uid ;
current_user . gid = ctx_p - > gid ;
current_user . ngroups = ctx_p - > ngroups ;
current_user . groups = ctx_p - > groups ;
0001-01-01 02:30:17 +02:30
/* The conn and vuid are usually taken care of by other modules.
We initialise them here . */
current_user . conn = NULL ;
current_user . vuid = UID_FIELD_INVALID ;
0001-01-01 02:30:17 +02:30
current_user . nt_user_token = NULL ;
0001-01-01 02:30:17 +02:30
}