diff options
author | Ron Yorston <rmy@pobox.com> | 2023-03-13 10:25:56 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2023-03-13 10:25:56 +0000 |
commit | 385decd6bf62c116565ece1e0992ff7a79d48474 (patch) | |
tree | 30065938d54231dcadf54cc3e22206f4985a7180 /win32/mingw.c | |
parent | 6eeb5240974bb304830319e9fa5afbc4d6194fc0 (diff) | |
download | busybox-w32-385decd6bf62c116565ece1e0992ff7a79d48474.tar.gz busybox-w32-385decd6bf62c116565ece1e0992ff7a79d48474.tar.bz2 busybox-w32-385decd6bf62c116565ece1e0992ff7a79d48474.zip |
runuser: new applet
Add a cut down, Windows-specific implementation of `runuser` from
util-linux.
This allows elevated privileges to be dropped when running in an
SSH session. It also works when using `su` or starting busybox-w32
'as administrator'.
There are complications:
- The method used to drop privileges leaves the access token in the
TokenIsElevated state. Detecting this is likely to be fragile.
- The unprivileged shell is started by CreateProcessAsUserA(). In
older versions of Windows this has to be loaded dynamically.
Adds about 900 bytes.
(GitHub issue #240)
Diffstat (limited to 'win32/mingw.c')
-rw-r--r-- | win32/mingw.c | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/win32/mingw.c b/win32/mingw.c index 712728bd6..c7eeea088 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -1109,7 +1109,7 @@ static char *getsysdir(void) | |||
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | #define NAME_LEN 100 | 1111 | #define NAME_LEN 100 |
1112 | static char *get_user_name(void) | 1112 | char *get_user_name(void) |
1113 | { | 1113 | { |
1114 | static char *user_name = NULL; | 1114 | static char *user_name = NULL; |
1115 | char *s; | 1115 | char *s; |
@@ -1136,18 +1136,42 @@ static char *get_user_name(void) | |||
1136 | return user_name; | 1136 | return user_name; |
1137 | } | 1137 | } |
1138 | 1138 | ||
1139 | #if ENABLE_RUNUSER | ||
1140 | /* | ||
1141 | * When runuser drops privileges TokenIsElevated still returns TRUE. | ||
1142 | * Use other means to determine if we're actually unprivileged. | ||
1143 | * This is likely to be fragile. | ||
1144 | */ | ||
1145 | static int | ||
1146 | actually_unprivileged(HANDLE h) | ||
1147 | { | ||
1148 | DWORD restricted = 0; | ||
1149 | DWORD size; | ||
1150 | |||
1151 | if (GetTokenInformation(h, TokenHasRestrictions, &restricted, | ||
1152 | sizeof(restricted), &size)) { | ||
1153 | // The token generated by runuser seems to 'have restrictions'. | ||
1154 | return restricted != 0; | ||
1155 | } | ||
1156 | |||
1157 | return FALSE; | ||
1158 | } | ||
1159 | #else | ||
1160 | # define actually_unprivileged(h) (FALSE) | ||
1161 | #endif | ||
1162 | |||
1139 | int getuid(void) | 1163 | int getuid(void) |
1140 | { | 1164 | { |
1141 | int ret = DEFAULT_UID; | 1165 | int ret = DEFAULT_UID; |
1142 | HANDLE h; | 1166 | HANDLE h; |
1143 | 1167 | ||
1144 | if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h)) { | 1168 | if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &h)) { |
1145 | TOKEN_ELEVATION elevation; | 1169 | TOKEN_ELEVATION elevation = { 0 }; |
1146 | DWORD size = sizeof(TOKEN_ELEVATION); | 1170 | DWORD size; |
1147 | 1171 | ||
1148 | if (GetTokenInformation(h, TokenElevation, &elevation, | 1172 | if (GetTokenInformation(h, TokenElevation, &elevation, |
1149 | sizeof(elevation), &size)) { | 1173 | sizeof(elevation), &size)) { |
1150 | if (elevation.TokenIsElevated) | 1174 | if (elevation.TokenIsElevated && !actually_unprivileged(h)) |
1151 | ret = 0; | 1175 | ret = 0; |
1152 | } | 1176 | } |
1153 | CloseHandle(h); | 1177 | CloseHandle(h); |
@@ -1174,17 +1198,12 @@ struct passwd *getpwuid(uid_t uid) | |||
1174 | { | 1198 | { |
1175 | static struct passwd p; | 1199 | static struct passwd p; |
1176 | 1200 | ||
1177 | if (uid == 0) { | 1201 | if (uid == 0) |
1178 | p.pw_name = (char *)"root"; | 1202 | p.pw_name = (char *)"root"; |
1179 | p.pw_dir = getsysdir(); | 1203 | else if (uid != DEFAULT_UID || (p.pw_name=get_user_name()) == NULL) |
1180 | } | ||
1181 | else if (uid == DEFAULT_UID && (p.pw_name=get_user_name()) != NULL) { | ||
1182 | p.pw_dir = gethomedir(); | ||
1183 | } | ||
1184 | else { | ||
1185 | return NULL; | 1204 | return NULL; |
1186 | } | ||
1187 | 1205 | ||
1206 | p.pw_dir = gethomedir(); | ||
1188 | p.pw_passwd = (char *)""; | 1207 | p.pw_passwd = (char *)""; |
1189 | p.pw_gecos = p.pw_name; | 1208 | p.pw_gecos = p.pw_name; |
1190 | p.pw_shell = NULL; | 1209 | p.pw_shell = NULL; |