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); |