aboutsummaryrefslogtreecommitdiff
path: root/loginutils/suw32.c
diff options
context:
space:
mode:
Diffstat (limited to 'loginutils/suw32.c')
-rw-r--r--loginutils/suw32.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/loginutils/suw32.c b/loginutils/suw32.c
new file mode 100644
index 000000000..77c038582
--- /dev/null
+++ b/loginutils/suw32.c
@@ -0,0 +1,163 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini su implementation for busybox-w32
4 *
5 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
6 */
7//config:config SUW32
8//config: bool "su for Microsoft Windows"
9//config: default y
10//config: depends on PLATFORM_MINGW32 && ASH
11//config: help
12//config: su runs a shell with elevated privileges.
13
14//applet:IF_SUW32(APPLET_ODDNAME(su, suw32, BB_DIR_BIN, BB_SUID_DROP, suw32))
15
16//kbuild:lib-$(CONFIG_SUW32) += suw32.o
17
18//usage:#define suw32_trivial_usage
19//usage: "[-tW] [-N|-s SHELL] [root]\n"
20//usage: "or: su [-tW] [-N|-s SHELL] -c CMD_STRING [[--] root [ARG0 [ARG...]]]\n"
21//usage: "or: su [-tW] [-N|-s SHELL] [--] root [arbitrary sh arguments]"
22//usage:#define suw32_full_usage "\n\n"
23//usage: "Run shell with elevated privileges\n"
24//usage: "\n -c CMD Command to pass to 'sh -c'"
25//usage: "\n -s SHELL Use specified shell"
26//usage: "\n -N Don't close console when shell exits"
27//usage: "\n -t Test mode, no elevation, implies -W"
28//usage: "\n -W Wait for shell exit code"
29
30#include "libbb.h"
31#include "lazyload.h"
32
33enum {
34 OPT_c = (1 << 0),
35 OPT_s = (1 << 1),
36 OPT_t = (1 << 2),
37 OPT_N = (1 << 3),
38 OPT_W = (1 << 4)
39};
40
41#define test_mode (opt & OPT_t)
42
43int suw32_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
44int suw32_main(int argc UNUSED_PARAM, char **argv)
45{
46 int ret = 0;
47 unsigned opt;
48 char *opt_command = NULL;
49 char *opt_shell = NULL;
50 SHELLEXECUTEINFO info;
51 const char *bb_path;
52 char *cwd, *realcwd, *q, *args;
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
63#if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP
64 // If privilege has been dropped (ELEVATED_PRIVILEGE but not
65 // ADMIN_ENABLED) ShellExecuteEx() thinks we already have elevated
66 // privilege and doesn't raise privilege. In that case, give up.
67 if (!test_mode && elevation_state() == ELEVATED_PRIVILEGE) {
68 xfunc_error_retval = 2;
69 bb_error_msg_and_die("unable to restore privilege");
70 }
71#endif
72
73 if (opt_shell) {
74 bb_path = file_is_win32_exe(opt_shell);
75 if (!bb_path)
76 bb_error_msg_and_die("%s: Not found", opt_shell);
77 args = NULL;
78 } else {
79 bb_path = bb_busybox_exec_path;
80 args = xstrdup("--busybox ash");
81 if (!test_mode)
82 args = xappendword(args, "-t \"BusyBox ash (Admin)\"");
83 }
84
85 memset(&info, 0, sizeof(SHELLEXECUTEINFO));
86 info.cbSize = sizeof(SHELLEXECUTEINFO);
87 /* info.fMask = SEE_MASK_DEFAULT; */
88 if (opt & (OPT_t|OPT_W))
89 info.fMask |= SEE_MASK_NOCLOSEPROCESS;
90 if (test_mode)
91 info.fMask |= SEE_MASK_NO_CONSOLE;
92 /* info.hwnd = NULL; */
93 info.lpVerb = !test_mode ? "runas" : "open";
94 info.lpFile = bb_path;
95 /*
96 * It seems that when ShellExecuteEx() runs binaries residing in
97 * certain 'system' directories it sets the current directory of
98 * the process to %SYSTEMROOT%\System32. Override this by passing
99 * the directory we want to the shell.
100 *
101 * Canonicalise the directory now: if it's in a drive mapped to
102 * a network share it may not be available once we have elevated
103 * privileges.
104 */
105 if (opt_shell == NULL) {
106 cwd = getcwd(NULL, 0);
107 realcwd = cwd ? xmalloc_realpath(cwd) : NULL;
108 if (realcwd || cwd) {
109 args = xappendword(args, "-d");
110 q = quote_arg(realcwd ?: cwd);
111 args = xappendword(args, q);
112 free(q);
113 }
114 }
115
116 if (opt & OPT_N)
117 args = xappendword(args, "-N");
118
119 if (opt_command) {
120 args = xappendword(args,
121 (opt_shell && strcasecmp(bb_basename(bb_path), "cmd.exe") == 0) ?
122 "/c" : "-c");
123 q = quote_arg(opt_command);
124 args = xappendword(args, q);
125 free(q);
126 }
127
128 while (*argv) {
129 q = quote_arg(*argv++);
130 args = xappendword(args, q);
131 free(q);
132 }
133
134 info.lpParameters = args;
135 /* info.lpDirectory = NULL; */
136 info.nShow = SW_SHOWNORMAL;
137
138 if (!mingw_shell_execute(&info)) {
139 ret = 1;
140 goto end;
141 }
142
143 if (opt & (OPT_t|OPT_W)) {
144 DWORD r;
145
146 WaitForSingleObject(info.hProcess, INFINITE);
147 if (!GetExitCodeProcess(info.hProcess, &r))
148 ret = 1;
149 else
150 ret = exit_code_to_posix(r);
151 CloseHandle(info.hProcess);
152 }
153 end:
154 if (ENABLE_FEATURE_CLEAN_UP) {
155 if (bb_path != bb_busybox_exec_path)
156 free((void *)bb_path);
157 free(cwd);
158 free(realcwd);
159 free(args);
160 }
161
162 return ret;
163}