diff options
author | Ron Yorston <rmy@pobox.com> | 2024-08-03 10:00:59 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2024-08-03 10:00:59 +0100 |
commit | fb959dd3f29c2d0655e01147f7b0b9bb2dab4223 (patch) | |
tree | ff5f9a7a40c4fa2656c1ee2b794c877ada2904c4 | |
parent | dab0de7dbe833a44b3e4c20fcd0044f2d878d10d (diff) | |
download | busybox-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.h | 5 | ||||
-rw-r--r-- | loginutils/suw32.c | 10 | ||||
-rw-r--r-- | win32/mingw.c | 44 |
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); | |||
640 | int windows_env(void); | 640 | int windows_env(void); |
641 | void change_critical_error_dialogs(const char *newval) FAST_FUNC; | 641 | void change_critical_error_dialogs(const char *newval) FAST_FUNC; |
642 | char *exe_relative_path(const char *tail); | 642 | char *exe_relative_path(const char *tail); |
643 | enum { | ||
644 | ELEVATED_PRIVILEGE = 1, | ||
645 | ADMIN_ENABLED = 2 | ||
646 | }; | ||
647 | int 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 | */ |
1183 | static int | 1182 | int |
1184 | really_privileged(void) | 1183 | elevation_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 | ||
1203 | int 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 | |||
1216 | int getuid(void) | ||
1217 | { | ||
1218 | return elevation_state() == (ELEVATED_PRIVILEGE | ADMIN_ENABLED) ? | ||
1219 | 0 : DEFAULT_UID; | ||
1220 | } | 1220 | } |
1221 | 1221 | ||
1222 | struct passwd *getpwnam(const char *name) | 1222 | struct passwd *getpwnam(const char *name) |