mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
272 lines
9.9 KiB
Diff
272 lines
9.9 KiB
Diff
From 2a1064c5f90beac2bd709ab5d1c454c90a16189b Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
|
Date: Fri, 4 Aug 2017 02:51:57 +0200
|
|
Subject: advapi32: Implement CreateRestrictedToken.
|
|
|
|
---
|
|
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 82bb6689d43..c531e45c9a0 100644
|
|
--- a/dlls/advapi32/security.c
|
|
+++ b/dlls/advapi32/security.c
|
|
@@ -840,6 +840,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.@]
|
|
*
|
|
@@ -871,25 +925,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 a1ecc409b73..0fd41fe82fa 100644
|
|
--- a/dlls/advapi32/tests/security.c
|
|
+++ b/dlls/advapi32/tests/security.c
|
|
@@ -5292,10 +5292,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;
|
|
@@ -5311,7 +5314,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());
|
|
|
|
@@ -5342,11 +5345,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)
|
|
@@ -5355,7 +5368,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",
|
|
@@ -5370,9 +5383,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);
|
|
@@ -5386,10 +5399,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);
|
|
}
|
|
--
|
|
2.13.1
|
|
|