Support non-elevated admin user check on Windows

Currently, if a repository is owned by the Administrators group, libgit2
only considers the current user to be the owner if the process is
running with elevated privileges. This change allows non-elevated
processes run by users who are members of the Administrators group to
also be considered the owner of such repositories.

For the corresponding fix in git.exe see
03a4e46d12
This commit is contained in:
Tyrie Vella
2026-01-23 15:24:29 -08:00
committed by Edward Thomson
parent 5e4dcabe75
commit cc477ee897

View File

@@ -1853,12 +1853,16 @@ static PSID *sid_dup(PSID sid)
return dup;
}
static int current_user_sid(PSID *out)
static int current_user_sid(PSID *sid, HANDLE *linked_token)
{
TOKEN_USER *info = NULL;
HANDLE token = NULL;
DWORD len = 0;
int error = -1;
TOKEN_ELEVATION_TYPE elevation_type;
DWORD size;
*linked_token = NULL;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
git_error_set(GIT_ERROR_OS, "could not lookup process information");
@@ -1879,9 +1883,19 @@ static int current_user_sid(PSID *out)
goto done;
}
if ((*out = sid_dup(info->User.Sid)))
if ((*sid = sid_dup(info->User.Sid)))
error = 0;
if (GetTokenInformation(token, TokenElevationType, &elevation_type, sizeof(elevation_type), &size) &&
elevation_type == 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(HANDLE), &size)) {
linked_token = NULL;
}
}
done:
if (token)
CloseHandle(token);
@@ -1926,6 +1940,7 @@ int git_fs_path_owner_is(
git_fs_path_owner_t owner_type)
{
PSID owner_sid = NULL, user_sid = NULL;
static HANDLE linked_token;
BOOL is_admin, admin_owned;
int error;
@@ -1938,7 +1953,7 @@ int git_fs_path_owner_is(
goto done;
if ((owner_type & GIT_FS_PATH_OWNER_CURRENT_USER) != 0) {
if ((error = current_user_sid(&user_sid)) < 0)
if ((error = current_user_sid(&user_sid, &linked_token)) < 0)
goto done;
if (EqualSid(owner_sid, user_sid)) {
@@ -1959,7 +1974,8 @@ int git_fs_path_owner_is(
if (admin_owned &&
(owner_type & GIT_FS_PATH_USER_IS_ADMINISTRATOR) != 0 &&
CheckTokenMembership(NULL, owner_sid, &is_admin) &&
(CheckTokenMembership(NULL, owner_sid, &is_admin) &&
CheckTokenMembership(linked_token, owner_sid, &is_admin)) &&
is_admin) {
*out = true;
goto done;