aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-08-07 12:32:11 +0100
committerRon Yorston <rmy@pobox.com>2024-08-07 12:32:11 +0100
commit2908a94a565c162eea751f1d7042b75cdc8cd13d (patch)
treee0a010428c859aed5067df37e01bae57714e822a
parente5244175baa5c94726670a6aeb8645428306011a (diff)
downloadbusybox-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.c46
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 @@
32enum { 33enum {
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
39int suw32_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 43int suw32_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
40int suw32_main(int argc UNUSED_PARAM, char **argv) 44int 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);