2000-11-03 05:37:44 +00:00
/*
2004-05-17 20:08:46 +00:00
* Copyright ( c ) 1994 - 1996 , 1998 - 2004 Todd C . Miller < Todd . Miller @ courtesan . com >
2000-11-03 05:37:44 +00:00
*
2004-02-13 21:36:43 +00:00
* Permission to use , copy , modify , and distribute this software for any
* purpose with or without fee is hereby granted , provided that the above
* copyright notice and this permission notice appear in all copies .
2000-11-03 05:37:44 +00:00
*
2004-02-13 21:36:43 +00:00
* THE SOFTWARE IS PROVIDED " AS IS " AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS . IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL , DIRECT , INDIRECT , OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE , DATA OR PROFITS , WHETHER IN AN
* ACTION OF CONTRACT , NEGLIGENCE OR OTHER TORTIOUS ACTION , ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE .
2003-04-16 00:42:10 +00:00
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency ( DARPA ) and Air Force Research Laboratory , Air Force
* Materiel Command , USAF , under agreement number F39502 - 99 - 1 - 0512.
2000-11-03 05:37:44 +00:00
*/
# include "config.h"
2001-12-14 19:52:54 +00:00
# include <sys/types.h>
# include <sys/param.h>
# include <sys/stat.h>
2000-11-03 05:37:44 +00:00
# include <stdio.h>
# ifdef STDC_HEADERS
2001-12-14 19:52:54 +00:00
# include <stdlib.h>
# include <stddef.h>
# else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
2000-11-03 05:37:44 +00:00
# endif /* STDC_HEADERS */
# ifdef HAVE_STRING_H
2001-12-14 19:52:54 +00:00
# include <string.h>
# else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
2000-11-03 05:37:44 +00:00
# endif /* HAVE_STRING_H */
2001-12-14 19:52:54 +00:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
# endif /* HAVE_UNISTD_H */
2000-11-03 05:37:44 +00:00
# include <pwd.h>
# include <errno.h>
# include <grp.h>
# ifdef HAVE_LOGIN_CAP_H
# include <login_cap.h>
# endif
# include "sudo.h"
# ifndef lint
static const char rcsid [ ] = " $Sudo$ " ;
# endif /* lint */
2004-05-17 20:08:46 +00:00
# ifdef __TANDEM
# define ROOT_UID 65535
# else
# define ROOT_UID 0
# endif
2000-11-03 05:37:44 +00:00
/*
2000-12-30 03:29:47 +00:00
* Prototypes
2000-11-03 05:37:44 +00:00
*/
2000-12-30 03:29:47 +00:00
static void runas_setup __P ( ( void ) ) ;
2002-01-22 02:00:25 +00:00
static void fatal __P ( ( char * , int ) ) ;
2000-11-03 05:37:44 +00:00
2002-12-15 16:08:32 +00:00
# if !defined(HAVE_SETRESUID) && !defined(HAVE_SETREUID) && \
! defined ( NO_SAVED_IDS ) & & defined ( _SC_SAVED_IDS ) & & defined ( _SC_VERSION )
2000-11-03 05:37:44 +00:00
/*
* Set real and effective uids and gids based on perm .
2000-12-30 03:29:47 +00:00
* Since we have POSIX saved IDs we can get away with just
2000-11-03 05:37:44 +00:00
* toggling the effective uid / gid unless we are headed for an exec ( ) .
*/
void
2002-05-05 00:43:38 +00:00
set_perms_posix ( perm )
2000-11-03 05:37:44 +00:00
int perm ;
{
int error ;
2000-12-30 03:29:47 +00:00
switch ( perm ) {
case PERM_ROOT :
2004-05-17 20:08:46 +00:00
if ( seteuid ( ROOT_UID ) )
fatal ( " seteuid(ROOT_UID) failed, your operating system may have broken POSIX saved ID support \n Try running configure with --disable-saved-ids " , 0 ) ;
2000-12-30 03:29:47 +00:00
break ;
2002-01-13 18:28:09 +00:00
case PERM_FULL_ROOT :
/* headed for exec() */
2004-05-17 20:08:46 +00:00
( void ) seteuid ( ROOT_UID ) ;
if ( setuid ( ROOT_UID ) )
fatal ( " setuid(ROOT_UID) " , 1 ) ;
2002-01-13 18:28:09 +00:00
break ;
2000-12-30 03:29:47 +00:00
case PERM_USER :
( void ) setegid ( user_gid ) ;
if ( seteuid ( user_uid ) )
2002-01-22 02:00:25 +00:00
fatal ( " seteuid(user_uid) " , 1 ) ;
2000-12-30 03:29:47 +00:00
break ;
2002-01-16 21:27:09 +00:00
case PERM_FULL_USER :
/* headed for exec() */
( void ) setgid ( user_gid ) ;
if ( setuid ( user_uid ) )
2002-01-22 02:00:25 +00:00
fatal ( " setuid(user_uid) " , 1 ) ;
2002-01-16 21:27:09 +00:00
break ;
2000-12-30 03:29:47 +00:00
case PERM_RUNAS :
2004-01-16 23:05:47 +00:00
if ( seteuid ( runas_pw - > pw_uid ) )
fatal ( " unable to change to runas uid " , 1 ) ;
break ;
case PERM_FULL_RUNAS :
2004-05-17 20:08:46 +00:00
/* headed for exec(), assume euid == ROOT_UID */
2000-12-30 03:29:47 +00:00
runas_setup ( ) ;
2003-12-30 22:20:21 +00:00
if ( def_stay_setuid )
2000-12-30 03:29:47 +00:00
error = seteuid ( runas_pw - > pw_uid ) ;
else
error = setuid ( runas_pw - > pw_uid ) ;
if ( error )
2002-01-22 02:00:25 +00:00
fatal ( " unable to change to runas uid " , 1 ) ;
2000-12-30 03:29:47 +00:00
break ;
case PERM_SUDOERS :
2004-05-17 20:08:46 +00:00
/* assume euid == ROOT_UID, ruid == user */
2000-12-30 03:29:47 +00:00
if ( setegid ( SUDOERS_GID ) )
2002-01-22 02:00:25 +00:00
fatal ( " unable to change to sudoers gid " , 1 ) ;
2000-12-30 03:29:47 +00:00
/*
2004-05-17 20:08:46 +00:00
* If SUDOERS_UID = = ROOT_UID and SUDOERS_MODE
2000-12-30 03:29:47 +00:00
* is group readable we use a non - zero
* uid in order to avoid NFS lossage .
* Using uid 1 is a bit bogus but should
* work on all OS ' s .
*/
2004-05-17 20:08:46 +00:00
if ( SUDOERS_UID = = ROOT_UID ) {
2000-12-30 03:29:47 +00:00
if ( ( SUDOERS_MODE & 040 ) & & seteuid ( 1 ) )
2002-01-22 02:00:25 +00:00
fatal ( " seteuid(1) " , 1 ) ;
2000-12-30 03:29:47 +00:00
} else {
if ( seteuid ( SUDOERS_UID ) )
2002-01-22 02:00:25 +00:00
fatal ( " seteuid(SUDOERS_UID) " , 1 ) ;
2000-12-30 03:29:47 +00:00
}
break ;
2002-05-03 22:48:17 +00:00
case PERM_TIMESTAMP :
if ( seteuid ( timestamp_uid ) )
fatal ( " seteuid(timestamp_uid) " , 1 ) ;
break ;
2000-11-03 05:37:44 +00:00
}
2000-12-30 03:29:47 +00:00
}
2002-01-15 22:47:29 +00:00
# endif /* !NO_SAVED_IDS && _SC_SAVED_IDS && _SC_VERSION */
2000-12-30 03:29:47 +00:00
2002-11-22 19:09:49 +00:00
# ifdef HAVE_SETRESUID
/*
* Set real and effective and saved uids and gids based on perm .
* We always retain a saved uid of 0 unless we are headed for an exec ( ) .
* We only flip the effective gid since it only changes for PERM_SUDOERS .
* This version of set_perms ( ) works fine with the " stay_setuid " option .
*/
void
set_perms_suid ( perm )
int perm ;
{
int error ;
switch ( perm ) {
case PERM_FULL_ROOT :
case PERM_ROOT :
2004-05-17 20:08:46 +00:00
if ( setresuid ( ROOT_UID , ROOT_UID , ROOT_UID ) )
fatal ( " setresuid(ROOT_UID, ROOT_UID, ROOT_UID) failed, your operating system may have a broken setresuid() function \n Try running configure with --disable-setresuid " , 0 ) ;
2002-11-22 19:09:49 +00:00
break ;
case PERM_USER :
2002-12-15 16:24:24 +00:00
( void ) setresgid ( - 1 , user_gid , - 1 ) ;
2004-05-17 20:08:46 +00:00
if ( setresuid ( user_uid , user_uid , ROOT_UID ) )
fatal ( " setresuid(user_uid, user_uid, ROOT_UID) " , 1 ) ;
2002-11-22 19:09:49 +00:00
break ;
case PERM_FULL_USER :
/* headed for exec() */
( void ) setgid ( user_gid ) ;
if ( setresuid ( user_uid , user_uid , user_uid ) )
fatal ( " setresuid(user_uid, user_uid, user_uid) " , 1 ) ;
break ;
case PERM_RUNAS :
2004-02-06 19:52:17 +00:00
if ( setresuid ( - 1 , runas_pw - > pw_uid , - 1 ) )
2004-01-16 23:05:47 +00:00
fatal ( " unable to change to runas uid " , 1 ) ;
break ;
case PERM_FULL_RUNAS :
2004-05-17 20:08:46 +00:00
/* headed for exec(), assume euid == ROOT_UID */
2002-11-22 19:09:49 +00:00
runas_setup ( ) ;
2003-12-30 22:20:21 +00:00
error = setresuid ( def_stay_setuid ?
2002-11-22 19:09:49 +00:00
user_uid : runas_pw - > pw_uid ,
runas_pw - > pw_uid , runas_pw - > pw_uid ) ;
if ( error )
fatal ( " unable to change to runas uid " , 1 ) ;
break ;
case PERM_SUDOERS :
2004-05-17 20:08:46 +00:00
/* assume euid == ROOT_UID, ruid == user */
2002-12-15 16:24:24 +00:00
if ( setresgid ( - 1 , SUDOERS_GID , - 1 ) )
2002-11-22 19:09:49 +00:00
fatal ( " unable to change to sudoers gid " , 1 ) ;
/*
2004-05-17 20:08:46 +00:00
* If SUDOERS_UID = = ROOT_UID and SUDOERS_MODE
2002-11-22 19:09:49 +00:00
* is group readable we use a non - zero
* uid in order to avoid NFS lossage .
* Using uid 1 is a bit bogus but should
* work on all OS ' s .
*/
2004-05-17 20:08:46 +00:00
if ( SUDOERS_UID = = ROOT_UID ) {
if ( ( SUDOERS_MODE & 040 ) & & setresuid ( ROOT_UID , 1 , ROOT_UID ) )
fatal ( " setresuid(ROOT_UID, 1, ROOT_UID) " , 1 ) ;
2002-11-22 19:09:49 +00:00
} else {
2004-05-17 20:08:46 +00:00
if ( setresuid ( ROOT_UID , SUDOERS_UID , ROOT_UID ) )
fatal ( " setresuid(ROOT_UID, SUDOERS_UID, ROOT_UID) " , 1 ) ;
2002-11-22 19:09:49 +00:00
}
break ;
case PERM_TIMESTAMP :
2004-05-17 20:08:46 +00:00
if ( setresuid ( ROOT_UID , timestamp_uid , ROOT_UID ) )
fatal ( " setresuid(ROOT_UID, timestamp_uid, ROOT_UID) " , 1 ) ;
2002-11-22 19:09:49 +00:00
break ;
}
}
# else
# ifdef HAVE_SETREUID
2000-12-30 03:29:47 +00:00
/*
* Set real and effective uids and gids based on perm .
2004-05-17 20:08:46 +00:00
* We always retain a real or effective uid of ROOT_UID unless
2000-12-30 03:29:47 +00:00
* we are headed for an exec ( ) .
2002-11-22 19:09:49 +00:00
* This version of set_perms ( ) works fine with the " stay_setuid " option .
2000-12-30 03:29:47 +00:00
*/
void
2002-11-22 19:09:49 +00:00
set_perms_suid ( perm )
2000-12-30 03:29:47 +00:00
int perm ;
{
int error ;
2000-11-03 05:37:44 +00:00
switch ( perm ) {
2002-01-13 18:28:09 +00:00
case PERM_FULL_ROOT :
2000-11-03 05:37:44 +00:00
case PERM_ROOT :
2004-05-17 20:08:46 +00:00
if ( setreuid ( - 1 , ROOT_UID ) )
fatal ( " setreuid(-1, ROOT_UID) failed, your operating system may have a broken setreuid() function \n Try running configure with --disable-setreuid " , 0 ) ;
if ( setuid ( ROOT_UID ) )
fatal ( " setuid(ROOT_UID) " , 1 ) ;
2000-11-03 05:37:44 +00:00
break ;
2002-01-13 18:28:09 +00:00
2000-11-03 05:37:44 +00:00
case PERM_USER :
2002-12-15 16:24:24 +00:00
( void ) setregid ( - 1 , user_gid ) ;
2004-05-17 20:08:46 +00:00
if ( setreuid ( ROOT_UID , user_uid ) )
fatal ( " setreuid(ROOT_UID, user_uid) " , 1 ) ;
2000-11-03 05:37:44 +00:00
break ;
2002-01-16 21:27:09 +00:00
case PERM_FULL_USER :
/* headed for exec() */
( void ) setgid ( user_gid ) ;
2002-11-22 19:09:49 +00:00
if ( setreuid ( user_uid , user_uid ) )
fatal ( " setreuid(user_uid, user_uid) " , 1 ) ;
2002-01-16 21:27:09 +00:00
break ;
2000-11-03 05:37:44 +00:00
case PERM_RUNAS :
2004-02-06 19:52:17 +00:00
if ( setreuid ( - 1 , runas_pw - > pw_uid ) )
2004-01-16 23:05:47 +00:00
fatal ( " unable to change to runas uid " , 1 ) ;
break ;
case PERM_FULL_RUNAS :
2004-05-17 20:08:46 +00:00
/* headed for exec(), assume euid == ROOT_UID */
2000-12-30 03:29:47 +00:00
runas_setup ( ) ;
2003-12-30 22:20:21 +00:00
error = setreuid ( def_stay_setuid ?
2002-11-22 19:09:49 +00:00
user_uid : runas_pw - > pw_uid ,
runas_pw - > pw_uid ) ;
2000-12-30 03:29:47 +00:00
if ( error )
2002-01-22 02:00:25 +00:00
fatal ( " unable to change to runas uid " , 1 ) ;
2000-11-03 05:37:44 +00:00
break ;
case PERM_SUDOERS :
2004-05-17 20:08:46 +00:00
/* assume euid == ROOT_UID, ruid == user */
2002-12-15 16:24:24 +00:00
if ( setregid ( - 1 , SUDOERS_GID ) )
2002-01-22 02:00:25 +00:00
fatal ( " unable to change to sudoers gid " , 1 ) ;
2000-11-03 05:37:44 +00:00
/*
2004-05-17 20:08:46 +00:00
* If SUDOERS_UID = = ROOT_UID and SUDOERS_MODE
2000-11-03 05:37:44 +00:00
* is group readable we use a non - zero
* uid in order to avoid NFS lossage .
* Using uid 1 is a bit bogus but should
* work on all OS ' s .
*/
2004-05-17 20:08:46 +00:00
if ( SUDOERS_UID = = ROOT_UID ) {
if ( ( SUDOERS_MODE & 040 ) & & setreuid ( ROOT_UID , 1 ) )
fatal ( " setreuid(ROOT_UID, 1) " , 1 ) ;
2000-11-03 05:37:44 +00:00
} else {
2004-05-17 20:08:46 +00:00
if ( setreuid ( ROOT_UID , SUDOERS_UID ) )
fatal ( " setreuid(ROOT_UID, SUDOERS_UID) " , 1 ) ;
2000-11-03 05:37:44 +00:00
}
2000-12-30 03:29:47 +00:00
break ;
2002-05-03 22:48:17 +00:00
case PERM_TIMESTAMP :
2004-05-17 20:08:46 +00:00
if ( setreuid ( ROOT_UID , timestamp_uid ) )
fatal ( " setreuid(ROOT_UID, timestamp_uid) " , 1 ) ;
2002-05-03 22:48:17 +00:00
break ;
2000-12-30 03:29:47 +00:00
}
}
2002-11-22 19:09:49 +00:00
# else
2000-12-30 03:59:40 +00:00
2000-12-30 03:29:47 +00:00
/*
* Set real and effective uids and gids based on perm .
* NOTE : does not support the " stay_setuid " option .
*/
void
2002-11-22 19:09:49 +00:00
set_perms_nosuid ( perm )
2000-12-30 03:29:47 +00:00
int perm ;
{
/*
* Since we only have setuid ( ) and seteuid ( ) we have to set
2004-05-17 20:08:46 +00:00
* real and effective uids to ROOT_UID initially .
2000-12-30 03:29:47 +00:00
*/
2004-05-17 20:08:46 +00:00
if ( setuid ( ROOT_UID ) )
fatal ( " setuid(ROOT_UID) " , 1 ) ;
2000-12-30 03:29:47 +00:00
switch ( perm ) {
case PERM_USER :
( void ) setegid ( user_gid ) ;
if ( seteuid ( user_uid ) )
2002-01-22 02:00:25 +00:00
fatal ( " seteuid(user_uid) " , 1 ) ;
2000-12-30 03:29:47 +00:00
break ;
2002-01-16 21:27:09 +00:00
case PERM_FULL_USER :
/* headed for exec() */
( void ) setgid ( user_gid ) ;
if ( setuid ( user_uid ) )
2002-01-22 02:00:25 +00:00
fatal ( " setuid(user_uid) " , 1 ) ;
2002-01-16 21:27:09 +00:00
break ;
2000-12-30 03:29:47 +00:00
case PERM_RUNAS :
2004-01-16 23:05:47 +00:00
if ( seteuid ( runas_pw - > pw_uid ) )
fatal ( " unable to change to runas uid " , 1 ) ;
break ;
case PERM_FULL_RUNAS :
2004-05-17 20:08:46 +00:00
/* headed for exec(), assume euid == ROOT_UID */
2000-12-30 03:29:47 +00:00
runas_setup ( ) ;
if ( setuid ( runas_pw - > pw_uid ) )
2002-01-22 02:00:25 +00:00
fatal ( " unable to change to runas uid " , 1 ) ;
2000-12-30 03:29:47 +00:00
break ;
case PERM_SUDOERS :
2004-05-17 20:08:46 +00:00
/* assume euid == ROOT_UID, ruid == user */
2000-12-30 03:29:47 +00:00
if ( setegid ( SUDOERS_GID ) )
2002-01-22 02:00:25 +00:00
fatal ( " unable to change to sudoers gid " , 1 ) ;
2000-12-30 03:29:47 +00:00
/*
2004-05-17 20:08:46 +00:00
* If SUDOERS_UID = = ROOT_UID and SUDOERS_MODE
2000-12-30 03:29:47 +00:00
* is group readable we use a non - zero
* uid in order to avoid NFS lossage .
* Using uid 1 is a bit bogus but should
* work on all OS ' s .
*/
2004-05-17 20:08:46 +00:00
if ( SUDOERS_UID = = ROOT_UID ) {
2000-11-03 05:37:44 +00:00
if ( ( SUDOERS_MODE & 040 ) & & seteuid ( 1 ) )
2002-01-22 02:00:25 +00:00
fatal ( " seteuid(1) " , 1 ) ;
2000-11-03 05:37:44 +00:00
} else {
if ( seteuid ( SUDOERS_UID ) )
2002-01-22 02:00:25 +00:00
fatal ( " seteuid(SUDOERS_UID) " , 1 ) ;
2000-11-03 05:37:44 +00:00
}
break ;
2002-05-03 22:48:17 +00:00
case PERM_TIMESTAMP :
if ( seteuid ( timestamp_uid ) )
fatal ( " seteuid(timestamp_uid) " , 1 ) ;
break ;
2000-11-03 05:37:44 +00:00
}
}
2002-11-22 19:09:49 +00:00
# endif /* HAVE_SETREUID */
# endif /* HAVE_SETRESUID */
2000-12-30 03:29:47 +00:00
static void
runas_setup ( )
{
# ifdef HAVE_LOGIN_CAP_H
2001-12-15 00:24:27 +00:00
int error , flags ;
2000-12-30 03:29:47 +00:00
extern login_cap_t * lc ;
# endif
if ( runas_pw - > pw_name ! = NULL ) {
2001-12-31 17:18:05 +00:00
# ifdef HAVE_PAM
pam_prep_user ( runas_pw ) ;
# endif /* HAVE_PAM */
2000-12-30 03:29:47 +00:00
# ifdef HAVE_LOGIN_CAP_H
2003-12-30 22:20:21 +00:00
if ( def_use_loginclass ) {
2000-12-30 03:29:47 +00:00
/*
2001-12-15 00:24:27 +00:00
* We don ' t have setusercontext ( ) set the user since we
* may only want to set the effective uid . Depending on
* sudoers and / or command line arguments we may not want
* setusercontext ( ) to call initgroups ( ) .
2000-12-30 03:29:47 +00:00
*/
2001-12-15 00:24:27 +00:00
flags = LOGIN_SETRESOURCES | LOGIN_SETPRIORITY ;
2003-12-30 22:20:21 +00:00
if ( ! def_preserve_groups )
2004-01-29 22:33:58 +00:00
SET ( flags , LOGIN_SETGROUP ) ;
2001-12-15 00:24:27 +00:00
else if ( setgid ( runas_pw - > pw_gid ) )
perror ( " cannot set gid to runas gid " ) ;
2000-12-30 03:29:47 +00:00
error = setusercontext ( lc , runas_pw ,
2001-12-15 00:24:27 +00:00
runas_pw - > pw_uid , flags ) ;
2002-07-20 12:30:45 +00:00
if ( error ) {
2004-05-17 20:08:46 +00:00
if ( runas_pw - > pw_uid ! = ROOT_UID )
2002-07-20 12:30:45 +00:00
fatal ( " unable to set user context " , 1 ) ;
else
perror ( " unable to set user context " ) ;
}
2000-12-30 03:29:47 +00:00
} else
# endif /* HAVE_LOGIN_CAP_H */
{
if ( setgid ( runas_pw - > pw_gid ) )
perror ( " cannot set gid to runas gid " ) ;
# ifdef HAVE_INITGROUPS
/*
2001-12-15 00:24:27 +00:00
* Initialize group vector unless asked not to .
2000-12-30 03:29:47 +00:00
*/
2003-12-30 22:20:21 +00:00
if ( ! def_preserve_groups & &
2000-12-30 03:29:47 +00:00
initgroups ( * user_runas , runas_pw - > pw_gid ) < 0 )
perror ( " cannot set group vector " ) ;
# endif /* HAVE_INITGROUPS */
}
}
}
static void
2002-01-22 02:00:25 +00:00
fatal ( str , printerr )
2000-12-30 03:29:47 +00:00
char * str ;
2003-06-21 16:50:56 +00:00
int printerr ;
2000-12-30 03:29:47 +00:00
{
2002-01-22 02:00:25 +00:00
if ( str ) {
if ( printerr )
perror ( str ) ;
else {
fputs ( str , stderr ) ;
fputc ( ' \n ' , stderr ) ;
}
}
2000-12-30 03:29:47 +00:00
exit ( 1 ) ;
}