From 3c1f5962482e7acf531f57f49d923d9c4e5278b1 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: [PATCH] advapi32: Implement CreateRestrictedToken.

---
 dlls/kernelbase/security.c | 103 ++++++++++++++++++++++++++++++-------
 1 file changed, 84 insertions(+), 19 deletions(-)

diff --git a/dlls/kernelbase/security.c b/dlls/kernelbase/security.c
index 2e75e81ed77..97f6ee6a2fd 100644
--- a/dlls/kernelbase/security.c
+++ b/dlls/kernelbase/security.c
@@ -592,31 +592,96 @@ exit:
     return ret;
 }
 
+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    (kernelbase.@)
  */
-BOOL WINAPI CreateRestrictedToken( HANDLE token, DWORD flags,
-                                   DWORD disable_count, PSID_AND_ATTRIBUTES disable_sids,
-                                   DWORD delete_count, PLUID_AND_ATTRIBUTES delete_privs,
-                                   DWORD restrict_count, PSID_AND_ATTRIBUTES restrict_sids, PHANDLE ret )
+BOOL WINAPI CreateRestrictedToken( HANDLE baseToken, DWORD flags,
+                                   DWORD nDisableSids, PSID_AND_ATTRIBUTES disableSids,
+                                   DWORD nDeletePrivs, PLUID_AND_ATTRIBUTES deletePrivs,
+                                   DWORD nRestrictSids, 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",
-          token, flags, disable_count, disable_sids, delete_count, delete_privs,
-          restrict_count, restrict_sids, ret );
+    TRACE("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p)\n",
+          baseToken, flags, nDisableSids, disableSids,
+          nDeletePrivs, deletePrivs,
+          nRestrictSids, restrictSids,
+          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;
 
-    size = sizeof(type);
-    if (!GetTokenInformation( token, TokenType, &type, size, &size )) return FALSE;
-    if (type == TokenImpersonation)
-    {
-        size = sizeof(level);
-        if (!GetTokenInformation( token, TokenImpersonationLevel, &level, size, &size ))
-            return FALSE;
-    }
-    return DuplicateTokenEx( token, MAXIMUM_ALLOWED, NULL, level, type, ret );
 }
 
 /******************************************************************************
-- 
2.20.1

