https://git.reactos.org/?p=reactos.git;a=commitdiff;h=39003dd408a605b4e66f1…
commit 39003dd408a605b4e66f1b040c7333b52e4d8158
Author: George Bișoc <george.bisoc(a)reactos.org>
AuthorDate: Sat Oct 23 13:55:02 2021 +0200
Commit: George Bișoc <george.bisoc(a)reactos.org>
CommitDate: Sun Nov 7 14:22:20 2021 +0100
[ADVAPI32] Properly implement CreateRestrictedToken
Instead of duplicating the token and masquerade it as if the token was filtered (which
is a big hack), properly implement CreateRestrictedToken function by calling NtFilterToken
which it'll create a restricted token for us.
---
dll/win32/advapi32/wine/security.c | 209 +++++++++++++++++++++++++++++--------
1 file changed, 166 insertions(+), 43 deletions(-)
diff --git a/dll/win32/advapi32/wine/security.c b/dll/win32/advapi32/wine/security.c
index 449cbd354b4..5651a92276a 100644
--- a/dll/win32/advapi32/wine/security.c
+++ b/dll/win32/advapi32/wine/security.c
@@ -481,56 +481,179 @@ SetThreadToken(IN PHANDLE ThreadHandle OPTIONAL,
return TRUE;
}
-/*************************************************************************
- * CreateRestrictedToken [ADVAPI32.@]
+/**
+ * @brief
+ * Creates a filtered token that is a restricted one
+ * of the regular access token. A restricted token
+ * can have disabled SIDs, deleted privileges and/or
+ * restricted SIDs added.
*
- * Create a new more restricted token from an existing token.
+ * @param[in] ExistingTokenHandle
+ * An existing handle to a token where it's to be
+ * filtered.
*
- * PARAMS
- * baseToken [I] Token to base the new restricted token on
- * flags [I] Options
- * nDisableSids [I] Length of disableSids array
- * disableSids [I] Array of SIDs to disable in the new token
- * nDeletePrivs [I] Length of deletePrivs array
- * deletePrivs [I] Array of privileges to delete in the new token
- * nRestrictSids [I] Length of restrictSids array
- * restrictSids [I] Array of SIDs to restrict in the new token
- * newToken [O] Address where the new token is stored
+ * @param[in] Flags
+ * Privilege flag options. This parameter argument influences how the token
+ * is filtered. Such parameter can be 0.
*
- * RETURNS
- * Success: TRUE
- * Failure: FALSE
+ * @param[in] DisableSidCount
+ * The count number of SIDs to disable.
+ *
+ * @param[in] SidsToDisable
+ * An array list with SIDs that have to be disabled in
+ * a token.
+ *
+ * @param[in] DeletePrivilegeCount
+ * The count number of privileges to be deleted.
+ *
+ * @param[in] PrivilegesToDelete
+ * An array list with privileges that have to be deleted
+ * in a token.
+ *
+ * @param[in] RestrictedSidCount
+ * The count number of restricted SIDs.
+ *
+ * @param[in] SidsToRestrict
+ * An array list with restricted SIDs to be added into
+ * the token. If the token already has restricted SIDs
+ * then the array provided by the caller is redundant
+ * information alongside with the existing restricted
+ * SIDs in the token.
+ *
+ * @param[out] NewTokenHandle
+ * The newly received handle to a restricted (filtered)
+ * token. The caller can use such handle to duplicate
+ * a new token.
+ *
+ * @return
+ * Returns TRUE if the function has successfully completed
+ * the operations, otherwise FALSE is returned to indicate
+ * failure. For further details the caller has to invoke
+ * GetLastError() API call for extended information
+ * about the failure.
*/
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;
-
- FIXME("(%p, 0x%x, %u, %p, %u, %p, %u, %p, %p): stub\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 ))
+ _In_ HANDLE ExistingTokenHandle,
+ _In_ DWORD Flags,
+ _In_ DWORD DisableSidCount,
+ _In_reads_opt_(DisableSidCount) PSID_AND_ATTRIBUTES SidsToDisable,
+ _In_ DWORD DeletePrivilegeCount,
+ _In_reads_opt_(DeletePrivilegeCount) PLUID_AND_ATTRIBUTES PrivilegesToDelete,
+ _In_ DWORD RestrictedSidCount,
+ _In_reads_opt_(RestrictedSidCount) PSID_AND_ATTRIBUTES SidsToRestrict,
+ _Outptr_ PHANDLE NewTokenHandle)
+{
+ NTSTATUS Status;
+ BOOL Success;
+ ULONG Index;
+ PTOKEN_GROUPS DisableSids = NULL;
+ PTOKEN_GROUPS RestrictedSids = NULL;
+ PTOKEN_PRIVILEGES DeletePrivileges = NULL;
+
+ /*
+ * Capture the elements we're being given from
+ * the caller and allocate the groups and/or
+ * privileges that have to be filtered in
+ * the token.
+ */
+ if (SidsToDisable != NULL)
+ {
+ DisableSids = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED, DisableSidCount *
sizeof(TOKEN_GROUPS));
+ if (DisableSids == NULL)
+ {
+ /* We failed, bail out */
+ SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES));
return FALSE;
+ }
+
+ /* Copy the counter and loop the elements to copy the rest */
+ DisableSids->GroupCount = DisableSidCount;
+ for (Index = 0; Index < DisableSidCount; Index++)
+ {
+ DisableSids->Groups[Index].Sid = SidsToDisable[Index].Sid;
+ DisableSids->Groups[Index].Attributes = SidsToDisable[Index].Attributes;
+ }
+ }
+
+ if (PrivilegesToDelete != NULL)
+ {
+ DeletePrivileges = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_FIXED, DeletePrivilegeCount
* sizeof(TOKEN_PRIVILEGES));
+ if (DeletePrivileges == NULL)
+ {
+ /* We failed, bail out */
+ SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES));
+ Success = FALSE;
+ goto Cleanup;
+ }
+
+ /* Copy the counter and loop the elements to copy the rest */
+ DeletePrivileges->PrivilegeCount = DeletePrivilegeCount;
+ for (Index = 0; Index < DeletePrivilegeCount; Index++)
+ {
+ DeletePrivileges->Privileges[Index].Luid =
PrivilegesToDelete[Index].Luid;
+ DeletePrivileges->Privileges[Index].Attributes =
PrivilegesToDelete[Index].Attributes;
+ }
}
- return DuplicateTokenEx( baseToken, MAXIMUM_ALLOWED, NULL, level, type, newToken );
+
+ if (SidsToRestrict != NULL)
+ {
+ RestrictedSids = (PTOKEN_GROUPS)LocalAlloc(LMEM_FIXED, RestrictedSidCount *
sizeof(TOKEN_GROUPS));
+ if (RestrictedSids == NULL)
+ {
+ /* We failed, bail out */
+ SetLastError(RtlNtStatusToDosError(STATUS_INSUFFICIENT_RESOURCES));
+ Success = FALSE;
+ goto Cleanup;
+ }
+
+ /* Copy the counter and loop the elements to copy the rest */
+ RestrictedSids->GroupCount = RestrictedSidCount;
+ for (Index = 0; Index < RestrictedSidCount; Index++)
+ {
+ RestrictedSids->Groups[Index].Sid = SidsToRestrict[Index].Sid;
+ RestrictedSids->Groups[Index].Attributes =
SidsToRestrict[Index].Attributes;
+ }
+ }
+
+ /*
+ * Call the NT API to request a token filtering
+ * operation for us.
+ */
+ Status = NtFilterToken(ExistingTokenHandle,
+ Flags,
+ DisableSids,
+ DeletePrivileges,
+ RestrictedSids,
+ NewTokenHandle);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed to do the job, bail out */
+ SetLastError(RtlNtStatusToDosError(Status));
+ Success = FALSE;
+ goto Cleanup;
+ }
+
+ /* If we reach here then we've successfully filtered the token */
+ Success = TRUE;
+
+Cleanup:
+ /* Free whatever we allocated before */
+ if (DisableSids != NULL)
+ {
+ LocalFree(DisableSids);
+ }
+
+ if (DeletePrivileges != NULL)
+ {
+ LocalFree(DeletePrivileges);
+ }
+
+ if (RestrictedSids != NULL)
+ {
+ LocalFree(RestrictedSids);
+ }
+
+ return Success;
}
/******************************************************************************