1996-06-01 19:25:30 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
uid / user handling
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
1996-06-01 19:25:30 +04:00
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 ;
1998-09-30 00:24:17 +04:00
static uid_t initial_uid ;
static gid_t initial_gid ;
1996-06-01 19:25:30 +04:00
1996-06-04 10:42:03 +04:00
/* what user is current? */
1998-08-14 21:38:29 +04:00
extern struct current_user current_user ;
1996-06-01 19:25:30 +04:00
1997-10-25 14:58:18 +04:00
pstring OriginalDir ;
1996-10-07 19:04:48 +04:00
1996-06-01 19:25:30 +04:00
/****************************************************************************
initialise the uid routines
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void init_uid ( void )
{
1998-07-29 07:08:05 +04:00
initial_uid = current_user . uid = geteuid ( ) ;
initial_gid = current_user . gid = getegid ( ) ;
1996-06-01 19:25:30 +04:00
1998-07-29 07:08:05 +04:00
if ( initial_gid ! = 0 & & initial_uid = = 0 ) {
# ifdef HAVE_SETRESUID
setresgid ( 0 , 0 , 0 ) ;
1996-06-01 19:25:30 +04:00
# else
1998-07-29 07:08:05 +04:00
setgid ( 0 ) ;
setegid ( 0 ) ;
1996-06-01 19:25:30 +04:00
# endif
1998-07-29 07:08:05 +04:00
}
1996-06-01 19:25:30 +04:00
1998-07-29 07:08:05 +04:00
initial_uid = geteuid ( ) ;
initial_gid = getegid ( ) ;
1996-06-01 19:25:30 +04:00
1998-08-14 21:38:29 +04:00
current_user . conn = NULL ;
1998-07-29 07:08:05 +04:00
current_user . vuid = UID_FIELD_INVALID ;
ChDir ( OriginalDir ) ;
1996-06-01 19:25:30 +04:00
}
/****************************************************************************
become the specified uid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-30 00:24:17 +04:00
static BOOL become_uid ( uid_t uid )
1996-06-01 19:25:30 +04:00
{
1998-07-29 07:08:05 +04:00
if ( initial_uid ! = 0 ) {
return ( True ) ;
}
1998-09-30 00:24:17 +04:00
if ( uid = = ( uid_t ) - 1 | | ( ( sizeof ( uid_t ) = = 2 ) & & ( uid = = ( uid_t ) 65535 ) ) ) {
1998-07-29 07:08:05 +04:00
static int done ;
if ( ! done ) {
1998-09-30 00:24:17 +04:00
DEBUG ( 1 , ( " WARNING: using uid %d is a security risk \n " , ( int ) uid ) ) ;
1998-07-29 07:08:05 +04:00
done = 1 ;
}
}
1998-07-10 05:13:16 +04:00
1998-07-29 07:08:05 +04:00
# ifdef HAVE_TRAPDOOR_UID
# ifdef HAVE_SETUIDX
/* AIX3 has setuidx which is NOT a trapoor function (tridge) */
1998-09-30 00:24:17 +04:00
if ( setuidx ( ID_EFFECTIVE , uid ) ! = 0 ) {
if ( seteuid ( uid ) ! = 0 ) {
DEBUG ( 1 , ( " Can't set uid %d (setuidx) \n " , ( int ) uid ) ) ;
1998-07-29 07:08:05 +04:00
return False ;
}
}
# endif
1996-06-01 19:25:30 +04:00
# endif
1998-07-29 07:08:05 +04:00
# ifdef HAVE_SETRESUID
if ( setresuid ( - 1 , uid , - 1 ) ! = 0 )
1996-06-01 19:25:30 +04:00
# else
if ( ( seteuid ( uid ) ! = 0 ) & &
( setuid ( uid ) ! = 0 ) )
# endif
{
DEBUG ( 0 , ( " Couldn't set uid %d currently set to (%d,%d) \n " ,
1998-09-30 00:24:17 +04:00
( int ) uid , ( int ) getuid ( ) , ( int ) geteuid ( ) ) ) ;
if ( uid > ( uid_t ) 32000 ) {
1998-07-29 07:08:05 +04:00
DEBUG ( 0 , ( " Looks like your OS doesn't like high uid values - try using a different account \n " ) ) ;
}
1996-06-01 19:25:30 +04:00
return ( False ) ;
}
1998-09-30 00:24:17 +04:00
if ( ( ( uid = = ( uid_t ) - 1 ) | | ( ( sizeof ( uid_t ) = = 2 ) & & ( uid = = 65535 ) ) ) & & ( geteuid ( ) ! = uid ) ) {
1998-07-29 07:08:05 +04:00
DEBUG ( 0 , ( " Invalid uid -1. perhaps you have a account with uid 65535? \n " ) ) ;
return ( False ) ;
}
1996-06-01 19:25:30 +04:00
1998-07-29 07:08:05 +04:00
current_user . uid = uid ;
1996-06-01 19:25:30 +04:00
1998-07-29 07:08:05 +04:00
return ( True ) ;
1996-06-01 19:25:30 +04:00
}
/****************************************************************************
become the specified gid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-30 00:24:17 +04:00
static BOOL become_gid ( gid_t gid )
1996-06-01 19:25:30 +04:00
{
if ( initial_uid ! = 0 )
return ( True ) ;
1996-10-04 13:31:07 +04:00
1998-09-30 00:24:17 +04:00
if ( gid = = ( gid_t ) - 1 | | ( ( sizeof ( gid_t ) = = 2 ) & & ( gid = = ( gid_t ) 65535 ) ) ) {
DEBUG ( 1 , ( " WARNING: using gid %d is a security risk \n " , ( int ) gid ) ) ;
1996-10-04 13:31:07 +04:00
}
1996-06-01 19:25:30 +04:00
1998-07-29 07:08:05 +04:00
# ifdef HAVE_SETRESUID
1996-06-01 19:25:30 +04:00
if ( setresgid ( - 1 , gid , - 1 ) ! = 0 )
# else
if ( setgid ( gid ) ! = 0 )
# endif
{
DEBUG ( 0 , ( " Couldn't set gid %d currently set to (%d,%d) \n " ,
1998-09-30 00:24:17 +04:00
( int ) gid , ( int ) getgid ( ) , ( int ) getegid ( ) ) ) ;
1998-07-29 07:08:05 +04:00
if ( gid > 32000 ) {
DEBUG ( 0 , ( " Looks like your OS doesn't like high gid values - try using a different account \n " ) ) ;
}
1996-06-01 19:25:30 +04:00
return ( False ) ;
}
1996-06-04 10:42:03 +04:00
current_user . gid = gid ;
1996-06-01 19:25:30 +04:00
return ( True ) ;
}
/****************************************************************************
become the specified uid and gid
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-30 00:24:17 +04:00
static BOOL become_id ( uid_t uid , gid_t gid )
1996-06-01 19:25:30 +04:00
{
1998-07-29 07:08:05 +04:00
return ( become_gid ( gid ) & & become_uid ( uid ) ) ;
1996-06-01 19:25:30 +04:00
}
/****************************************************************************
become the guest user
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL become_guest ( void )
{
BOOL ret ;
static struct passwd * pass = NULL ;
if ( initial_uid ! = 0 )
return ( True ) ;
if ( ! pass )
pass = Get_Pwnam ( lp_guestaccount ( - 1 ) , True ) ;
if ( ! pass ) return ( False ) ;
1998-07-10 05:13:16 +04:00
# ifdef AIX
/* MWW: From AIX FAQ patch to WU-ftpd: call initgroups before setting IDs */
initgroups ( pass - > pw_name , ( gid_t ) pass - > pw_gid ) ;
# endif
1998-07-29 07:08:05 +04:00
1996-06-01 19:25:30 +04:00
ret = become_id ( pass - > pw_uid , pass - > pw_gid ) ;
1998-07-29 07:08:05 +04:00
if ( ! ret ) {
1996-06-01 19:25:30 +04:00
DEBUG ( 1 , ( " Failed to become guest. Invalid guest account? \n " ) ) ;
1998-07-29 07:08:05 +04:00
}
1996-06-01 19:25:30 +04:00
1998-08-14 21:38:29 +04:00
current_user . conn = NULL ;
1998-02-11 14:07:14 +03:00
current_user . vuid = UID_FIELD_INVALID ;
1996-06-01 19:25:30 +04:00
return ( ret ) ;
}
/*******************************************************************
check if a username is OK
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-10-25 14:58:18 +04:00
static BOOL check_user_ok ( connection_struct * conn , user_struct * vuser , int snum )
1996-06-01 19:25:30 +04:00
{
int i ;
1997-10-25 14:58:18 +04:00
for ( i = 0 ; i < conn - > uid_cache . entries ; i + + )
if ( conn - > uid_cache . list [ i ] = = vuser - > uid ) return ( True ) ;
1996-06-01 19:25:30 +04:00
if ( ! user_ok ( vuser - > name , snum ) ) return ( False ) ;
1997-10-25 14:58:18 +04:00
i = conn - > uid_cache . entries % UID_CACHE_SIZE ;
conn - > uid_cache . list [ i ] = vuser - > uid ;
1996-06-01 19:25:30 +04:00
1997-10-25 14:58:18 +04:00
if ( conn - > uid_cache . entries < UID_CACHE_SIZE )
conn - > uid_cache . entries + + ;
1996-06-01 19:25:30 +04:00
return ( True ) ;
}
/****************************************************************************
become the user of a connection number
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-08-14 21:38:29 +04:00
BOOL become_user ( connection_struct * conn , uint16 vuid )
1996-06-01 19:25:30 +04:00
{
1998-08-14 21:38:29 +04:00
user_struct * vuser = get_valid_user_struct ( vuid ) ;
1998-09-30 00:24:17 +04:00
int snum ;
gid_t gid ;
uid_t uid ;
1998-08-14 21:38:29 +04:00
/*
* We need a separate check in security = share mode due to vuid
* always being UID_FIELD_INVALID . If we don ' t do this then
* in share mode security we are * always * changing uid ' s between
* SMB ' s - this hurts performance - Badly .
*/
if ( ( lp_security ( ) = = SEC_SHARE ) & & ( current_user . conn = = conn ) & &
( current_user . uid = = conn - > uid ) ) {
DEBUG ( 4 , ( " Skipping become_user - already user \n " ) ) ;
return ( True ) ;
} else if ( ( current_user . conn = = conn ) & &
( vuser ! = 0 ) & & ( current_user . vuid = = vuid ) & &
( current_user . uid = = vuser - > uid ) ) {
DEBUG ( 4 , ( " Skipping become_user - already user \n " ) ) ;
return ( True ) ;
}
1996-06-01 19:25:30 +04:00
1998-08-14 21:38:29 +04:00
unbecome_user ( ) ;
1997-12-23 14:30:58 +03:00
1998-08-17 10:13:32 +04:00
if ( ! conn ) {
1998-08-14 21:38:29 +04:00
DEBUG ( 2 , ( " Connection not open \n " ) ) ;
return ( False ) ;
}
1996-06-01 19:25:30 +04:00
1998-08-14 21:38:29 +04:00
snum = SNUM ( conn ) ;
if ( ( vuser ! = NULL ) & & ! check_user_ok ( conn , vuser , snum ) )
return False ;
if ( conn - > force_user | |
lp_security ( ) = = SEC_SHARE | |
! ( vuser ) | | ( vuser - > guest ) ) {
uid = conn - > uid ;
gid = conn - > gid ;
current_user . groups = conn - > groups ;
current_user . ngroups = conn - > ngroups ;
} else {
if ( ! vuser ) {
DEBUG ( 2 , ( " Invalid vuid used %d \n " , vuid ) ) ;
return ( False ) ;
}
uid = vuser - > uid ;
if ( ! * lp_force_group ( snum ) ) {
gid = vuser - > gid ;
} else {
gid = conn - > gid ;
}
current_user . ngroups = vuser - > n_groups ;
current_user . groups = vuser - > groups ;
}
if ( initial_uid = = 0 ) {
if ( ! become_gid ( gid ) ) return ( False ) ;
1996-06-01 19:25:30 +04:00
1998-07-29 07:08:05 +04:00
# ifdef HAVE_SETGROUPS
1998-08-14 21:38:29 +04:00
if ( ! ( conn & & conn - > ipc ) ) {
/* groups stuff added by ih/wreu */
if ( current_user . ngroups > 0 )
if ( setgroups ( current_user . ngroups ,
current_user . groups ) < 0 ) {
DEBUG ( 0 , ( " setgroups call failed! \n " ) ) ;
}
}
1996-06-01 19:25:30 +04:00
# endif
1998-08-14 21:38:29 +04:00
if ( ! conn - > admin_user & & ! become_uid ( uid ) )
return ( False ) ;
}
current_user . conn = conn ;
current_user . vuid = vuid ;
1998-05-06 05:34:51 +04:00
1998-08-14 21:38:29 +04:00
DEBUG ( 5 , ( " become_user uid=(%d,%d) gid=(%d,%d) \n " ,
1998-08-15 05:19:26 +04:00
( int ) getuid ( ) , ( int ) geteuid ( ) , ( int ) getgid ( ) , ( int ) getegid ( ) ) ) ;
1996-06-01 19:25:30 +04:00
1998-08-14 21:38:29 +04:00
return ( True ) ;
1996-06-01 19:25:30 +04:00
}
/****************************************************************************
unbecome the user of a connection number
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL unbecome_user ( void )
{
1998-08-14 21:38:29 +04:00
if ( ! current_user . conn )
1996-06-01 19:25:30 +04:00
return ( False ) ;
1996-10-07 19:04:48 +04:00
ChDir ( OriginalDir ) ;
1996-06-01 19:25:30 +04:00
if ( initial_uid = = 0 )
{
1998-07-29 07:08:05 +04:00
# ifdef HAVE_SETRESUID
1996-06-01 19:25:30 +04:00
setresuid ( - 1 , getuid ( ) , - 1 ) ;
setresgid ( - 1 , getgid ( ) , - 1 ) ;
# else
if ( seteuid ( initial_uid ) ! = 0 )
setuid ( initial_uid ) ;
setgid ( initial_gid ) ;
# endif
}
1998-07-29 07:08:05 +04:00
1996-06-01 19:25:30 +04:00
# ifdef NO_EID
if ( initial_uid = = 0 )
DEBUG ( 2 , ( " Running with no EID \n " ) ) ;
initial_uid = getuid ( ) ;
initial_gid = getgid ( ) ;
# else
1998-07-29 07:08:05 +04:00
if ( geteuid ( ) ! = initial_uid ) {
DEBUG ( 0 , ( " Warning: You appear to have a trapdoor uid system \n " ) ) ;
initial_uid = geteuid ( ) ;
}
if ( getegid ( ) ! = initial_gid ) {
DEBUG ( 0 , ( " Warning: You appear to have a trapdoor gid system \n " ) ) ;
initial_gid = getegid ( ) ;
}
1996-06-01 19:25:30 +04:00
# endif
1996-06-04 10:42:03 +04:00
current_user . uid = initial_uid ;
current_user . gid = initial_gid ;
1996-06-01 19:25:30 +04:00
1996-10-07 19:04:48 +04:00
if ( ChDir ( OriginalDir ) ! = 0 )
1998-08-01 02:39:15 +04:00
DEBUG ( 0 , ( " chdir(%s) failed in unbecome_user \n " , OriginalDir ) ) ;
1996-06-01 19:25:30 +04:00
DEBUG ( 5 , ( " unbecome_user now uid=(%d,%d) gid=(%d,%d) \n " ,
1998-08-15 05:19:26 +04:00
( int ) getuid ( ) , ( int ) geteuid ( ) , ( int ) getgid ( ) , ( int ) getegid ( ) ) ) ;
1996-06-01 19:25:30 +04:00
1998-08-14 21:38:29 +04:00
current_user . conn = NULL ;
1998-02-11 14:07:14 +03:00
current_user . vuid = UID_FIELD_INVALID ;
1996-06-01 19:25:30 +04:00
return ( True ) ;
}
1997-10-16 01:53:59 +04:00
static struct current_user current_user_saved ;
static int become_root_depth ;
static pstring become_root_dir ;
/****************************************************************************
This is used when we need to do a privilaged operation ( such as mucking
with share mode files ) and temporarily need root access to do it . This
call should always be paired with an unbecome_root ( ) call immediately
after the operation
Set save_dir if you also need to save / restore the CWD
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void become_root ( BOOL save_dir )
{
if ( become_root_depth ) {
DEBUG ( 0 , ( " ERROR: become root depth is non zero \n " ) ) ;
}
if ( save_dir )
GetWd ( become_root_dir ) ;
current_user_saved = current_user ;
become_root_depth = 1 ;
become_uid ( 0 ) ;
1997-10-21 15:54:57 +04:00
become_gid ( 0 ) ;
1997-10-16 01:53:59 +04:00
}
/****************************************************************************
When the privilaged operation is over call this
Set save_dir if you also need to save / restore the CWD
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void unbecome_root ( BOOL restore_dir )
{
if ( become_root_depth ! = 1 ) {
DEBUG ( 0 , ( " ERROR: unbecome root depth is %d \n " ,
become_root_depth ) ) ;
}
/* we might have done a become_user() while running as root,
if we have then become root again in order to become
non root ! */
if ( current_user . uid ! = 0 ) {
become_uid ( 0 ) ;
}
/* restore our gid first */
if ( ! become_gid ( current_user_saved . gid ) ) {
DEBUG ( 0 , ( " ERROR: Failed to restore gid \n " ) ) ;
exit_server ( " Failed to restore gid " ) ;
}
1998-07-29 07:08:05 +04:00
# ifdef HAVE_SETGROUPS
1997-10-16 01:53:59 +04:00
if ( current_user_saved . ngroups > 0 ) {
if ( setgroups ( current_user_saved . ngroups ,
current_user_saved . groups ) < 0 )
DEBUG ( 0 , ( " ERROR: setgroups call failed! \n " ) ) ;
}
# endif
/* now restore our uid */
if ( ! become_uid ( current_user_saved . uid ) ) {
DEBUG ( 0 , ( " ERROR: Failed to restore uid \n " ) ) ;
exit_server ( " Failed to restore uid " ) ;
}
if ( restore_dir )
ChDir ( become_root_dir ) ;
current_user = current_user_saved ;
become_root_depth = 0 ;
}
1998-11-12 10:06:48 +03:00