mirror of
https://github.com/reactos/reactos.git
synced 2024-07-30 08:08:56 +00:00
[RTL]
Implement RtlAcquirePrivilege and RtlReleasePrivilege. Reviewed by Aleksey svn path=/trunk/; revision=58937
This commit is contained in:
parent
6743a1174e
commit
d4c38c2fe4
|
@ -4,6 +4,7 @@
|
||||||
* FILE: lib/rtl/priv.c
|
* FILE: lib/rtl/priv.c
|
||||||
* PURPOSE: Security related functions and Security Objects
|
* PURPOSE: Security related functions and Security Objects
|
||||||
* PROGRAMMER: Eric Kohl
|
* PROGRAMMER: Eric Kohl
|
||||||
|
* Pierre Schweitzer (pierre@reactos.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES *****************************************************************/
|
||||||
|
@ -15,6 +16,27 @@
|
||||||
|
|
||||||
/* FUNCTIONS ***************************************************************/
|
/* FUNCTIONS ***************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
RtlpOpenThreadToken(IN ACCESS_MASK DesiredAccess,
|
||||||
|
OUT PHANDLE TokenHandle)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
Status = ZwOpenThreadToken(NtCurrentThread(), DesiredAccess,
|
||||||
|
TRUE, TokenHandle);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
Status = ZwOpenThreadToken(NtCurrentThread(), DesiredAccess,
|
||||||
|
FALSE, TokenHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
@ -81,7 +103,7 @@ RtlImpersonateSelf(IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
|
@ -90,18 +112,282 @@ RtlAcquirePrivilege(IN PULONG Privilege,
|
||||||
IN ULONG Flags,
|
IN ULONG Flags,
|
||||||
OUT PVOID *ReturnedState)
|
OUT PVOID *ReturnedState)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
NTSTATUS Status;
|
||||||
return STATUS_NOT_IMPLEMENTED;
|
PRTL_ACQUIRE_STATE State;
|
||||||
|
ULONG ReturnLength, i, OldSize;
|
||||||
|
SECURITY_QUALITY_OF_SERVICE Sqos;
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
HANDLE ImpersonationToken = 0, ProcessToken;
|
||||||
|
|
||||||
|
/* Validate flags */
|
||||||
|
if (Flags & ~(RTL_ACQUIRE_PRIVILEGE_PROCESS | RTL_ACQUIRE_PRIVILEGE_IMPERSONATE))
|
||||||
|
{
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If user wants to acquire privileges for the process, we have to impersonate him */
|
||||||
|
if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS)
|
||||||
|
{
|
||||||
|
Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate enough memory to hold: old privileges (fixed buffer size, might not be enough)
|
||||||
|
* new privileges (big enough, after old privileges memory area)
|
||||||
|
*/
|
||||||
|
State = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTL_ACQUIRE_STATE) + sizeof(TOKEN_PRIVILEGES) +
|
||||||
|
NumPriv * sizeof(LUID_AND_ATTRIBUTES));
|
||||||
|
if (!State)
|
||||||
|
{
|
||||||
|
return STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only zero a bit of the memory (will be faster that way) */
|
||||||
|
State->Token = 0;
|
||||||
|
State->OldImpersonationToken = 0;
|
||||||
|
State->Flags = 0;
|
||||||
|
State->OldPrivileges = NULL;
|
||||||
|
|
||||||
|
/* Check whether we have already an active impersonation */
|
||||||
|
if (NtCurrentTeb()->IsImpersonating)
|
||||||
|
{
|
||||||
|
/* Check whether we want to impersonate */
|
||||||
|
if (Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)
|
||||||
|
{
|
||||||
|
/* That's all fine, just get the token.
|
||||||
|
* We need access for: adjust (obvious...) but also
|
||||||
|
* query, to be able to query old privileges
|
||||||
|
*/
|
||||||
|
Status = RtlpOpenThreadToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &State->Token);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, State);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we have to temporary disable active impersonation.
|
||||||
|
* Get previous impersonation token to save it
|
||||||
|
*/
|
||||||
|
Status = RtlpOpenThreadToken(TOKEN_IMPERSONATE, &State->OldImpersonationToken);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, State);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember the fact we had an active impersonation */
|
||||||
|
State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE;
|
||||||
|
|
||||||
|
/* Revert impersonation (ie, give 0 as handle) */
|
||||||
|
Status = ZwSetInformationThread(NtCurrentThread(),
|
||||||
|
ThreadImpersonationToken,
|
||||||
|
&ImpersonationToken,
|
||||||
|
sizeof(HANDLE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have no token yet (which is likely) */
|
||||||
|
if (!State->Token)
|
||||||
|
{
|
||||||
|
/* If we are asked to use process, then do */
|
||||||
|
if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS)
|
||||||
|
{
|
||||||
|
Status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
|
||||||
|
&State->Token);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, we have to impersonate.
|
||||||
|
* Open token for duplication
|
||||||
|
*/
|
||||||
|
Status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken);
|
||||||
|
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ObjectAttributes.SecurityQualityOfService = &Sqos;
|
||||||
|
Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
||||||
|
Sqos.ImpersonationLevel = SecurityDelegation;
|
||||||
|
Sqos.ContextTrackingMode = 1;
|
||||||
|
Sqos.EffectiveOnly = FALSE;
|
||||||
|
|
||||||
|
/* Duplicate */
|
||||||
|
Status = ZwDuplicateToken(ProcessToken,
|
||||||
|
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE,
|
||||||
|
&ObjectAttributes,
|
||||||
|
FALSE,
|
||||||
|
TokenImpersonation,
|
||||||
|
&ImpersonationToken);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ZwClose(ProcessToken);
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign our duplicated token to current thread */
|
||||||
|
Status = ZwSetInformationThread(NtCurrentThread(),
|
||||||
|
ThreadImpersonationToken,
|
||||||
|
&ImpersonationToken,
|
||||||
|
sizeof(HANDLE));
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ZwClose(ImpersonationToken);
|
||||||
|
ZwClose(ProcessToken);
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save said token */
|
||||||
|
State->Token = ImpersonationToken;
|
||||||
|
|
||||||
|
ZwClose(ProcessToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Properly set the privileges pointers:
|
||||||
|
* OldPrivileges points to the static memory in struct (= OldPrivBuffer)
|
||||||
|
* NewPrivileges points to the dynamic memory after OldPrivBuffer
|
||||||
|
* There's NO overflow risks (OldPrivileges is always used with its size)
|
||||||
|
*/
|
||||||
|
State->OldPrivileges = (PTOKEN_PRIVILEGES)State->OldPrivBuffer;
|
||||||
|
State->NewPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer + 1024);
|
||||||
|
|
||||||
|
/* Assign all the privileges to be acquired */
|
||||||
|
State->NewPrivileges->PrivilegeCount = NumPriv;
|
||||||
|
for (i = 0; i < NumPriv; ++i)
|
||||||
|
{
|
||||||
|
State->NewPrivileges->Privileges[i].Luid.LowPart = Privilege[i];
|
||||||
|
State->NewPrivileges->Privileges[i].Luid.HighPart = 0;
|
||||||
|
State->NewPrivileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Start privileges adjustements */
|
||||||
|
OldSize = sizeof(State->OldPrivBuffer);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ReturnLength = sizeof(State->OldPrivBuffer);
|
||||||
|
Status = ZwAdjustPrivilegesToken(State->Token, FALSE, State->NewPrivileges,
|
||||||
|
OldSize, State->OldPrivileges, &ReturnLength);
|
||||||
|
/* This is returned when OldPrivileges buffer is too small */
|
||||||
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
||||||
|
{
|
||||||
|
/* Try to allocate a new one, big enough to hold data */
|
||||||
|
State->OldPrivileges = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength);
|
||||||
|
if (State->OldPrivileges)
|
||||||
|
{
|
||||||
|
OldSize = ReturnLength;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If we failed, properly set status: we failed because of the lack of memory */
|
||||||
|
Status = STATUS_NO_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we failed to assign at least one privilege */
|
||||||
|
if (Status == STATUS_NOT_ALL_ASSIGNED)
|
||||||
|
{
|
||||||
|
/* If there was actually only one privilege to acquire, use more accurate status */
|
||||||
|
if (NumPriv == 1)
|
||||||
|
{
|
||||||
|
Status = STATUS_PRIVILEGE_NOT_HELD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fail if needed, otherwise return our state to caller */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*ReturnedState = State;
|
||||||
|
}
|
||||||
|
} while (FALSE);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
/* If we allocated our own buffer for old privileges, release it */
|
||||||
|
if (State->OldPrivileges && (PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges)
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do we have to restore previously active impersonation? */
|
||||||
|
if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)
|
||||||
|
{
|
||||||
|
Status = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
|
||||||
|
&State->OldImpersonationToken, sizeof(HANDLE));
|
||||||
|
/* If this ever happens, we're in a really bad situation... */
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlRaiseStatus(Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release token */
|
||||||
|
if (State->Token)
|
||||||
|
{
|
||||||
|
ZwClose(State->Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And free our state buffer */
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, State);
|
||||||
|
|
||||||
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
RtlReleasePrivilege(IN PVOID ReturnedState)
|
RtlReleasePrivilege(IN PVOID ReturnedState)
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
NTSTATUS Status;
|
||||||
|
PRTL_ACQUIRE_STATE State = (PRTL_ACQUIRE_STATE)ReturnedState;
|
||||||
|
|
||||||
|
/* If we had an active impersonation before we acquired privileges */
|
||||||
|
if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)
|
||||||
|
{
|
||||||
|
/* Restore it for the current thread */
|
||||||
|
Status = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
|
||||||
|
&State->OldImpersonationToken, sizeof(HANDLE));
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
RtlRaiseStatus(Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And close the token if needed */
|
||||||
|
if (State->OldImpersonationToken)
|
||||||
|
ZwClose(State->OldImpersonationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Otherwise, restore old state */
|
||||||
|
ZwAdjustPrivilegesToken(State->Token, FALSE,
|
||||||
|
State->OldPrivileges, 0, NULL, NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we used a different buffer for old privileges, just free it */
|
||||||
|
if ((PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges)
|
||||||
|
{
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release token and free state */
|
||||||
|
ZwClose(State->Token);
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(), 0, State);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue