aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mingw.h1
-rw-r--r--util-linux/runuser.c97
-rw-r--r--win32/mingw.c2
-rw-r--r--win32/process.c2
4 files changed, 78 insertions, 24 deletions
diff --git a/include/mingw.h b/include/mingw.h
index 7e6109f2e..0ccced2a3 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -593,3 +593,4 @@ char *get_last_slash(const char *path);
593const char *applet_to_exe(const char *name); 593const char *applet_to_exe(const char *name);
594char *get_user_name(void); 594char *get_user_name(void);
595char *quote_arg(const char *arg); 595char *quote_arg(const char *arg);
596char *find_first_executable(const char *name);
diff --git a/util-linux/runuser.c b/util-linux/runuser.c
index f6abd9a74..6b87c641c 100644
--- a/util-linux/runuser.c
+++ b/util-linux/runuser.c
@@ -14,10 +14,19 @@
14//config: depends on PLATFORM_MINGW32 && SH_IS_ASH 14//config: depends on PLATFORM_MINGW32 && SH_IS_ASH
15//config: help 15//config: help
16//config: Run a shell without elevated privileges 16//config: Run a shell without elevated privileges
17//config:
18//config:config DROP
19//config: bool "drop"
20//config: default y
21//config: depends on PLATFORM_MINGW32 && SH_IS_ASH
22//config: help
23//config: Run a command without elevated privileges
17 24
18//applet:IF_RUNUSER(APPLET(runuser, BB_DIR_USR_BIN, BB_SUID_DROP)) 25//applet:IF_RUNUSER(APPLET(runuser, BB_DIR_USR_BIN, BB_SUID_DROP))
26//applet:IF_DROP(APPLET_ODDNAME(drop, runuser, BB_DIR_USR_BIN, BB_SUID_DROP, drop))
19 27
20//kbuild:lib-$(CONFIG_RUNUSER) += runuser.o 28//kbuild:lib-$(CONFIG_RUNUSER) += runuser.o
29//kbuild:lib-$(CONFIG_DROP) += runuser.o
21 30
22//usage:#define runuser_trivial_usage 31//usage:#define runuser_trivial_usage
23//usage: "USER [ARG...]" 32//usage: "USER [ARG...]"
@@ -26,14 +35,26 @@
26//usage: "must be that of the user who was granted those privileges.\n" 35//usage: "must be that of the user who was granted those privileges.\n"
27//usage: "Any arguments are passed to the shell.\n" 36//usage: "Any arguments are passed to the shell.\n"
28 37
38//usage:#define drop_trivial_usage
39//usage: "[COMMAND [ARG...]]"
40//usage:#define drop_full_usage "\n\n"
41//usage: "Run a command without elevated privileges. Run the BusyBox\n"
42//usage: "shell if no COMMAND is provided. Any arguments are passed\n"
43//usage: "to the command.\n"
44
29#include "libbb.h" 45#include "libbb.h"
30#include <winsafer.h> 46#include <winsafer.h>
31#include <lazyload.h> 47#include <lazyload.h>
32 48
33int runuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 49int runuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
34int runuser_main(int argc UNUSED_PARAM, char **argv) 50int runuser_main(int argc, char **argv)
35{ 51{
36 const char *user; 52#if ENABLE_RUNUSER && ENABLE_DROP
53 int is_runuser = strcmp(applet_name, "runuser") == 0;
54#else
55 const int is_runuser = ENABLE_RUNUSER;
56#endif
57 const char *user, *exe;
37 SAFER_LEVEL_HANDLE safer; 58 SAFER_LEVEL_HANDLE safer;
38 HANDLE token; 59 HANDLE token;
39 STARTUPINFO si; 60 STARTUPINFO si;
@@ -56,15 +77,17 @@ int runuser_main(int argc UNUSED_PARAM, char **argv)
56 if (!INIT_PROC_ADDR(advapi32.dll, CreateProcessAsUserA)) 77 if (!INIT_PROC_ADDR(advapi32.dll, CreateProcessAsUserA))
57 bb_simple_error_msg_and_die("not supported"); 78 bb_simple_error_msg_and_die("not supported");
58 79
59 if (getuid() != 0) 80 if (is_runuser) {
60 bb_simple_error_msg_and_die("may not be used by non-root users"); 81 if (getuid() != 0)
82 bb_simple_error_msg_and_die("may not be used by non-root users");
61 83
62 if (argc < 2) 84 if (argc < 2)
63 bb_show_usage(); 85 bb_show_usage();
64 86
65 user = get_user_name(); 87 user = get_user_name();
66 if (user == NULL || strcmp(argv[1], user) != 0) 88 if (user == NULL || strcmp(argv[1], user) != 0)
67 bb_simple_error_msg_and_die("invalid user"); 89 bb_simple_error_msg_and_die("invalid user");
90 }
68 91
69 /* 92 /*
70 * Run a shell using a token with reduced privilege. Hints from: 93 * Run a shell using a token with reduced privilege. Hints from:
@@ -81,16 +104,40 @@ int runuser_main(int argc UNUSED_PARAM, char **argv)
81 if (SetTokenInformation(token, TokenIntegrityLevel, &TIL, 104 if (SetTokenInformation(token, TokenIntegrityLevel, &TIL,
82 sizeof(TOKEN_MANDATORY_LABEL))) { 105 sizeof(TOKEN_MANDATORY_LABEL))) {
83 106
84 ZeroMemory(&si, sizeof(STARTUPINFO)); 107 if (is_runuser || argc == 1) {
85 si.cb = sizeof(STARTUPINFO); 108 exe = bb_busybox_exec_path;
86 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 109 cmd = xstrdup("sh");
87 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 110 } else {
88 si.hStdError = GetStdHandle(STD_ERROR_HANDLE); 111 char *file;
89 si.dwFlags = STARTF_USESTDHANDLES; 112
113#if ENABLE_FEATURE_PREFER_APPLETS
114 if (!has_path(argv[1]) && find_applet_by_name(argv[1]) >= 0) {
115 file = xstrdup(bb_busybox_exec_path);
116 cmd = argv[1];
117 } else
118#endif
119 if (has_path(argv[1])) {
120 file = cmd = file_is_win32_exe(argv[1]);
121 } else {
122 file = cmd = find_first_executable(argv[1]);
123 }
124
125 if (file == NULL) {
126 xfunc_error_retval = 127;
127 bb_error_msg_and_die("can't find '%s'", argv[1]);
128 }
129
130 slash_to_bs(file);
131 exe = file;
132 cmd = xstrdup(cmd);
133 file = quote_arg(cmd);
134 if (file != cmd)
135 free(cmd);
136 cmd = file;
137 }
90 138
91 // Build the command line 139 // Build the command line
92 cmd = xstrdup("sh"); 140 for (a = argv + 1 + (argc != 1); *a; ++a) {
93 for (a = argv + 2; *a; ++a) {
94 char *q = quote_arg(*a); 141 char *q = quote_arg(*a);
95 char *newcmd = xasprintf("%s %s", cmd, q); 142 char *newcmd = xasprintf("%s %s", cmd, q);
96 if (q != *a) 143 if (q != *a)
@@ -99,11 +146,17 @@ int runuser_main(int argc UNUSED_PARAM, char **argv)
99 cmd = newcmd; 146 cmd = newcmd;
100 } 147 }
101 148
102 if (!CreateProcessAsUserA(token, bb_busybox_exec_path, 149 ZeroMemory(&si, sizeof(STARTUPINFO));
103 cmd, NULL, NULL, TRUE, 0, NULL, 150 si.cb = sizeof(STARTUPINFO);
104 NULL, &si, &pi)) { 151 si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
105 errno = err_win_to_posix(); 152 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
106 bb_perror_msg_and_die("can't execute 'sh'"); 153 si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
154 si.dwFlags = STARTF_USESTDHANDLES;
155
156 if (!CreateProcessAsUserA(token, exe, cmd, NULL, NULL, TRUE,
157 0, NULL, NULL, &si, &pi)) {
158 xfunc_error_retval = 126;
159 bb_error_msg_and_die("can't execute '%s'", exe);
107 } 160 }
108 161
109 WaitForSingleObject(pi.hProcess, INFINITE); 162 WaitForSingleObject(pi.hProcess, INFINITE);
diff --git a/win32/mingw.c b/win32/mingw.c
index 0a1af6b72..fd670ebf6 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -1136,7 +1136,7 @@ char *get_user_name(void)
1136 return user_name; 1136 return user_name;
1137} 1137}
1138 1138
1139#if ENABLE_RUNUSER 1139#if ENABLE_RUNUSER || ENABLE_DROP
1140/* 1140/*
1141 * When runuser drops privileges TokenIsElevated still returns TRUE. 1141 * When runuser drops privileges TokenIsElevated still returns TRUE.
1142 * Use other means to determine if we're actually unprivileged. 1142 * Use other means to determine if we're actually unprivileged.
diff --git a/win32/process.c b/win32/process.c
index a0678f50d..7db7741fd 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -204,7 +204,7 @@ quote_arg(const char *arg)
204 return q; 204 return q;
205} 205}
206 206
207static char * 207char *
208find_first_executable(const char *name) 208find_first_executable(const char *name)
209{ 209{
210 char *tmp, *path = getenv("PATH"); 210 char *tmp, *path = getenv("PATH");