From 2908a94a565c162eea751f1d7042b75cdc8cd13d Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Wed, 7 Aug 2024 12:32:11 +0100 Subject: su: add test mode Testing some uses of 'su' can be challenging because any errors appear in the new console window which may close as a result. Add the '-t' option to enable test mode. This starts a new shell using ShellExecuteEx(), but without elevated privileges and a new console. All other options and arguments are handled much as before, though some differences in behaviour are to be expected due to the lack of elevated privilege. Adds 80-96 bytes. (GitHub issue #438) --- loginutils/suw32.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/loginutils/suw32.c b/loginutils/suw32.c index 821071388..11935e326 100644 --- a/loginutils/suw32.c +++ b/loginutils/suw32.c @@ -16,14 +16,15 @@ //kbuild:lib-$(CONFIG_SUW32) += suw32.o //usage:#define suw32_trivial_usage -//usage: "[-W] [-N|-s SHELL] [root]\n" -//usage: "or: su [-W] [-N|-s SHELL] -c CMD_STRING [[--] root [ARG0 [ARG...]]]\n" -//usage: "or: su [-W] [-N|-s SHELL] [--] root [arbitrary sh arguments]" +//usage: "[-tW] [-N|-s SHELL] [root]\n" +//usage: "or: su [-tW] [-N|-s SHELL] -c CMD_STRING [[--] root [ARG0 [ARG...]]]\n" +//usage: "or: su [-tW] [-N|-s SHELL] [--] root [arbitrary sh arguments]" //usage:#define suw32_full_usage "\n\n" //usage: "Run shell with elevated privileges\n" //usage: "\n -c CMD Command to pass to 'sh -c'" //usage: "\n -s SHELL Use specified shell" //usage: "\n -N Don't close console when shell exits" +//usage: "\n -t Test mode, no elevation" //usage: "\n -W Wait for shell exit code" #include "libbb.h" @@ -32,10 +33,13 @@ enum { OPT_c = (1 << 0), OPT_s = (1 << 1), - OPT_N = (1 << 2), - OPT_W = (1 << 3) + OPT_t = (1 << 2), + OPT_N = (1 << 3), + OPT_W = (1 << 4) }; +#define test_mode (opt & OPT_t) + int suw32_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int suw32_main(int argc UNUSED_PARAM, char **argv) { @@ -47,25 +51,25 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) char *bb_path, *cwd, *realcwd, *q, *args; DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); + opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell); + argv += optind; + if (argv[0]) { + if (!test_mode && strcmp(argv[0], "root") != 0) { + bb_error_msg_and_die("unknown user '%s'", argv[0]); + } + ++argv; + } + #if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP // If privilege has been dropped (ELEVATED_PRIVILEGE but not // ADMIN_ENABLED) ShellExecuteEx() thinks we already have elevated // privilege and doesn't raise privilege. In that case, give up. - if (elevation_state() == ELEVATED_PRIVILEGE) { + if (!test_mode && elevation_state() == ELEVATED_PRIVILEGE) { xfunc_error_retval = 2; bb_error_msg_and_die("unable to restore privilege"); } #endif - opt = getopt32(argv, "^c:s:NW" "\0" "s--N:N--s", &opt_command, &opt_shell); - argv += optind; - if (argv[0]) { - if (strcmp(argv[0], "root") != 0) { - bb_error_msg_and_die("unknown user '%s'", argv[0]); - } - ++argv; - } - /* ShellExecuteEx() needs backslash as separator in UNC paths. */ if (opt_shell) { bb_path = file_is_win32_exe(opt_shell); @@ -74,17 +78,21 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) args = NULL; } else { bb_path = xstrdup(bb_busybox_exec_path); - args = xasprintf("--busybox ash -t \"BusyBox ash (Admin)\""); + args = xstrdup("--busybox ash"); + if (!test_mode) + args = xappendword(args, "-t \"BusyBox ash (Admin)\""); } slash_to_bs(bb_path); memset(&info, 0, sizeof(SHELLEXECUTEINFO)); info.cbSize = sizeof(SHELLEXECUTEINFO); /* info.fMask = SEE_MASK_DEFAULT; */ - if (opt & OPT_W) + if (opt & (OPT_t|OPT_W)) info.fMask |= SEE_MASK_NOCLOSEPROCESS; + if (test_mode) + info.fMask |= SEE_MASK_NO_CONSOLE; /* info.hwnd = NULL; */ - info.lpVerb = "runas"; + info.lpVerb = !test_mode ? "runas" : "open"; info.lpFile = bb_path; /* * It seems that when ShellExecuteEx() runs binaries residing in @@ -139,7 +147,7 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) goto end; } - if (opt & OPT_W) { + if (opt & (OPT_t|OPT_W)) { DWORD r; WaitForSingleObject(info.hProcess, INFINITE); -- cgit v1.2.3-55-g6feb