2024-07-01 10:23:00 +00:00
# include <pwd.h>
# include <stdio.h>
# include <errno.h>
# include <stdlib.h>
# include <string.h>
# include <limits.h>
# include <unistd.h>
# include <signal.h>
# include <termios.h>
# include "pw_check.h"
# include "unused.h"
# define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)
2024-07-09 12:43:55 +00:00
static char * c_flag = NULL ;
static char * s_flag = NULL ;
static char p_flag ;
2024-07-01 10:23:00 +00:00
2024-07-09 12:43:55 +00:00
static int hide_input ( int fd , int flag ) {
2024-07-01 10:23:00 +00:00
struct termios term ;
if ( tcgetattr ( fd , & term ) < 0 )
return 1 ;
if ( flag )
term . c_lflag & = ~ ECHOFLAGS ;
else
term . c_lflag | = ECHOFLAGS ;
if ( tcsetattr ( fd , TCSAFLUSH , & term ) < 0 )
return 1 ;
return 0 ;
}
2024-07-09 12:43:55 +00:00
static void su ( const struct passwd * pw ) {
2024-07-01 10:23:00 +00:00
char * shell = s_flag ;
if ( s_flag = = NULL )
shell = ( pw - > pw_shell [ 0 ] = = ' \0 ' ) ? " /bin/sh " : pw - > pw_shell ;
if ( ! p_flag ) {
setenv ( " HOME " , pw - > pw_dir , 1 ) ;
setenv ( " SHELL " , shell , 1 ) ;
setenv ( " USER " , pw - > pw_name , 1 ) ;
setenv ( " LOGNAME " , pw - > pw_name , 1 ) ;
setenv ( " PATH " , " /bin " , 1 ) ;
}
if ( c_flag )
execlp ( shell , shell , " -c " , c_flag , NULL ) ;
else
execlp ( shell , shell , " -l " , NULL ) ;
}
2024-07-09 12:43:55 +00:00
static int password ( const struct passwd * pw ) {
2024-07-01 10:23:00 +00:00
static char psswd [ 512 ] ;
printf ( " Password: " ) ;
fflush ( stdout ) ;
if ( hide_input ( STDIN_FILENO , 1 ) ) {
2024-09-30 13:11:43 +00:00
fprintf ( stderr , " \n su: %s \n " , strerror ( errno ) ) ;
2024-07-01 10:23:00 +00:00
return 1 ;
}
off_t ret = 0 ;
if ( ( ret = read ( STDIN_FILENO , psswd , sizeof ( psswd ) ) ) < = 0 ) {
2024-09-30 13:11:43 +00:00
fprintf ( stderr , " \n su: %s \n " , strerror ( errno ) ) ;
2024-07-01 10:23:00 +00:00
return 1 ;
}
2024-09-30 13:11:43 +00:00
putchar ( ' \n ' ) ;
2024-07-01 10:23:00 +00:00
psswd [ ret - 1 ] = ' \0 ' ;
if ( pw_check ( " su " , pw , psswd ) ) {
memset ( psswd , ' \0 ' , sizeof ( psswd ) ) ;
return 1 ;
}
memset ( psswd , ' \0 ' , sizeof ( psswd ) ) ;
return 0 ;
}
2024-07-09 12:43:55 +00:00
static void endwin ( int sig ) {
2024-07-01 10:23:00 +00:00
UNUSED ( sig ) ;
hide_input ( STDIN_FILENO , 0 ) ;
exit ( 1 ) ;
}
int main ( int argc , char * * argv ) {
int opt ;
while ( ( opt = getopt ( argc , argv , " c:s:p " ) ) ! = - 1 ) {
switch ( opt ) {
case ' c ' :
c_flag = optarg ;
break ;
case ' s ' :
s_flag = optarg ;
break ;
case ' p ' :
p_flag = 1 ;
break ;
default :
2024-07-03 14:22:50 +00:00
puts ( " su [cps] [user Default: root] \n \t -c CMD Command to pass to \' sh -c \' \n \t -s SHELL Shell to use instead of user's default \n \t -p Do not set new env " ) ;
2024-07-01 10:23:00 +00:00
return 0 ;
}
}
argc - = optind ;
argv + = optind ;
char * user = " root " ;
if ( argv [ 0 ] )
user = argv [ 0 ] ;
struct passwd * pw = getpwnam ( user ) ;
if ( ! pw ) {
fprintf ( stderr , " su: Incorrent username \n " ) ;
return 1 ;
}
signal ( SIGINT , endwin ) ;
if ( getuid ( ) ! = 0 ) {
int ret = password ( pw ) ;
hide_input ( STDIN_FILENO , 0 ) ;
if ( ret )
return 1 ;
}
/* Start */
if ( setgid ( pw - > pw_gid ) < 0 ) {
fprintf ( stderr , " su: %s \n " , strerror ( errno ) ) ;
return 1 ;
}
if ( setuid ( pw - > pw_uid ) < 0 ) {
fprintf ( stderr , " su: %s \n " , strerror ( errno ) ) ;
return 1 ;
}
su ( pw ) ;
return 0 ;
}