[PATCH 2/2] advapi32: Implement CreateRestrictedToken.

Vijay Kiran Kamuju infyquest at gmail.com
Sun Apr 14 11:19:20 CDT 2019


From: Michael Müller <michael at fds-team.de>

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=25834
From: Michael Müller <michael at fds-team.de>
Signed-off-by: Vijay Kiran Kamuju <infyquest at 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);
 }
-- 
2.17.0




More information about the wine-devel mailing list