aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-08-03 10:00:59 +0100
committerRon Yorston <rmy@pobox.com>2024-08-03 10:00:59 +0100
commitfb959dd3f29c2d0655e01147f7b0b9bb2dab4223 (patch)
treeff5f9a7a40c4fa2656c1ee2b794c877ada2904c4
parentdab0de7dbe833a44b3e4c20fcd0044f2d878d10d (diff)
downloadbusybox-w32-fb959dd3f29c2d0655e01147f7b0b9bb2dab4223.tar.gz
busybox-w32-fb959dd3f29c2d0655e01147f7b0b9bb2dab4223.tar.bz2
busybox-w32-fb959dd3f29c2d0655e01147f7b0b9bb2dab4223.zip
su: detect inability to raise privilege
When privilege has been dropped by the 'drop' applet, the 'su' applet is unable to raise it again because ShellExecuteEx() thinks it unnecessary. Detect this situation, report an error and return exit code 2. Costs 72-112 bytes. (GitHub issue #437)
-rw-r--r--include/mingw.h5
-rw-r--r--loginutils/suw32.c10
-rw-r--r--win32/mingw.c44
3 files changed, 37 insertions, 22 deletions
diff --git a/include/mingw.h b/include/mingw.h
index c4c2e199a..7a07de619 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -640,3 +640,8 @@ char *xappendword(const char *str, const char *word);
640int windows_env(void); 640int windows_env(void);
641void change_critical_error_dialogs(const char *newval) FAST_FUNC; 641void change_critical_error_dialogs(const char *newval) FAST_FUNC;
642char *exe_relative_path(const char *tail); 642char *exe_relative_path(const char *tail);
643enum {
644 ELEVATED_PRIVILEGE = 1,
645 ADMIN_ENABLED = 2
646};
647int elevation_state(void);
diff --git a/loginutils/suw32.c b/loginutils/suw32.c
index edf42177b..a0afe5bb7 100644
--- a/loginutils/suw32.c
+++ b/loginutils/suw32.c
@@ -44,6 +44,16 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
44 char *bb_path, *cwd, *realcwd, *q, *args; 44 char *bb_path, *cwd, *realcwd, *q, *args;
45 DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); 45 DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *);
46 46
47#if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP
48 // If privilege has been dropped (ELEVATED_PRIVILEGE but not
49 // ADMIN_ENABLED) ShellExecuteEx() thinks we already have elevated
50 // privilege and doesn't raise privilege. In that case, give up.
51 if (elevation_state() == ELEVATED_PRIVILEGE) {
52 xfunc_error_retval = 2;
53 bb_error_msg_and_die("unable to restore privilege");
54 }
55#endif
56
47 opt = getopt32(argv, "c:NW", &opt_command); 57 opt = getopt32(argv, "c:NW", &opt_command);
48 argv += optind; 58 argv += optind;
49 if (argv[0]) { 59 if (argv[0]) {
diff --git a/win32/mingw.c b/win32/mingw.c
index f2b025e43..97bc95d8e 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -1174,49 +1174,49 @@ char *get_user_name(void)
1174 return user_name; 1174 return user_name;
1175} 1175}
1176 1176
1177#if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP
1178/* 1177/*
1179 * When 'drop' drops privileges TokenIsElevated is still TRUE. 1178 * When 'drop' drops privileges TokenIsElevated is still TRUE.
1180 * Find out if we're really privileged by checking if the group 1179 * Find out if we're really privileged by checking if the group
1181 * BUILTIN\Administrators is enabled. 1180 * BUILTIN\Administrators is enabled.
1182 */ 1181 */
1183static int 1182int
1184really_privileged(void) 1183elevation_state(void)
1185{ 1184{
1186 BOOL admin_enabled; 1185 int elevated = FALSE;
1186 int enabled = TRUE;
1187 HANDLE h;
1188#if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP
1189 BOOL admin_enabled = TRUE;
1187 unsigned char admin[16] = { 1190 unsigned char admin[16] = {
1188 0x01, 0x02, 0x00, 0x00, 1191 0x01, 0x02, 0x00, 0x00,
1189 0x00, 0x00, 0x00, 0x05, 1192 0x00, 0x00, 0x00, 0x05,
1190 0x20, 0x00, 0x00, 0x00, 1193 0x20, 0x00, 0x00, 0x00,
1191 0x20, 0x02, 0x00, 0x00 1194 0x20, 0x02, 0x00, 0x00
1192 }; 1195 };
1193
1194 if (CheckTokenMembership(NULL, (PSID)admin, &admin_enabled))
1195 return admin_enabled;
1196
1197 return TRUE;
1198}
1199#else
1200# define really_privileged() (TRUE)
1201#endif 1196#endif
1202 1197
1203int getuid(void)
1204{
1205 int ret = DEFAULT_UID;
1206 HANDLE h;
1207
1208 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h)) { 1198 if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h)) {
1209 TOKEN_ELEVATION elevation = { 0 }; 1199 TOKEN_ELEVATION elevation = { 0 };
1210 DWORD size; 1200 DWORD size;
1211 1201
1212 if (GetTokenInformation(h, TokenElevation, &elevation, 1202 if (GetTokenInformation(h, TokenElevation, &elevation,
1213 sizeof(elevation), &size)) { 1203 sizeof(elevation), &size))
1214 if (elevation.TokenIsElevated && really_privileged()) 1204 elevated = elevation.TokenIsElevated != 0;
1215 ret = 0;
1216 }
1217 CloseHandle(h); 1205 CloseHandle(h);
1218 } 1206 }
1219 return ret; 1207
1208#if ENABLE_DROP || ENABLE_CDROP || ENABLE_PDROP
1209 if (CheckTokenMembership(NULL, (PSID)admin, &admin_enabled))
1210 enabled = admin_enabled != 0;
1211#endif
1212
1213 return elevated | (enabled << 1);
1214}
1215
1216int getuid(void)
1217{
1218 return elevation_state() == (ELEVATED_PRIVILEGE | ADMIN_ENABLED) ?
1219 0 : DEFAULT_UID;
1220} 1220}
1221 1221
1222struct passwd *getpwnam(const char *name) 1222struct passwd *getpwnam(const char *name)