2018-07-18 18:12:47 +08:00
/*
2021-01-11 02:19:10 -08:00
* Copyright 2017 - 2021 , John Wu ( @ topjohnwu )
2017-04-15 03:21:31 +08:00
* Copyright 2015 , Pierre - Hugues Husson < phh @ phh . me >
* Copyright 2010 , Adam Shanks ( @ ChainsDD )
* Copyright 2008 , Zinx Verituse ( @ zinxv )
*/
# include <unistd.h>
2018-07-18 18:12:47 +08:00
# include <getopt.h>
2017-04-15 03:21:31 +08:00
# include <fcntl.h>
2018-07-18 18:12:47 +08:00
# include <pwd.h>
2017-07-08 01:12:47 +08:00
# include <sched.h>
2018-07-18 18:12:47 +08:00
# include <sys/types.h>
2017-04-15 03:21:31 +08:00
# include <sys/stat.h>
2018-07-18 18:12:47 +08:00
2021-01-11 02:19:10 -08:00
# include <magisk.hpp>
2022-05-12 02:03:42 -07:00
# include <base.hpp>
2021-09-07 19:35:28 -07:00
# include <flags.h>
2019-02-10 03:57:51 -05:00
2020-03-09 01:50:30 -07:00
# include "su.hpp"
# include "pts.hpp"
2018-07-18 18:12:47 +08:00
2018-11-20 04:40:42 -05:00
int quit_signals [ ] = { SIGALRM , SIGABRT , SIGHUP , SIGPIPE , SIGQUIT , SIGTERM , SIGINT , 0 } ;
2018-10-12 21:46:09 -04:00
2023-05-16 19:26:44 +08:00
[[noreturn]] static void usage ( int status ) {
2020-12-30 22:11:24 -08:00
FILE * stream = ( status = = EXIT_SUCCESS ) ? stdout : stderr ;
fprintf ( stream ,
" MagiskSU \n \n "
2023-05-22 16:56:43 +08:00
" Usage: su [options] [-] [user [argument...]] \n \n "
2020-12-30 22:11:24 -08:00
" Options: \n "
" -c, --command COMMAND pass COMMAND to the invoked shell \n "
2023-05-22 16:56:43 +08:00
" -g, --group GROUP Specify the primary group \n "
" -G, --supp-group GROUP Specify a supplementary group. The first specified supplementary group is also used as a primary group if the option --group is not specified. \n "
2023-05-18 01:25:05 +08:00
" -z, --context CONTEXT change SELinux context \n "
2023-05-18 02:08:25 +08:00
" -t, --target PID PID to take mount namespace from \n "
2020-12-30 22:11:24 -08:00
" -h, --help display this help message and exit \n "
" -, -l, --login pretend the shell to be a login shell \n "
" -m, -p, \n "
" --preserve-environment preserve the entire environment \n "
" -s, --shell SHELL use SHELL instead of the default " DEFAULT_SHELL " \n "
" -v, --version display version number and exit \n "
" -V display version code and exit \n "
" -mm, -M, \n "
2022-01-25 02:04:15 -08:00
" --mount-master force run in the global mount namespace \n \n " ) ;
2020-12-30 22:11:24 -08:00
exit ( status ) ;
2018-07-18 18:12:47 +08:00
}
2018-10-04 04:59:51 -04:00
static void sighandler ( int sig ) {
2020-12-30 22:11:24 -08:00
restore_stdin ( ) ;
// Assume we'll only be called before death
// See note before sigaction() in set_stdin_raw()
//
// Now, close all standard I/O to cause the pumps
// to exit so we can continue and retrieve the exit
// code
close ( STDIN_FILENO ) ;
close ( STDOUT_FILENO ) ;
close ( STDERR_FILENO ) ;
// Put back all the default handlers
struct sigaction act ;
memset ( & act , 0 , sizeof ( act ) ) ;
act . sa_handler = SIG_DFL ;
for ( int i = 0 ; quit_signals [ i ] ; + + i ) {
sigaction ( quit_signals [ i ] , & act , nullptr ) ;
}
2018-07-18 18:12:47 +08:00
}
2018-10-12 21:46:09 -04:00
static void setup_sighandlers ( void ( * handler ) ( int ) ) {
2020-12-30 22:11:24 -08:00
struct sigaction act ;
memset ( & act , 0 , sizeof ( act ) ) ;
act . sa_handler = handler ;
for ( int i = 0 ; quit_signals [ i ] ; + + i ) {
sigaction ( quit_signals [ i ] , & act , nullptr ) ;
}
2018-10-12 21:46:09 -04:00
}
2018-10-04 04:59:51 -04:00
int su_client_main ( int argc , char * argv [ ] ) {
2020-12-30 22:11:24 -08:00
int c ;
struct option long_opts [ ] = {
{ " command " , required_argument , nullptr , ' c ' } ,
{ " help " , no_argument , nullptr , ' h ' } ,
{ " login " , no_argument , nullptr , ' l ' } ,
{ " preserve-environment " , no_argument , nullptr , ' p ' } ,
{ " shell " , required_argument , nullptr , ' s ' } ,
{ " version " , no_argument , nullptr , ' v ' } ,
{ " context " , required_argument , nullptr , ' z ' } ,
{ " mount-master " , no_argument , nullptr , ' M ' } ,
2023-05-18 02:08:25 +08:00
{ " target " , required_argument , nullptr , ' t ' } ,
2023-05-22 16:56:43 +08:00
{ " group " , required_argument , nullptr , ' g ' } ,
{ " supp-group " , required_argument , nullptr , ' G ' } ,
2020-12-30 22:11:24 -08:00
{ nullptr , 0 , nullptr , 0 } ,
} ;
su_request su_req ;
for ( int i = 0 ; i < argc ; i + + ) {
// Replace -cn with -z, -mm with -M for supporting getopt_long
if ( strcmp ( argv [ i ] , " -cn " ) = = 0 )
strcpy ( argv [ i ] , " -z " ) ;
else if ( strcmp ( argv [ i ] , " -mm " ) = = 0 )
strcpy ( argv [ i ] , " -M " ) ;
}
2023-05-22 16:56:43 +08:00
while ( ( c = getopt_long ( argc , argv , " c:hlmps:Vvuz:Mt:g:G: " , long_opts , nullptr ) ) ! = - 1 ) {
2020-12-30 22:11:24 -08:00
switch ( c ) {
case ' c ' :
2021-01-12 00:07:48 -08:00
for ( int i = optind - 1 ; i < argc ; + + i ) {
if ( ! su_req . command . empty ( ) )
su_req . command + = ' ' ;
su_req . command + = argv [ i ] ;
}
2020-12-30 22:11:24 -08:00
optind = argc ;
break ;
case ' h ' :
usage ( EXIT_SUCCESS ) ;
case ' l ' :
su_req . login = true ;
break ;
case ' m ' :
case ' p ' :
su_req . keepenv = true ;
break ;
case ' s ' :
su_req . shell = optarg ;
break ;
case ' V ' :
printf ( " %d \n " , MAGISK_VER_CODE ) ;
exit ( EXIT_SUCCESS ) ;
case ' v ' :
printf ( " %s \n " , MAGISK_VERSION " :MAGISKSU " ) ;
exit ( EXIT_SUCCESS ) ;
case ' z ' :
2023-05-18 01:25:05 +08:00
su_req . context = optarg ;
2020-12-30 22:11:24 -08:00
break ;
case ' M ' :
2023-05-18 02:08:25 +08:00
case ' t ' :
if ( su_req . target ! = - 1 ) {
fprintf ( stderr , " Can't use -M and -t at the same time \n " ) ;
usage ( EXIT_FAILURE ) ;
}
if ( optarg = = nullptr ) {
su_req . target = 0 ;
} else {
su_req . target = parse_int ( optarg ) ;
if ( * optarg = = ' - ' | | su_req . target = = - 1 ) {
fprintf ( stderr , " Invalid PID: %s \n " , optarg ) ;
usage ( EXIT_FAILURE ) ;
}
}
2020-12-30 22:11:24 -08:00
break ;
2023-05-22 16:56:43 +08:00
case ' g ' :
case ' G ' :
if ( int gid = parse_int ( optarg ) ; gid > = 0 ) {
su_req . gids . insert ( c = = ' g ' ? su_req . gids . begin ( ) : su_req . gids . end ( ) , gid ) ;
} else {
fprintf ( stderr , " Invalid GID: %s \n " , optarg ) ;
usage ( EXIT_FAILURE ) ;
}
break ;
2020-12-30 22:11:24 -08:00
default :
/* Bionic getopt_long doesn't terminate its error output by newline */
fprintf ( stderr , " \n " ) ;
usage ( 2 ) ;
}
}
if ( optind < argc & & strcmp ( argv [ optind ] , " - " ) = = 0 ) {
su_req . login = true ;
optind + + ;
}
/* username or uid */
if ( optind < argc ) {
struct passwd * pw ;
2023-05-22 16:56:43 +08:00
pw = getpwnam ( argv [ optind ] ) ;
if ( pw )
su_req . uid = pw - > pw_uid ;
else
su_req . uid = parse_int ( argv [ optind ] ) ;
2020-12-30 22:11:24 -08:00
optind + + ;
}
int ptmx , fd ;
// Connect to client
2022-03-01 02:13:18 -08:00
fd = connect_daemon ( MainRequest : : SUPERUSER ) ;
2020-12-30 22:11:24 -08:00
// Send su_request
xwrite ( fd , & su_req , sizeof ( su_req_base ) ) ;
write_string ( fd , su_req . shell ) ;
write_string ( fd , su_req . command ) ;
2023-05-18 01:25:05 +08:00
write_string ( fd , su_req . context ) ;
2023-05-16 19:26:44 +08:00
write_vector ( fd , su_req . gids ) ;
2020-12-30 22:11:24 -08:00
// Wait for ack from daemon
if ( read_int ( fd ) ) {
// Fast fail
fprintf ( stderr , " %s \n " , strerror ( EACCES ) ) ;
return EACCES ;
}
// Determine which one of our streams are attached to a TTY
int atty = 0 ;
if ( isatty ( STDIN_FILENO ) ) atty | = ATTY_IN ;
if ( isatty ( STDOUT_FILENO ) ) atty | = ATTY_OUT ;
if ( isatty ( STDERR_FILENO ) ) atty | = ATTY_ERR ;
// Send stdin
send_fd ( fd , ( atty & ATTY_IN ) ? - 1 : STDIN_FILENO ) ;
// Send stdout
send_fd ( fd , ( atty & ATTY_OUT ) ? - 1 : STDOUT_FILENO ) ;
// Send stderr
send_fd ( fd , ( atty & ATTY_ERR ) ? - 1 : STDERR_FILENO ) ;
2021-07-22 23:35:14 +08:00
if ( atty ) {
// We need a PTY. Get one.
write_int ( fd , 1 ) ;
ptmx = recv_fd ( fd ) ;
} else {
write_int ( fd , 0 ) ;
}
2020-12-30 22:11:24 -08:00
if ( atty ) {
setup_sighandlers ( sighandler ) ;
watch_sigwinch_async ( STDOUT_FILENO , ptmx ) ;
pump_stdin_async ( ptmx ) ;
pump_stdout_blocking ( ptmx ) ;
}
// Get the exit code
int code = read_int ( fd ) ;
close ( fd ) ;
return code ;
2018-11-04 03:38:06 -05:00
}