aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2025-02-03 11:55:28 +0000
committerRon Yorston <rmy@pobox.com>2025-02-03 11:55:28 +0000
commit14ccc45d548c9dfa73594f155e920c83e2882081 (patch)
treeaf1fcbc52ba1240474f321346781144d983bdc8d
parent820ade383860692d0b5abbba00a3e428f21b88e4 (diff)
downloadbusybox-w32-14ccc45d548c9dfa73594f155e920c83e2882081.tar.gz
busybox-w32-14ccc45d548c9dfa73594f155e920c83e2882081.tar.bz2
busybox-w32-14ccc45d548c9dfa73594f155e920c83e2882081.zip
win32: retry when command needs elevated privileges
Some installer programs have an entry in their manifest to indicate that they need elevated privileges. The shell in busybox-w32 was unable to run such programs. When a program fails to run with ERROR_ELEVATION_REQUIRED, try again using ShellExecuteEx() with the 'runas' verb to give it elevated privileges. Adds 272-288 bytes. (GitHub issue #481)
-rw-r--r--include/mingw.h1
-rw-r--r--loginutils/suw32.c18
-rw-r--r--win32/mingw.c22
-rw-r--r--win32/process.c42
4 files changed, 71 insertions, 12 deletions
diff --git a/include/mingw.h b/include/mingw.h
index c41c0f91e..3ee1cc46f 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -669,3 +669,4 @@ enum {
669}; 669};
670int elevation_state(void); 670int elevation_state(void);
671void set_interp(int i) FAST_FUNC; 671void set_interp(int i) FAST_FUNC;
672int mingw_shell_execute(SHELLEXECUTEINFO *info);
diff --git a/loginutils/suw32.c b/loginutils/suw32.c
index b3976dcfd..77c038582 100644
--- a/loginutils/suw32.c
+++ b/loginutils/suw32.c
@@ -48,8 +48,8 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
48 char *opt_command = NULL; 48 char *opt_command = NULL;
49 char *opt_shell = NULL; 49 char *opt_shell = NULL;
50 SHELLEXECUTEINFO info; 50 SHELLEXECUTEINFO info;
51 char *bb_path, *cwd, *realcwd, *q, *args; 51 const char *bb_path;
52 DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); 52 char *cwd, *realcwd, *q, *args;
53 53
54 opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell); 54 opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell);
55 argv += optind; 55 argv += optind;
@@ -70,19 +70,17 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
70 } 70 }
71#endif 71#endif
72 72
73 /* ShellExecuteEx() needs backslash as separator in UNC paths. */
74 if (opt_shell) { 73 if (opt_shell) {
75 bb_path = file_is_win32_exe(opt_shell); 74 bb_path = file_is_win32_exe(opt_shell);
76 if (!bb_path) 75 if (!bb_path)
77 bb_error_msg_and_die("%s: Not found", opt_shell); 76 bb_error_msg_and_die("%s: Not found", opt_shell);
78 args = NULL; 77 args = NULL;
79 } else { 78 } else {
80 bb_path = xstrdup(bb_busybox_exec_path); 79 bb_path = bb_busybox_exec_path;
81 args = xstrdup("--busybox ash"); 80 args = xstrdup("--busybox ash");
82 if (!test_mode) 81 if (!test_mode)
83 args = xappendword(args, "-t \"BusyBox ash (Admin)\""); 82 args = xappendword(args, "-t \"BusyBox ash (Admin)\"");
84 } 83 }
85 slash_to_bs(bb_path);
86 84
87 memset(&info, 0, sizeof(SHELLEXECUTEINFO)); 85 memset(&info, 0, sizeof(SHELLEXECUTEINFO));
88 info.cbSize = sizeof(SHELLEXECUTEINFO); 86 info.cbSize = sizeof(SHELLEXECUTEINFO);
@@ -137,12 +135,7 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
137 /* info.lpDirectory = NULL; */ 135 /* info.lpDirectory = NULL; */
138 info.nShow = SW_SHOWNORMAL; 136 info.nShow = SW_SHOWNORMAL;
139 137
140 if (!INIT_PROC_ADDR(shell32.dll, ShellExecuteExA)) { 138 if (!mingw_shell_execute(&info)) {
141 ret = -1;
142 goto end;
143 }
144
145 if (!ShellExecuteExA(&info)) {
146 ret = 1; 139 ret = 1;
147 goto end; 140 goto end;
148 } 141 }
@@ -159,7 +152,8 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
159 } 152 }
160 end: 153 end:
161 if (ENABLE_FEATURE_CLEAN_UP) { 154 if (ENABLE_FEATURE_CLEAN_UP) {
162 free(bb_path); 155 if (bb_path != bb_busybox_exec_path)
156 free((void *)bb_path);
163 free(cwd); 157 free(cwd);
164 free(realcwd); 158 free(realcwd);
165 free(args); 159 free(args);
diff --git a/win32/mingw.c b/win32/mingw.c
index 7a5198ccf..cb1f84f30 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -2538,3 +2538,25 @@ char * FAST_FUNC exe_relative_path(const char *tail)
2538 free(exepath); 2538 free(exepath);
2539 return relpath; 2539 return relpath;
2540} 2540}
2541
2542int mingw_shell_execute(SHELLEXECUTEINFO *info)
2543{
2544 DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *);
2545 char *lpath;
2546 int ret;
2547
2548 if (!INIT_PROC_ADDR(shell32.dll, ShellExecuteExA)) {
2549 errno = ENOSYS;
2550 return FALSE;
2551 }
2552
2553 // ShellExecuteEx() needs backslash as separator in UNC paths.
2554 lpath = xstrdup(info->lpFile);
2555 slash_to_bs(lpath);
2556 info->lpFile = lpath;
2557
2558 ret = ShellExecuteExA(info);
2559
2560 free(lpath);
2561 return ret;
2562}
diff --git a/win32/process.c b/win32/process.c
index fd89707ca..33f45ee42 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -501,6 +501,38 @@ static NORETURN void wait_for_child(HANDLE child, const char *cmd)
501 exit((int)code); 501 exit((int)code);
502} 502}
503 503
504static intptr_t
505shell_execute(const char *path, char *const *argv)
506{
507 SHELLEXECUTEINFO info;
508 char *args;
509
510 memset(&info, 0, sizeof(SHELLEXECUTEINFO));
511 info.cbSize = sizeof(SHELLEXECUTEINFO);
512 info.fMask = SEE_MASK_NOCLOSEPROCESS;
513 /* info.hwnd = NULL; */
514 info.lpVerb = "runas";
515 info.lpFile = path;
516
517 args = NULL;
518 if (*argv++) {
519 while (*argv) {
520 char *q = quote_arg(*argv++);
521 args = xappendword(args, q);
522 free(q);
523 }
524 }
525
526 info.lpParameters = args;
527 /* info.lpDirectory = NULL; */
528 info.nShow = SW_SHOWNORMAL;
529
530 mingw_shell_execute(&info);
531
532 free(args);
533 return info.hProcess ? (intptr_t)info.hProcess : -1;
534}
535
504int 536int
505mingw_execvp(const char *cmd, char *const *argv) 537mingw_execvp(const char *cmd, char *const *argv)
506{ 538{
@@ -514,6 +546,16 @@ int
514mingw_execve(const char *cmd, char *const *argv, char *const *envp) 546mingw_execve(const char *cmd, char *const *argv, char *const *envp)
515{ 547{
516 intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); 548 intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0);
549
550 if (ret == -1 && GetLastError() == ERROR_ELEVATION_REQUIRED) {
551 // Command exists but failed because it wants elevated privileges.
552 // Try again using ShellExecuteEx().
553 SetLastError(0);
554 ret = shell_execute(cmd, argv);
555 if (GetLastError())
556 exit(1);
557 }
558
517 if (ret != -1) 559 if (ret != -1)
518 wait_for_child((HANDLE)ret, cmd); 560 wait_for_child((HANDLE)ret, cmd);
519 return ret; 561 return ret;