reactos/ntoskrnl/se/client.c
George Bișoc 9a2c62b544
[NTOS:SE] Reorganize the security manager component
The current state of Security manager's code is kind of a mess. Mainly, there's code scattered around places where they shouldn't belong and token implementation (token.c) is already of a bloat in itself as it is. The file has over 6k lines and it's subject to grow exponentially with improvements, features, whatever that is.

With that being said, the token implementation code in the kernel will be split accordingly and rest of the code moved to appropriate places. The new layout will look as follows (excluding the already existing files):

- client.c (Client security implementation code)
- objtype.c (Object type list implementation code -- more code related to object types will be put here when I'm going to implement object type access checks in the future)
- subject.c (Subject security context support)

The token implementation in the kernel will be split in 4 distinct files as shown:

- token.c (Base token support routines)
- tokenlif.c (Life management of a token object -- that is Duplication, Creation and Filtering)
- tokencls.c (Token Query/Set Information Classes support)
- tokenadj.c (Token privileges/groups adjusting support)

In addition to that, tidy up the internal header and reorganize it as well.
2022-05-29 20:22:19 +02:00

331 lines
10 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Security client support routines
* COPYRIGHT: Copyright Alex Ionescu <alex@relsoft.net>
*/
/* INCLUDES *******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* PRIVATE FUNCTIONS **********************************************************/
/**
* @brief
* Creates a client security context based upon an access token.
*
* @param[in] Token
* A valid token object.
*
* @param[in] ClientSecurityQos
* The Quality of Service (QoS) of a client security context.
*
* @param[in] ServerIsRemote
* If the client is a remote server (TRUE), the function will retrieve the
* control information of an access token, that is, we're doing delegation
* and that the server isn't local.
*
* @param[in] TokenType
* Type of token.
*
* @param[in] ThreadEffectiveOnly
* If set to TRUE, the client wants that the current thread wants to modify
* (enable or disable) privileges and groups.
*
* @param[in] ImpersonationLevel
* Security impersonation level filled in the QoS context.
*
* @param[out] ClientContext
* The returned security client context.
*
* @return
* Returns STATUS_SUCCESS if client security creation has completed successfully.
* STATUS_INVALID_PARAMETER is returned if one or more of the parameters are bogus.
* STATUS_BAD_IMPERSONATION_LEVEL is returned if the current impersonation level
* within QoS context doesn't meet with the conditions required. A failure
* NTSTATUS code is returned otherwise.
*/
NTSTATUS
NTAPI
SepCreateClientSecurity(
_In_ PACCESS_TOKEN Token,
_In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
_In_ BOOLEAN ServerIsRemote,
_In_ TOKEN_TYPE TokenType,
_In_ BOOLEAN ThreadEffectiveOnly,
_In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
_Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
{
NTSTATUS Status;
PACCESS_TOKEN NewToken;
PAGED_CODE();
/* Check for bogus impersonation level */
if (!VALID_IMPERSONATION_LEVEL(ClientSecurityQos->ImpersonationLevel))
{
/* Fail the call */
return STATUS_INVALID_PARAMETER;
}
/* Check what kind of token this is */
if (TokenType != TokenImpersonation)
{
/* On a primary token, if we do direct access, copy the flag from the QOS */
ClientContext->DirectAccessEffectiveOnly = ClientSecurityQos->EffectiveOnly;
}
else
{
/* This is an impersonation token, is the level ok? */
if (ClientSecurityQos->ImpersonationLevel > ImpersonationLevel)
{
/* Nope, fail */
return STATUS_BAD_IMPERSONATION_LEVEL;
}
/* Is the level too low, or are we doing something other than delegation remotely */
if ((ImpersonationLevel == SecurityAnonymous) ||
(ImpersonationLevel == SecurityIdentification) ||
((ServerIsRemote) && (ImpersonationLevel != SecurityDelegation)))
{
/* Fail the call */
return STATUS_BAD_IMPERSONATION_LEVEL;
}
/* Pick either the thread setting or the QOS setting */
ClientContext->DirectAccessEffectiveOnly =
((ThreadEffectiveOnly) || (ClientSecurityQos->EffectiveOnly)) ? TRUE : FALSE;
}
/* Is this static tracking */
if (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING)
{
/* Do not use direct access and make a copy */
ClientContext->DirectlyAccessClientToken = FALSE;
Status = SeCopyClientToken(Token,
ClientSecurityQos->ImpersonationLevel,
KernelMode,
&NewToken);
if (!NT_SUCCESS(Status))
return Status;
}
else
{
/* Use direct access and check if this is local */
ClientContext->DirectlyAccessClientToken = TRUE;
if (ServerIsRemote)
{
/* We are doing delegation, so make a copy of the control data */
SeGetTokenControlInformation(Token,
&ClientContext->ClientTokenControl);
}
/* Keep the same token */
NewToken = Token;
}
/* Fill out the context and return success */
ClientContext->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
ClientContext->SecurityQos.ImpersonationLevel = ClientSecurityQos->ImpersonationLevel;
ClientContext->SecurityQos.ContextTrackingMode = ClientSecurityQos->ContextTrackingMode;
ClientContext->SecurityQos.EffectiveOnly = ClientSecurityQos->EffectiveOnly;
ClientContext->ServerIsRemote = ServerIsRemote;
ClientContext->ClientToken = NewToken;
return STATUS_SUCCESS;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/**
* @brief
* Creates a client security context.
*
* @param[in] Thread
* Thread object of the client where impersonation has to begin.
*
* @param[in] Qos
* Quality of service to specify what kind of impersonation to be done.
*
* @param[in] RemoteClient
* If set to TRUE, the client that we're going to impersonate is remote.
*
* @param[out] ClientContext
* The returned security client context.
*
* @return
* See SepCreateClientSecurity.
*/
NTSTATUS
NTAPI
SeCreateClientSecurity(
_In_ PETHREAD Thread,
_In_ PSECURITY_QUALITY_OF_SERVICE Qos,
_In_ BOOLEAN RemoteClient,
_Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
{
TOKEN_TYPE TokenType;
BOOLEAN ThreadEffectiveOnly;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
PACCESS_TOKEN Token;
NTSTATUS Status;
PAGED_CODE();
/* Reference the correct token */
Token = PsReferenceEffectiveToken(Thread,
&TokenType,
&ThreadEffectiveOnly,
&ImpersonationLevel);
/* Create client security from it */
Status = SepCreateClientSecurity(Token,
Qos,
RemoteClient,
TokenType,
ThreadEffectiveOnly,
ImpersonationLevel,
ClientContext);
/* Check if we failed or static tracking was used */
if (!(NT_SUCCESS(Status)) || (Qos->ContextTrackingMode == SECURITY_STATIC_TRACKING))
{
/* Dereference our copy since it's not being used */
ObDereferenceObject(Token);
}
/* Return status */
return Status;
}
/**
* @brief
* Creates a client security context based upon the captured security
* subject context.
*
* @param[in] SubjectContext
* The captured subject context where client security is to be created
* from.
*
* @param[in] ClientSecurityQos
* Quality of service to specify what kind of impersonation to be done.
*
* @param[in] ServerIsRemote
* If set to TRUE, the client that we're going to impersonate is remote.
*
* @param[out] ClientContext
* The returned security client context.
*
* @return
* See SepCreateClientSecurity.
*/
NTSTATUS
NTAPI
SeCreateClientSecurityFromSubjectContext(
_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext,
_In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
_In_ BOOLEAN ServerIsRemote,
_Out_ PSECURITY_CLIENT_CONTEXT ClientContext)
{
PACCESS_TOKEN Token;
NTSTATUS Status;
PAGED_CODE();
/* Get the right token and reference it */
Token = SeQuerySubjectContextToken(SubjectContext);
ObReferenceObject(Token);
/* Create the context */
Status = SepCreateClientSecurity(Token,
ClientSecurityQos,
ServerIsRemote,
SubjectContext->ClientToken ?
TokenImpersonation : TokenPrimary,
FALSE,
SubjectContext->ImpersonationLevel,
ClientContext);
/* Check if we failed or static tracking was used */
if (!(NT_SUCCESS(Status)) ||
(ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING))
{
/* Dereference our copy since it's not being used */
ObDereferenceObject(Token);
}
/* Return status */
return Status;
}
/**
* @brief
* Extended function that impersonates a client.
*
* @param[in] ClientContext
* A valid client context.
*
* @param[in] ServerThread
* The thread where impersonation is to be done.
*
* @return
* STATUS_SUCCESS is returned if the calling thread successfully impersonates
* the client. A failure NTSTATUS code is returned otherwise.
*/
NTSTATUS
NTAPI
SeImpersonateClientEx(
_In_ PSECURITY_CLIENT_CONTEXT ClientContext,
_In_opt_ PETHREAD ServerThread)
{
BOOLEAN EffectiveOnly;
PAGED_CODE();
/* Check if direct access is requested */
if (!ClientContext->DirectlyAccessClientToken)
{
/* No, so get the flag from QOS */
EffectiveOnly = ClientContext->SecurityQos.EffectiveOnly;
}
else
{
/* Yes, so see if direct access should be effective only */
EffectiveOnly = ClientContext->DirectAccessEffectiveOnly;
}
/* Use the current thread if one was not passed */
if (!ServerThread) ServerThread = PsGetCurrentThread();
/* Call the lower layer routine */
return PsImpersonateClient(ServerThread,
ClientContext->ClientToken,
TRUE,
EffectiveOnly,
ClientContext->SecurityQos.ImpersonationLevel);
}
/**
* @brief
* Impersonates a client user.
*
* @param[in] ClientContext
* A valid client context.
*
* @param[in] ServerThread
* The thread where impersonation is to be done.
* *
* @return
* Nothing.
*/
VOID
NTAPI
SeImpersonateClient(
_In_ PSECURITY_CLIENT_CONTEXT ClientContext,
_In_opt_ PETHREAD ServerThread)
{
PAGED_CODE();
/* Call the new API */
SeImpersonateClientEx(ClientContext, ServerThread);
}
/* EOF */