@@ -53,8 +53,11 @@ static struct su_initiator su_from = {
53
53
static struct su_request su_to = {
54
54
.uid = AID_ROOT ,
55
55
.login = 0 ,
56
- .doshell = 1 ,
57
- .command = DEFAULT_COMMAND ,
56
+ .shell = DEFAULT_SHELL ,
57
+ .command = NULL ,
58
+ .argv = NULL ,
59
+ .argc = 0 ,
60
+ .optind = 0 ,
58
61
};
59
62
60
63
static int from_init (struct su_initiator * from )
@@ -206,6 +209,7 @@ static int socket_send_request(int fd, struct su_initiator *from, struct su_requ
206
209
{
207
210
size_t len ;
208
211
size_t bin_size , cmd_size ;
212
+ char * cmd ;
209
213
210
214
#define write_token (fd , data ) \
211
215
do { \
@@ -230,9 +234,10 @@ do { \
230
234
PLOGE ("write(bin)" );
231
235
return -1 ;
232
236
}
233
- cmd_size = strlen (to -> command ) + 1 ;
237
+ cmd = (to -> command ) ? to -> command : to -> shell ;
238
+ cmd_size = strlen (cmd ) + 1 ;
234
239
write_token (fd , cmd_size );
235
- len = write (fd , to -> command , cmd_size );
240
+ len = write (fd , cmd , cmd_size );
236
241
if (len != cmd_size ) {
237
242
PLOGE ("write(cmd)" );
238
243
return -1 ;
@@ -259,13 +264,13 @@ static void usage(int status)
259
264
FILE * stream = (status == EXIT_SUCCESS ) ? stdout : stderr ;
260
265
261
266
fprintf (stream ,
262
- "Usage: su [options] [LOGIN]\n\n"
267
+ "Usage: su [options] [--] [-] [ LOGIN] [--] [args... ]\n\n"
263
268
"Options:\n"
264
269
" -c, --command COMMAND pass COMMAND to the invoked shell\n"
265
270
" -h, --help display this help message and exit\n"
266
271
" -, -l, --login, -m, -p,\n"
267
272
" --preserve-environment do nothing, kept for compatibility\n"
268
- " -s, --shell SHELL use SHELL instead of the default " DEFAULT_COMMAND "\n"
273
+ " -s, --shell SHELL use SHELL instead of the default " DEFAULT_SHELL "\n"
269
274
" -v, --version display version number and exit\n"
270
275
" -V display version code and exit,\n"
271
276
" this is used almost exclusively by Superuser.apk\n" );
@@ -276,40 +281,36 @@ static void deny(void)
276
281
{
277
282
struct su_initiator * from = & su_from ;
278
283
struct su_request * to = & su_to ;
284
+ char * cmd = (to -> command ) ? to -> command : to -> shell ;
279
285
280
286
send_intent (& su_from , & su_to , "" , 0 , 1 );
281
- LOGW ("request rejected (%u->%u %s)" , from -> uid , to -> uid , to -> command );
287
+ LOGW ("request rejected (%u->%u %s)" , from -> uid , to -> uid , cmd );
282
288
fprintf (stderr , "%s\n" , strerror (EACCES ));
283
289
exit (EXIT_FAILURE );
284
290
}
285
291
286
- static void allow (char * shell , mode_t mask )
292
+ static void allow (void )
287
293
{
288
294
struct su_initiator * from = & su_from ;
289
295
struct su_request * to = & su_to ;
290
- char * exe = NULL ;
291
- char * argv [4 ];
292
- int argc = 0 ;
293
- int err ;
296
+ char * arg0 ;
297
+ int argc , err ;
294
298
295
- umask (mask );
299
+ umask (to -> umask );
296
300
send_intent (& su_from , & su_to , "" , 1 , 1 );
297
301
298
- if (!shell ) {
299
- shell = DEFAULT_COMMAND ;
300
- }
301
- exe = strrchr (shell , '/' );
302
- exe = (exe ) ? exe + 1 : shell ;
302
+ arg0 = strrchr (to -> shell , '/' );
303
+ arg0 = (arg0 ) ? arg0 + 1 : to -> shell ;
303
304
if (to -> login ) {
304
- int s = strlen (exe ) + 2 ;
305
+ int s = strlen (arg0 ) + 2 ;
305
306
char * p = malloc (s );
306
307
307
308
if (!p )
308
309
exit (EXIT_FAILURE );
309
310
310
311
* p = '-' ;
311
- strcpy (p + 1 , exe );
312
- exe = p ;
312
+ strcpy (p + 1 , arg0 );
313
+ arg0 = p ;
313
314
}
314
315
if (setresgid (to -> uid , to -> uid , to -> uid )) {
315
316
PLOGE ("setresgid (%u)" , to -> uid );
@@ -319,30 +320,34 @@ static void allow(char *shell, mode_t mask)
319
320
PLOGE ("setresuid (%u)" , to -> uid );
320
321
exit (EXIT_FAILURE );
321
322
}
322
- LOGD ("%u %s executing %u %s using shell %s : %s" , from -> uid , from -> bin ,
323
- to -> uid , to -> command , shell , exe );
324
- argv [argc ++ ] = exe ;
325
- if (to -> doshell ) {
326
- argv [argc ++ ] = "-" ;
327
- } else {
328
- argv [argc ++ ] = "-c" ;
329
- argv [argc ++ ] = to -> command ;
323
+
324
+ #define PARG (arg ) (to->optind + (arg) < to->argc) ? " " : "", \
325
+ (to->optind + (arg) < to->argc) ? to->argv[to->optind + (arg)] : ""
326
+ LOGD ("%u %s executing %u %s using shell %s : %s%s%s%s%s%s%s%s%s%s%s%s%s%s" ,
327
+ from -> uid , from -> bin ,
328
+ to -> uid , (to -> command ) ? to -> command : to -> shell , to -> shell ,
329
+ arg0 , PARG (0 ), PARG (1 ), PARG (2 ), PARG (3 ), PARG (4 ), PARG (5 ),
330
+ (to -> optind + 6 < to -> argc ) ? " ..." : "" );
331
+
332
+ argc = to -> optind ;
333
+ if (to -> command ) {
334
+ to -> argv [-- argc ] = to -> command ;
335
+ to -> argv [-- argc ] = "-c" ;
330
336
}
331
- argv [argc ] = NULL ;
332
- execv (shell , argv );
337
+ to -> argv [-- argc ] = arg0 ;
338
+ execv (to -> shell , to -> argv + argc );
333
339
err = errno ;
334
340
PLOGE ("exec" );
335
- fprintf (stderr , "Cannot execute %s: %s\n" , shell , strerror (err ));
341
+ fprintf (stderr , "Cannot execute %s: %s\n" , to -> shell , strerror (err ));
336
342
exit (EXIT_FAILURE );
337
343
}
338
344
339
345
int main (int argc , char * argv [])
340
346
{
341
347
struct stat st ;
342
348
int socket_serv_fd , fd ;
343
- char buf [64 ], * shell = NULL , * result ;
349
+ char buf [64 ], * result ;
344
350
int c , dballow ;
345
- mode_t orig_umask ;
346
351
struct option long_opts [] = {
347
352
{ "command" , required_argument , NULL , 'c' },
348
353
{ "help" , no_argument , NULL , 'h' },
@@ -353,11 +358,10 @@ int main(int argc, char *argv[])
353
358
{ NULL , 0 , NULL , 0 },
354
359
};
355
360
356
- while ((c = getopt_long (argc , argv , "c:hlmps:Vv" , long_opts , NULL )) != -1 ) {
361
+ while ((c = getopt_long (argc , argv , "+ c:hlmps:Vv" , long_opts , NULL )) != -1 ) {
357
362
switch (c ) {
358
363
case 'c' :
359
364
su_to .command = optarg ;
360
- su_to .doshell = 0 ;
361
365
break ;
362
366
case 'h' :
363
367
usage (EXIT_SUCCESS );
@@ -369,7 +373,7 @@ int main(int argc, char *argv[])
369
373
case 'p' :
370
374
break ;
371
375
case 's' :
372
- shell = optarg ;
376
+ su_to . shell = optarg ;
373
377
break ;
374
378
case 'V' :
375
379
printf ("%d\n" , VERSION_CODE );
@@ -387,14 +391,8 @@ int main(int argc, char *argv[])
387
391
su_to .login = 1 ;
388
392
optind ++ ;
389
393
}
390
- /*
391
- * Other su implementations pass the remaining args to the shell.
392
- * -- maybe implement this later
393
- */
394
- if (optind < argc - 1 ) {
395
- usage (2 );
396
- }
397
- if (optind == argc - 1 ) {
394
+ /* username or uid */
395
+ if (optind < argc && strcmp (argv [optind ], "--" )) {
398
396
struct passwd * pw ;
399
397
pw = getpwnam (argv [optind ]);
400
398
if (!pw ) {
@@ -411,16 +409,23 @@ int main(int argc, char *argv[])
411
409
} else {
412
410
su_to .uid = pw -> pw_uid ;
413
411
}
412
+ optind ++ ;
413
+ }
414
+ if (optind < argc && !strcmp (argv [optind ], "--" )) {
415
+ optind ++ ;
414
416
}
417
+ su_to .argv = argv ;
418
+ su_to .argc = argc ;
419
+ su_to .optind = optind ;
415
420
416
421
if (from_init (& su_from ) < 0 ) {
417
422
deny ();
418
423
}
419
424
420
- orig_umask = umask (027 );
425
+ su_to . umask = umask (027 );
421
426
422
427
if (su_from .uid == AID_ROOT || su_from .uid == AID_SHELL )
423
- allow (shell , orig_umask );
428
+ allow ();
424
429
425
430
if (stat (REQUESTOR_DATA_PATH , & st ) < 0 ) {
426
431
PLOGE ("stat" );
@@ -456,7 +461,7 @@ int main(int argc, char *argv[])
456
461
dballow = database_check (& su_from , & su_to );
457
462
switch (dballow ) {
458
463
case DB_DENY : deny ();
459
- case DB_ALLOW : allow (shell , orig_umask );
464
+ case DB_ALLOW : allow ();
460
465
case DB_INTERACTIVE : break ;
461
466
default : deny ();
462
467
}
@@ -504,7 +509,7 @@ int main(int argc, char *argv[])
504
509
if (!strcmp (result , "DENY" )) {
505
510
deny ();
506
511
} else if (!strcmp (result , "ALLOW" )) {
507
- allow (shell , orig_umask );
512
+ allow ();
508
513
} else {
509
514
LOGE ("unknown response from Superuser Requestor: %s" , result );
510
515
deny ();
0 commit comments