Merge branch 'js/mingw-admins-are-special'

"Dubious ownership" checks on Windows has been tightened up.

* js/mingw-admins-are-special:
  test-tool path-utils: support debugging "dubious ownership" issues
  mingw: special-case administrators even more
This commit is contained in:
Junio C Hamano
2025-04-07 14:23:20 -07:00
2 changed files with 47 additions and 11 deletions

View File

@@ -2826,31 +2826,44 @@ static void setup_windows_environment(void)
} }
} }
static PSID get_current_user_sid(void) static void get_current_user_sid(PSID *sid, HANDLE *linked_token)
{ {
HANDLE token; HANDLE token;
DWORD len = 0; DWORD len = 0;
PSID result = NULL; TOKEN_ELEVATION_TYPE elevationType;
DWORD size;
*sid = NULL;
*linked_token = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
return NULL; return;
if (!GetTokenInformation(token, TokenUser, NULL, 0, &len)) { if (!GetTokenInformation(token, TokenUser, NULL, 0, &len)) {
TOKEN_USER *info = xmalloc((size_t)len); TOKEN_USER *info = xmalloc((size_t)len);
if (GetTokenInformation(token, TokenUser, info, len, &len)) { if (GetTokenInformation(token, TokenUser, info, len, &len)) {
len = GetLengthSid(info->User.Sid); len = GetLengthSid(info->User.Sid);
result = xmalloc(len); *sid = xmalloc(len);
if (!CopySid(len, result, info->User.Sid)) { if (!CopySid(len, *sid, info->User.Sid)) {
error(_("failed to copy SID (%ld)"), error(_("failed to copy SID (%ld)"),
GetLastError()); GetLastError());
FREE_AND_NULL(result); FREE_AND_NULL(*sid);
} }
} }
FREE_AND_NULL(info); FREE_AND_NULL(info);
} }
CloseHandle(token);
return result; if (GetTokenInformation(token, TokenElevationType, &elevationType, sizeof(elevationType), &size) &&
elevationType == TokenElevationTypeLimited) {
/*
* The current process is run by a member of the Administrators
* group, but is not running elevated.
*/
if (!GetTokenInformation(token, TokenLinkedToken, linked_token, sizeof(*linked_token), &size))
linked_token = NULL; /* there is no linked token */
}
CloseHandle(token);
} }
static BOOL user_sid_to_user_name(PSID sid, LPSTR *str) static BOOL user_sid_to_user_name(PSID sid, LPSTR *str)
@@ -2931,18 +2944,22 @@ int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
else if (sid && IsValidSid(sid)) { else if (sid && IsValidSid(sid)) {
/* Now, verify that the SID matches the current user's */ /* Now, verify that the SID matches the current user's */
static PSID current_user_sid; static PSID current_user_sid;
static HANDLE linked_token;
BOOL is_member; BOOL is_member;
if (!current_user_sid) if (!current_user_sid)
current_user_sid = get_current_user_sid(); get_current_user_sid(&current_user_sid, &linked_token);
if (current_user_sid && if (current_user_sid &&
IsValidSid(current_user_sid) && IsValidSid(current_user_sid) &&
EqualSid(sid, current_user_sid)) EqualSid(sid, current_user_sid))
result = 1; result = 1;
else if (IsWellKnownSid(sid, WinBuiltinAdministratorsSid) && else if (IsWellKnownSid(sid, WinBuiltinAdministratorsSid) &&
CheckTokenMembership(NULL, sid, &is_member) && ((CheckTokenMembership(NULL, sid, &is_member) &&
is_member) is_member) ||
(linked_token &&
CheckTokenMembership(linked_token, sid, &is_member) &&
is_member)))
/* /*
* If owned by the Administrators group, and the * If owned by the Administrators group, and the
* current user is an administrator, we consider that * current user is an administrator, we consider that

View File

@@ -504,6 +504,25 @@ int cmd__path_utils(int argc, const char **argv)
return !!res; return !!res;
} }
if (argc > 1 && !strcmp(argv[1], "is_path_owned_by_current_user")) {
int res = 0;
for (int i = 2; i < argc; i++) {
struct strbuf buf = STRBUF_INIT;
if (is_path_owned_by_current_user(argv[i], &buf))
printf("'%s' is owned by current SID\n", argv[i]);
else {
printf("'%s' is not owned by current SID: %s\n", argv[i], buf.buf);
res = 1;
}
strbuf_release(&buf);
}
return res;
}
fprintf(stderr, "%s: unknown function name: %s\n", argv[0], fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
argv[1] ? argv[1] : "(there was none)"); argv[1] ? argv[1] : "(there was none)");
return 1; return 1;