diff options
| author | Ron Yorston <rmy@pobox.com> | 2024-08-07 12:32:11 +0100 |
|---|---|---|
| committer | Ron Yorston <rmy@pobox.com> | 2024-08-07 12:32:11 +0100 |
| commit | 2908a94a565c162eea751f1d7042b75cdc8cd13d (patch) | |
| tree | e0a010428c859aed5067df37e01bae57714e822a | |
| parent | e5244175baa5c94726670a6aeb8645428306011a (diff) | |
| download | busybox-w32-2908a94a565c162eea751f1d7042b75cdc8cd13d.tar.gz busybox-w32-2908a94a565c162eea751f1d7042b75cdc8cd13d.tar.bz2 busybox-w32-2908a94a565c162eea751f1d7042b75cdc8cd13d.zip | |
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)
| -rw-r--r-- | loginutils/suw32.c | 46 |
1 files 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 @@ | |||
| 16 | //kbuild:lib-$(CONFIG_SUW32) += suw32.o | 16 | //kbuild:lib-$(CONFIG_SUW32) += suw32.o |
| 17 | 17 | ||
| 18 | //usage:#define suw32_trivial_usage | 18 | //usage:#define suw32_trivial_usage |
| 19 | //usage: "[-W] [-N|-s SHELL] [root]\n" | 19 | //usage: "[-tW] [-N|-s SHELL] [root]\n" |
| 20 | //usage: "or: su [-W] [-N|-s SHELL] -c CMD_STRING [[--] root [ARG0 [ARG...]]]\n" | 20 | //usage: "or: su [-tW] [-N|-s SHELL] -c CMD_STRING [[--] root [ARG0 [ARG...]]]\n" |
| 21 | //usage: "or: su [-W] [-N|-s SHELL] [--] root [arbitrary sh arguments]" | 21 | //usage: "or: su [-tW] [-N|-s SHELL] [--] root [arbitrary sh arguments]" |
| 22 | //usage:#define suw32_full_usage "\n\n" | 22 | //usage:#define suw32_full_usage "\n\n" |
| 23 | //usage: "Run shell with elevated privileges\n" | 23 | //usage: "Run shell with elevated privileges\n" |
| 24 | //usage: "\n -c CMD Command to pass to 'sh -c'" | 24 | //usage: "\n -c CMD Command to pass to 'sh -c'" |
| 25 | //usage: "\n -s SHELL Use specified shell" | 25 | //usage: "\n -s SHELL Use specified shell" |
| 26 | //usage: "\n -N Don't close console when shell exits" | 26 | //usage: "\n -N Don't close console when shell exits" |
| 27 | //usage: "\n -t Test mode, no elevation" | ||
| 27 | //usage: "\n -W Wait for shell exit code" | 28 | //usage: "\n -W Wait for shell exit code" |
| 28 | 29 | ||
| 29 | #include "libbb.h" | 30 | #include "libbb.h" |
| @@ -32,10 +33,13 @@ | |||
| 32 | enum { | 33 | enum { |
| 33 | OPT_c = (1 << 0), | 34 | OPT_c = (1 << 0), |
| 34 | OPT_s = (1 << 1), | 35 | OPT_s = (1 << 1), |
| 35 | OPT_N = (1 << 2), | 36 | OPT_t = (1 << 2), |
| 36 | OPT_W = (1 << 3) | 37 | OPT_N = (1 << 3), |
| 38 | OPT_W = (1 << 4) | ||
| 37 | }; | 39 | }; |
| 38 | 40 | ||
| 41 | #define test_mode (opt & OPT_t) | ||
| 42 | |||
| 39 | int suw32_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 43 | int suw32_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| 40 | int suw32_main(int argc UNUSED_PARAM, char **argv) | 44 | int suw32_main(int argc UNUSED_PARAM, char **argv) |
| 41 | { | 45 | { |
| @@ -47,25 +51,25 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) | |||
| 47 | char *bb_path, *cwd, *realcwd, *q, *args; | 51 | char *bb_path, *cwd, *realcwd, *q, *args; |
| 48 | DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); | 52 | DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); |
| 49 | 53 | ||
| 54 | opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell); | ||
| 55 | argv += optind; | ||
| 56 | if (argv[0]) { | ||
| 57 | if (!test_mode && strcmp(argv[0], "root") != 0) { | ||
| 58 | bb_error_msg_and_die("unknown user '%s'", argv[0]); | ||
| 59 | } | ||
| 60 | ++argv; | ||
| 61 | } | ||
| 62 | |||
| 50 | #if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP | 63 | #if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP |
| 51 | // If privilege has been dropped (ELEVATED_PRIVILEGE but not | 64 | // If privilege has been dropped (ELEVATED_PRIVILEGE but not |
| 52 | // ADMIN_ENABLED) ShellExecuteEx() thinks we already have elevated | 65 | // ADMIN_ENABLED) ShellExecuteEx() thinks we already have elevated |
| 53 | // privilege and doesn't raise privilege. In that case, give up. | 66 | // privilege and doesn't raise privilege. In that case, give up. |
| 54 | if (elevation_state() == ELEVATED_PRIVILEGE) { | 67 | if (!test_mode && elevation_state() == ELEVATED_PRIVILEGE) { |
| 55 | xfunc_error_retval = 2; | 68 | xfunc_error_retval = 2; |
| 56 | bb_error_msg_and_die("unable to restore privilege"); | 69 | bb_error_msg_and_die("unable to restore privilege"); |
| 57 | } | 70 | } |
| 58 | #endif | 71 | #endif |
| 59 | 72 | ||
| 60 | opt = getopt32(argv, "^c:s:NW" "\0" "s--N:N--s", &opt_command, &opt_shell); | ||
| 61 | argv += optind; | ||
| 62 | if (argv[0]) { | ||
| 63 | if (strcmp(argv[0], "root") != 0) { | ||
| 64 | bb_error_msg_and_die("unknown user '%s'", argv[0]); | ||
| 65 | } | ||
| 66 | ++argv; | ||
| 67 | } | ||
| 68 | |||
| 69 | /* ShellExecuteEx() needs backslash as separator in UNC paths. */ | 73 | /* ShellExecuteEx() needs backslash as separator in UNC paths. */ |
| 70 | if (opt_shell) { | 74 | if (opt_shell) { |
| 71 | bb_path = file_is_win32_exe(opt_shell); | 75 | bb_path = file_is_win32_exe(opt_shell); |
| @@ -74,17 +78,21 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) | |||
| 74 | args = NULL; | 78 | args = NULL; |
| 75 | } else { | 79 | } else { |
| 76 | bb_path = xstrdup(bb_busybox_exec_path); | 80 | bb_path = xstrdup(bb_busybox_exec_path); |
| 77 | args = xasprintf("--busybox ash -t \"BusyBox ash (Admin)\""); | 81 | args = xstrdup("--busybox ash"); |
| 82 | if (!test_mode) | ||
| 83 | args = xappendword(args, "-t \"BusyBox ash (Admin)\""); | ||
| 78 | } | 84 | } |
| 79 | slash_to_bs(bb_path); | 85 | slash_to_bs(bb_path); |
| 80 | 86 | ||
| 81 | memset(&info, 0, sizeof(SHELLEXECUTEINFO)); | 87 | memset(&info, 0, sizeof(SHELLEXECUTEINFO)); |
| 82 | info.cbSize = sizeof(SHELLEXECUTEINFO); | 88 | info.cbSize = sizeof(SHELLEXECUTEINFO); |
| 83 | /* info.fMask = SEE_MASK_DEFAULT; */ | 89 | /* info.fMask = SEE_MASK_DEFAULT; */ |
| 84 | if (opt & OPT_W) | 90 | if (opt & (OPT_t|OPT_W)) |
| 85 | info.fMask |= SEE_MASK_NOCLOSEPROCESS; | 91 | info.fMask |= SEE_MASK_NOCLOSEPROCESS; |
| 92 | if (test_mode) | ||
| 93 | info.fMask |= SEE_MASK_NO_CONSOLE; | ||
| 86 | /* info.hwnd = NULL; */ | 94 | /* info.hwnd = NULL; */ |
| 87 | info.lpVerb = "runas"; | 95 | info.lpVerb = !test_mode ? "runas" : "open"; |
| 88 | info.lpFile = bb_path; | 96 | info.lpFile = bb_path; |
| 89 | /* | 97 | /* |
| 90 | * It seems that when ShellExecuteEx() runs binaries residing in | 98 | * It seems that when ShellExecuteEx() runs binaries residing in |
| @@ -139,7 +147,7 @@ int suw32_main(int argc UNUSED_PARAM, char **argv) | |||
| 139 | goto end; | 147 | goto end; |
| 140 | } | 148 | } |
| 141 | 149 | ||
| 142 | if (opt & OPT_W) { | 150 | if (opt & (OPT_t|OPT_W)) { |
| 143 | DWORD r; | 151 | DWORD r; |
| 144 | 152 | ||
| 145 | WaitForSingleObject(info.hProcess, INFINITE); | 153 | WaitForSingleObject(info.hProcess, INFINITE); |
