From: Michael Müller michael@fds-team.de
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=25834 From: Michael Müller michael@fds-team.de Signed-off-by: Vijay Kiran Kamuju infyquest@gmail.com --- dlls/advapi32/security.c | 88 +++++++++++++++++++++++++++++----- dlls/advapi32/tests/security.c | 88 +++++++++++++++++++++++++++++++--- 2 files changed, 157 insertions(+), 19 deletions(-)
diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c index 6891feea2a0..c1c5d05d6a4 100644 --- a/dlls/advapi32/security.c +++ b/dlls/advapi32/security.c @@ -832,6 +832,60 @@ BOOL WINAPI SetThreadToken(PHANDLE thread, HANDLE token) ThreadImpersonationToken, &token, sizeof token )); }
+static BOOL allocate_groups(TOKEN_GROUPS **groups_ret, SID_AND_ATTRIBUTES *sids, DWORD count) +{ + TOKEN_GROUPS *groups; + DWORD i; + + if (!count) + { + *groups_ret = NULL; + return TRUE; + } + + groups = (TOKEN_GROUPS *)heap_alloc(FIELD_OFFSET(TOKEN_GROUPS, Groups) + + count * sizeof(SID_AND_ATTRIBUTES)); + if (!groups) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + groups->GroupCount = count; + for (i = 0; i < count; i++) + groups->Groups[i] = sids[i]; + + *groups_ret = groups; + return TRUE; +} + +static BOOL allocate_privileges(TOKEN_PRIVILEGES **privileges_ret, LUID_AND_ATTRIBUTES *privs, DWORD count) +{ + TOKEN_PRIVILEGES *privileges; + DWORD i; + + if (!count) + { + *privileges_ret = NULL; + return TRUE; + } + + privileges = (TOKEN_PRIVILEGES *)heap_alloc(FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + + count * sizeof(LUID_AND_ATTRIBUTES)); + if (!privileges) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + privileges->PrivilegeCount = count; + for (i = 0; i < count; i++) + privileges->Privileges[i] = privs[i]; + + *privileges_ret = privileges; + return TRUE; +} + /************************************************************************* * CreateRestrictedToken [ADVAPI32.@] * @@ -863,25 +917,33 @@ BOOL WINAPI CreateRestrictedToken( PSID_AND_ATTRIBUTES restrictSids, PHANDLE newToken) { - TOKEN_TYPE type; - SECURITY_IMPERSONATION_LEVEL level = SecurityAnonymous; - DWORD size; + TOKEN_PRIVILEGES *delete_privs = NULL; + TOKEN_GROUPS *disable_groups = NULL; + TOKEN_GROUPS *restrict_sids = NULL; + BOOL ret = FALSE;
- FIXME("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p): stub\n", + TRACE("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p)\n", baseToken, flags, nDisableSids, disableSids, nDeletePrivs, deletePrivs, nRestrictSids, restrictSids, newToken);
- size = sizeof(type); - if (!GetTokenInformation( baseToken, TokenType, &type, size, &size )) return FALSE; - if (type == TokenImpersonation) - { - size = sizeof(level); - if (!GetTokenInformation( baseToken, TokenImpersonationLevel, &level, size, &size )) - return FALSE; - } - return DuplicateTokenEx( baseToken, MAXIMUM_ALLOWED, NULL, level, type, newToken ); + if (!allocate_groups(&disable_groups, disableSids, nDisableSids)) + goto done; + + if (!allocate_privileges(&delete_privs, deletePrivs, nDeletePrivs)) + goto done; + + if (!allocate_groups(&restrict_sids, restrictSids, nRestrictSids)) + goto done; + + ret = set_ntstatus(NtFilterToken(baseToken, flags, disable_groups, delete_privs, restrict_sids, newToken)); + +done: + heap_free(disable_groups); + heap_free(delete_privs); + heap_free(restrict_sids); + return ret; }
/* ############################## diff --git a/dlls/advapi32/tests/security.c b/dlls/advapi32/tests/security.c index d9cae64da8b..62aa556846a 100644 --- a/dlls/advapi32/tests/security.c +++ b/dlls/advapi32/tests/security.c @@ -5120,10 +5120,13 @@ static void test_GetUserNameW(void)
static void test_CreateRestrictedToken(void) { + TOKEN_PRIMARY_GROUP *primary_group, *primary_group2; HANDLE process_token, token, r_token; PTOKEN_GROUPS token_groups, groups2; SID_AND_ATTRIBUTES sattr; SECURITY_IMPERSONATION_LEVEL level; + TOKEN_PRIVILEGES *privs; + PRIVILEGE_SET privset; TOKEN_TYPE type; BOOL is_member; DWORD size; @@ -5139,7 +5142,7 @@ static void test_CreateRestrictedToken(void) ret = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_QUERY, &process_token); ok(ret, "got error %d\n", GetLastError());
- ret = DuplicateTokenEx(process_token, TOKEN_DUPLICATE|TOKEN_ADJUST_GROUPS|TOKEN_QUERY, + ret = DuplicateTokenEx(process_token, TOKEN_DUPLICATE|TOKEN_ADJUST_GROUPS|TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, NULL, SecurityImpersonation, TokenImpersonation, &token); ok(ret, "got error %d\n", GetLastError());
@@ -5170,11 +5173,21 @@ static void test_CreateRestrictedToken(void) ok(ret, "got error %d\n", GetLastError()); ok(is_member, "not a member\n");
- /* disable a SID in new token */ + privset.PrivilegeCount = 1; + privset.Control = PRIVILEGE_SET_ALL_NECESSARY; + ret = LookupPrivilegeValueA(NULL, "SeChangeNotifyPrivilege", &privset.Privilege[0].Luid); + ok(ret, "got error %d\n", GetLastError()); + + is_member = FALSE; + ret = PrivilegeCheck(token, &privset, &is_member); + ok(ret, "got error %d\n", GetLastError()); + ok(is_member, "Expected SeChangeNotifyPrivilege to be enabled\n"); + + /* disable a SID and a privilege in new token */ sattr.Sid = token_groups->Groups[i].Sid; sattr.Attributes = 0; r_token = NULL; - ret = pCreateRestrictedToken(token, 0, 1, &sattr, 0, NULL, 0, NULL, &r_token); + ret = pCreateRestrictedToken(token, 0, 1, &sattr, 1, &privset.Privilege[0], 0, NULL, &r_token); ok(ret, "got error %d\n", GetLastError());
if (ret) @@ -5183,7 +5196,7 @@ static void test_CreateRestrictedToken(void) is_member = TRUE; ret = pCheckTokenMembership(r_token, token_groups->Groups[i].Sid, &is_member); ok(ret, "got error %d\n", GetLastError()); - todo_wine ok(!is_member, "not a member\n"); + ok(!is_member, "not a member\n");
ret = GetTokenInformation(r_token, TokenGroups, NULL, 0, &size); ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d with error %d\n", @@ -5198,9 +5211,9 @@ static void test_CreateRestrictedToken(void) break; }
- todo_wine ok(groups2->Groups[j].Attributes & SE_GROUP_USE_FOR_DENY_ONLY, + ok(groups2->Groups[j].Attributes & SE_GROUP_USE_FOR_DENY_ONLY, "got wrong attributes\n"); - todo_wine ok((groups2->Groups[j].Attributes & SE_GROUP_ENABLED) == 0, + ok((groups2->Groups[j].Attributes & SE_GROUP_ENABLED) == 0, "got wrong attributes\n");
HeapFree(GetProcessHeap(), 0, groups2); @@ -5214,10 +5227,73 @@ static void test_CreateRestrictedToken(void) ret = GetTokenInformation(r_token, TokenImpersonationLevel, &level, size, &size); ok(ret, "got error %d\n", GetLastError()); ok(level == SecurityImpersonation, "got level %u\n", type); + + is_member = TRUE; + ret = PrivilegeCheck(r_token, &privset, &is_member); + ok(ret, "got error %d\n", GetLastError()); + ok(!is_member, "Expected SeChangeNotifyPrivilege not to be enabled\n"); + + ret = GetTokenInformation(r_token, TokenPrivileges, NULL, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d with error %d\n", + ret, GetLastError()); + privs = HeapAlloc(GetProcessHeap(), 0, size); + ret = GetTokenInformation(r_token, TokenPrivileges, privs, size, &size); + ok(ret, "got error %d\n", GetLastError()); + + is_member = FALSE; + for (j = 0; j < privs->PrivilegeCount; j++) + { + if (RtlEqualLuid(&privs->Privileges[j].Luid, &privset.Privilege[0].Luid)) + { + is_member = TRUE; + break; + } + } + + ok(!is_member, "Expected not to find privilege\n"); + HeapFree(GetProcessHeap(), 0, privs); }
HeapFree(GetProcessHeap(), 0, token_groups); CloseHandle(r_token); + + ret = GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d with error %d\n", + ret, GetLastError()); + primary_group = HeapAlloc(GetProcessHeap(), 0, size); + ret = GetTokenInformation(token, TokenPrimaryGroup, primary_group, size, &size); + ok(ret, "got error %d\n", GetLastError()); + + /* disable primary group */ + sattr.Sid = primary_group->PrimaryGroup; + sattr.Attributes = 0; + r_token = NULL; + ret = pCreateRestrictedToken(token, 0, 1, &sattr, 0, NULL, 0, NULL, &r_token); + ok(ret, "got error %d\n", GetLastError()); + + if (ret) + { + is_member = TRUE; + ret = pCheckTokenMembership(r_token, primary_group->PrimaryGroup, &is_member); + ok(ret, "got error %d\n", GetLastError()); + ok(!is_member, "not a member\n"); + + ret = GetTokenInformation(r_token, TokenPrimaryGroup, NULL, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %d with error %d\n", + ret, GetLastError()); + primary_group2 = HeapAlloc(GetProcessHeap(), 0, size); + ret = GetTokenInformation(r_token, TokenPrimaryGroup, primary_group2, size, &size); + ok(ret, "got error %d\n", GetLastError()); + + ok(EqualSid(primary_group2->PrimaryGroup, primary_group->PrimaryGroup), + "Expected same primary group\n"); + + HeapFree(GetProcessHeap(), 0, primary_group2); + } + + HeapFree(GetProcessHeap(), 0, primary_group); + CloseHandle(r_token); + CloseHandle(token); CloseHandle(process_token); }