From ebdf8b17006a306cfe457f6975cb0451d639b551 Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Sun, 25 Oct 2015 14:33:27 +0000 Subject: [PATCH] [NTOSKRNL][LSASRV] - Add the SRM code from Timos kernel-fun branch. - Move its lsasrv code to a separate file. Thank you very much, Timo! svn path=/trunk/; revision=69697 --- reactos/dll/win32/lsasrv/CMakeLists.txt | 1 + reactos/dll/win32/lsasrv/lsasrv.c | 10 + reactos/dll/win32/lsasrv/lsasrv.h | 4 + reactos/dll/win32/lsasrv/srm.c | 264 ++++++++++ reactos/ntoskrnl/ex/init.c | 3 + reactos/ntoskrnl/include/internal/se.h | 4 + reactos/ntoskrnl/ntos.cmake | 1 + reactos/ntoskrnl/se/srm.c | 623 ++++++++++++++++++++++++ 8 files changed, 910 insertions(+) create mode 100644 reactos/dll/win32/lsasrv/srm.c create mode 100644 reactos/ntoskrnl/se/srm.c diff --git a/reactos/dll/win32/lsasrv/CMakeLists.txt b/reactos/dll/win32/lsasrv/CMakeLists.txt index e1b250a53f0..6bde681905c 100644 --- a/reactos/dll/win32/lsasrv/CMakeLists.txt +++ b/reactos/dll/win32/lsasrv/CMakeLists.txt @@ -22,6 +22,7 @@ list(APPEND SOURCE registry.c security.c session.c + srm.c utils.c lsasrv.h ${CMAKE_CURRENT_BINARY_DIR}/dssetup_s.c diff --git a/reactos/dll/win32/lsasrv/lsasrv.c b/reactos/dll/win32/lsasrv/lsasrv.c index 045a745f1b9..a887ab18846 100644 --- a/reactos/dll/win32/lsasrv/lsasrv.c +++ b/reactos/dll/win32/lsasrv/lsasrv.c @@ -6,6 +6,8 @@ * COPYRIGHT: Copyright 2006-2009 Eric Kohl */ +/* INCLUDES ****************************************************************/ + #include "lsasrv.h" /* FUNCTIONS ***************************************************************/ @@ -140,6 +142,14 @@ LsapInitLsa(VOID) /* Initialize the well known SIDs */ LsapInitSids(); + /* Initialize the SRM server */ + Status = LsapRmInitializeServer(); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmInitializeServer() failed (Status 0x%08lx)\n", Status); + return Status; + } + /* Initialize the LSA database */ LsapInitDatabase(); diff --git a/reactos/dll/win32/lsasrv/lsasrv.h b/reactos/dll/win32/lsasrv/lsasrv.h index 1fefc9b4e77..0a1ad3171df 100644 --- a/reactos/dll/win32/lsasrv/lsasrv.h +++ b/reactos/dll/win32/lsasrv/lsasrv.h @@ -421,6 +421,10 @@ LsapEnumLogonSessions(IN OUT PLSA_API_MSG RequestMsg); NTSTATUS LsapGetLogonSessionData(IN OUT PLSA_API_MSG RequestMsg); +/* srm.c */ +NTSTATUS +LsapRmInitializeServer(VOID); + /* utils.c */ INT LsapLoadString(HINSTANCE hInstance, diff --git a/reactos/dll/win32/lsasrv/srm.c b/reactos/dll/win32/lsasrv/srm.c new file mode 100644 index 00000000000..9eb9b23118d --- /dev/null +++ b/reactos/dll/win32/lsasrv/srm.c @@ -0,0 +1,264 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: Local Security Authority Server DLL + * FILE: dll/win32/lsasrv/srm.c + * PURPOSE: Security Reference Monitor Server + * + * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES ****************************************************************/ + +#include "lsasrv.h" +#include + +typedef struct _LSAP_RM_API_MESSAGE +{ + PORT_MESSAGE Header; + ULONG ApiNumber; + union + { + UCHAR Fill[PORT_MAXIMUM_MESSAGE_LENGTH - sizeof(PORT_MESSAGE)]; + struct + { + ULONG Info1; + } WriteLog; + + } u; +} LSAP_RM_API_MESSAGE, *PLSAP_RM_API_MESSAGE; + +enum _LSAP_API_NUMBER +{ + LsapAdtWriteLogApi = 1, + LsapComponentTestApi, + LsapAsyncApi +}; + +/* GLOBALS *****************************************************************/ + +HANDLE SeLsaCommandPort; +HANDLE SeRmCommandPort; + +/* FUNCTIONS ***************************************************************/ + +static +VOID +LsapComponentTest( + PLSAP_RM_API_MESSAGE Message) +{ + ERR("Security: LSA Component Test Command Received\n"); +} + +static +VOID +LsapAdtWriteLog( + PLSAP_RM_API_MESSAGE Message) +{ + ERR("LsapAdtWriteLog\n"); +} + +static +VOID +LsapAsync( + PLSAP_RM_API_MESSAGE Message) +{ + ERR("LsapAsync\n"); +} + +static +DWORD +WINAPI +LsapRmServerThread( + PVOID StartContext) +{ + LSAP_RM_API_MESSAGE Message; + PPORT_MESSAGE ReplyMessage; + REMOTE_PORT_VIEW RemotePortView; + HANDLE MessagePort, DummyPortHandle; + NTSTATUS Status; + + /* Initialize the port message */ + Message.Header.u1.s1.TotalLength = sizeof(Message); + Message.Header.u1.s1.DataLength = 0; + + /* Listen on the LSA command port */ + Status = NtListenPort(SeLsaCommandPort, &Message.Header); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmServerThread - Port Listen failed 0x%lx\n", Status); + return Status; + } + + /* Setup the Port View Structure */ + RemotePortView.Length = sizeof(REMOTE_PORT_VIEW); + RemotePortView.ViewSize = 0; + RemotePortView.ViewBase = NULL; + + /* Accept the connection */ + Status = NtAcceptConnectPort(&MessagePort, + 0, + &Message.Header, + TRUE, + NULL, + &RemotePortView); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmServerThread - Port Accept Connect failed 0x%lx\n", Status); + return Status; + } + + /* Complete the connection */ + Status = NtCompleteConnectPort(MessagePort); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmServerThread - Port Complete Connect failed 0x%lx\n", Status); + return Status; + } + + /* No reply yet */ + ReplyMessage = NULL; + + /* Start looping */ + while (TRUE) + { + /* Wait for a message */ + Status = NtReplyWaitReceivePort(MessagePort, + NULL, + ReplyMessage, + &Message.Header); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmServerThread - Failed to get message: 0x%lx", Status); + ReplyMessage = NULL; + continue; + } + + /* Check if this is a connection request */ + if (Message.Header.u2.s2.Type == LPC_CONNECTION_REQUEST) + { + /* Reject connection request */ + NtAcceptConnectPort(&DummyPortHandle, + NULL, + &Message.Header, + FALSE, + NULL, + NULL); + + /* Start over */ + ReplyMessage = NULL; + continue; + } + + /* Check if this is an actual request */ + if (Message.Header.u2.s2.Type == LPC_REQUEST) + { + ReplyMessage = &Message.Header; + + switch (Message.ApiNumber) + { + case LsapAdtWriteLogApi: + LsapAdtWriteLog(&Message); + break; + + case LsapAsyncApi: + LsapAsync(&Message); + break; + + case LsapComponentTestApi: + LsapComponentTest(&Message); + break; + + default: + ERR("LsapRmServerThread - invalid API number: 0x%lx\n", + Message.ApiNumber); + ReplyMessage = NULL; + } + + continue; + } + + ERR("LsapRmServerThread - unexpected message type: 0x%lx\n", + Message.Header.u2.s2.Type); + + /* Start over */ + ReplyMessage = NULL; + } +} + +NTSTATUS +LsapRmInitializeServer(VOID) +{ + UNICODE_STRING Name; + OBJECT_ATTRIBUTES ObjectAttributes; + SECURITY_QUALITY_OF_SERVICE SecurityQos; + HANDLE InitEvent; + HANDLE ThreadHandle; + DWORD ThreadId; + NTSTATUS Status; + + /* Create the LSA command port */ + RtlInitUnicodeString(&Name, L"\\SeLsaCommandPort"); + InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); + Status = NtCreatePort(&SeLsaCommandPort, + &ObjectAttributes, + 0, + PORT_MAXIMUM_MESSAGE_LENGTH, + 2 * PAGE_SIZE); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmInitializeServer - Port Create failed 0x%lx\n", Status); + return Status; + } + + /* Open the LSA init event */ + RtlInitUnicodeString(&Name, L"\\SeLsaInitEvent"); + InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); + Status = NtOpenEvent(&InitEvent, 2, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmInitializeServer - Lsa Init Event Open failed 0x%lx\n", Status); + return Status; + } + + /* Signal the kernel, that we are ready */ + Status = NtSetEvent(InitEvent, 0); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmInitializeServer - Set Init Event failed 0x%lx\n", Status); + return Status; + } + + /* Setup the QoS structure */ + SecurityQos.ImpersonationLevel = SecurityIdentification; + SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + SecurityQos.EffectiveOnly = TRUE; + + /* Connect to the kernel server */ + RtlInitUnicodeString(&Name, L"\\SeRmCommandPort"); + Status = NtConnectPort(&SeRmCommandPort, + &Name, + &SecurityQos, + NULL, + NULL, + NULL, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + ERR("LsapRmInitializeServer - Connect to Rm Command Port failed 0x%lx\n", Status); + return Status; + } + + /* Create the server thread */ + ThreadHandle = CreateThread(NULL, 0, LsapRmServerThread, NULL, 0, &ThreadId); + if (ThreadHandle == NULL) + { + ERR("LsapRmInitializeServer - Create Thread failed 0x%lx\n", Status); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Close the server thread handle */ + CloseHandle(ThreadHandle); + + return STATUS_SUCCESS; +} diff --git a/reactos/ntoskrnl/ex/init.c b/reactos/ntoskrnl/ex/init.c index 5db7a968cc7..ed6e39efffb 100644 --- a/reactos/ntoskrnl/ex/init.c +++ b/reactos/ntoskrnl/ex/init.c @@ -1950,6 +1950,9 @@ Phase1InitializationDiscard(IN PVOID Context) MmFreeLoaderBlock(LoaderBlock); LoaderBlock = Context = NULL; + /* Initialize the SRM in phase 1 */ + if (!SeRmInitPhase1()) KeBugCheck(PROCESS1_INITIALIZATION_FAILED); + /* Update progress bar */ InbvUpdateProgressBar(100); diff --git a/reactos/ntoskrnl/include/internal/se.h b/reactos/ntoskrnl/include/internal/se.h index 1b737be4159..d71d16de90b 100644 --- a/reactos/ntoskrnl/include/internal/se.h +++ b/reactos/ntoskrnl/include/internal/se.h @@ -267,6 +267,10 @@ BOOLEAN NTAPI SepInitSDs(VOID); +BOOLEAN +NTAPI +SeRmInitPhase1(VOID); + VOID NTAPI SeDeassignPrimaryToken(struct _EPROCESS *Process); diff --git a/reactos/ntoskrnl/ntos.cmake b/reactos/ntoskrnl/ntos.cmake index d6dc35e4364..ebde0b186fe 100644 --- a/reactos/ntoskrnl/ntos.cmake +++ b/reactos/ntoskrnl/ntos.cmake @@ -266,6 +266,7 @@ list(APPEND SOURCE ${REACTOS_SOURCE_DIR}/ntoskrnl/se/sd.c ${REACTOS_SOURCE_DIR}/ntoskrnl/se/semgr.c ${REACTOS_SOURCE_DIR}/ntoskrnl/se/sid.c + ${REACTOS_SOURCE_DIR}/ntoskrnl/se/srm.c ${REACTOS_SOURCE_DIR}/ntoskrnl/se/token.c ${REACTOS_SOURCE_DIR}/ntoskrnl/vf/driver.c ${REACTOS_SOURCE_DIR}/ntoskrnl/wmi/guidobj.c diff --git a/reactos/ntoskrnl/se/srm.c b/reactos/ntoskrnl/se/srm.c new file mode 100644 index 00000000000..bd680ba2306 --- /dev/null +++ b/reactos/ntoskrnl/se/srm.c @@ -0,0 +1,623 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/se/srm.c + * PURPOSE: Security Reference Monitor Server + * + * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES *******************************************************************/ + +#include +#define NDEBUG +#include + +extern LUID SeSystemAuthenticationId; +extern LUID SeAnonymousAuthenticationId; + +/* PRIVATE DEFINITIONS ********************************************************/ + +#define SEP_LOGON_SESSION_TAG 'sLeS' + +enum _RM_API_NUMBER +{ + RmAuditSetCommand = 1, + RmCreateLogonSession = 2, + RmDeleteLogonSession = 3 +}; + +typedef struct _SEP_RM_API_MESSAGE +{ + PORT_MESSAGE Header; + ULONG ApiNumber; + union + { + UCHAR Fill[PORT_MAXIMUM_MESSAGE_LENGTH - sizeof(PORT_MESSAGE)]; + NTSTATUS ResultStatus; + struct + { + BOOLEAN Enabled; + ULONG Flags[9]; + } SetAuditEvent; + LUID LogonLuid; + } u; +} SEP_RM_API_MESSAGE, *PSEP_RM_API_MESSAGE; + +typedef struct _SEP_LOGON_SESSION_REFERENCES +{ + struct _SEP_LOGON_SESSION_REFERENCES *Next; + LUID LogonId; + ULONG ReferenceCount; + ULONG Flags; + PDEVICE_MAP pDeviceMap; + LIST_ENTRY TokenList; +} SEP_LOGON_SESSION_REFERENCES, *PSEP_LOGON_SESSION_REFERENCES; + +VOID +NTAPI +SepRmCommandServerThread( + PVOID StartContext); + +static +NTSTATUS +SepRmCreateLogonSession( + PLUID LogonLuid); + + +/* GLOBALS ********************************************************************/ + +HANDLE SeRmCommandPort; +HANDLE SeLsaInitEvent; + +PVOID SepCommandPortViewBase; +PVOID SepCommandPortViewRemoteBase; +ULONG_PTR SepCommandPortViewBaseOffset; + +static HANDLE SepRmCommandMessagePort; + +BOOLEAN SepAdtAuditingEnabled; +ULONG SepAdtMinListLength = 0x2000; +ULONG SepAdtMaxListLength = 0x3000; + +#define POLICY_AUDIT_EVENT_TYPE_COUNT 9 // (AuditCategoryAccountLogon - AuditCategorySystem + 1) +UCHAR SeAuditingState[POLICY_AUDIT_EVENT_TYPE_COUNT]; + +KGUARDED_MUTEX SepRmDbLock; +PSEP_LOGON_SESSION_REFERENCES SepLogonSessions; + + +/* PRIVATE FUNCTIONS **********************************************************/ + +NTSTATUS +NTAPI +SepRegQueryHelper( + PCWSTR KeyName, + PCWSTR ValueName, + ULONG ValueType, + ULONG DataLength, + PVOID ValueData) +{ + UNICODE_STRING ValueNameString; + UNICODE_STRING KeyNameString; + ULONG ResultLength; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE KeyHandle = NULL; + struct + { + KEY_VALUE_PARTIAL_INFORMATION Partial; + UCHAR Buffer[64]; + } KeyValueInformation; + NTSTATUS Status, CloseStatus; + PAGED_CODE(); + + RtlInitUnicodeString(&KeyNameString, KeyName); + InitializeObjectAttributes(&ObjectAttributes, + &KeyNameString, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + RtlInitUnicodeString(&ValueNameString, ValueName); + Status = ZwQueryValueKey(KeyHandle, + &ValueNameString, + KeyValuePartialInformation, + &KeyValueInformation.Partial, + sizeof(KeyValueInformation), + &ResultLength); + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } + + if ((KeyValueInformation.Partial.Type != ValueType) || + (KeyValueInformation.Partial.DataLength != DataLength)) + { + Status = STATUS_OBJECT_TYPE_MISMATCH; + goto Cleanup; + } + + + if (ValueType == REG_BINARY) + { + RtlCopyMemory(ValueData, KeyValueInformation.Partial.Data, DataLength); + } + else if (ValueType == REG_DWORD) + { + *(PULONG)ValueData = *(PULONG)KeyValueInformation.Partial.Data; + } + else + { + Status = STATUS_INVALID_PARAMETER; + } + +Cleanup: + CloseStatus = ZwClose(KeyHandle); + ASSERT(NT_SUCCESS( CloseStatus )); + + return Status; +} + + +BOOLEAN +NTAPI +SeRmInitPhase1(VOID) +{ + UNICODE_STRING Name; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE ThreadHandle; + NTSTATUS Status; + + // Windows does this in SeRmInitPhase0, but it should not matter + KeInitializeGuardedMutex(&SepRmDbLock); + + Status = SepRmCreateLogonSession(&SeSystemAuthenticationId); + if (!NT_VERIFY(NT_SUCCESS(Status))) + { + return FALSE; + } + + Status = SepRmCreateLogonSession(&SeAnonymousAuthenticationId); + if (!NT_VERIFY(NT_SUCCESS(Status))) + { + return FALSE; + } + + /* Create the SeRm command port */ + RtlInitUnicodeString(&Name, L"\\SeRmCommandPort"); + InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); + Status = ZwCreatePort(&SeRmCommandPort, + &ObjectAttributes, + sizeof(ULONG), + PORT_MAXIMUM_MESSAGE_LENGTH, + 2 * PAGE_SIZE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Security: Rm Create Command Port failed 0x%lx\n", Status); + return FALSE; + } + + /* Create SeLsaInitEvent */ + RtlInitUnicodeString(&Name, L"\\SeLsaInitEvent"); + InitializeObjectAttributes(&ObjectAttributes, &Name, 0, NULL, NULL); + Status = ZwCreateEvent(&SeLsaInitEvent, + GENERIC_WRITE, + &ObjectAttributes, + NotificationEvent, + FALSE); + if (!NT_VERIFY((NT_SUCCESS(Status)))) + { + DPRINT1("Security: LSA init event creation failed.0x%xl\n", Status); + return FALSE; + } + + /* Create the SeRm server thread */ + Status = PsCreateSystemThread(&ThreadHandle, + THREAD_ALL_ACCESS, + NULL, + NULL, + NULL, + SepRmCommandServerThread, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Security: Rm Server Thread creation failed 0x%lx\n", Status); + return FALSE; + } + + ObCloseHandle(ThreadHandle, KernelMode); + + return TRUE; +} + +static +VOID +SepAdtInitializeBounds(VOID) +{ + struct + { + ULONG MaxLength; + ULONG MinLength; + } ListBounds; + NTSTATUS Status; + PAGED_CODE(); + + Status = SepRegQueryHelper(L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa", + L"Bounds", + REG_BINARY, + sizeof(ListBounds), + &ListBounds); + if (!NT_SUCCESS(Status)) + { + /* No registry values, so keep hardcoded defaults */ + return; + } + + /* Check if the bounds are valid */ + if ((ListBounds.MaxLength < ListBounds.MinLength) || + (ListBounds.MinLength < 16) || + (ListBounds.MaxLength - ListBounds.MinLength < 16)) + { + DPRINT1("ListBounds are invalid: %u, %u\n", + ListBounds.MinLength, ListBounds.MaxLength); + return; + } + + /* Set the new bounds globally */ + SepAdtMinListLength = ListBounds.MinLength; + SepAdtMaxListLength = ListBounds.MaxLength; +} + + +static +NTSTATUS +SepRmSetAuditEvent( + PSEP_RM_API_MESSAGE Message) +{ + ULONG i; + PAGED_CODE(); + + /* First re-initialize the bounds from the registry */ + SepAdtInitializeBounds(); + + /* Make sure we have the right message and clear */ + ASSERT(Message->ApiNumber == RmAuditSetCommand); + Message->ApiNumber = 0; + + /* Store the enable flag in the global variable */ + SepAdtAuditingEnabled = Message->u.SetAuditEvent.Enabled; + + /* Loop all audit event types */ + for (i = 0; i < POLICY_AUDIT_EVENT_TYPE_COUNT; i++) + { + /* Save the provided flags in the global array */ + SeAuditingState[i] = (UCHAR)Message->u.SetAuditEvent.Flags[i]; + } + + return STATUS_SUCCESS; +} + + +static +NTSTATUS +SepRmCreateLogonSession( + PLUID LogonLuid) +{ + PSEP_LOGON_SESSION_REFERENCES CurrentSession, NewSession; + NTSTATUS Status; + PAGED_CODE(); + + DPRINT1("SepRmCreateLogonSession(<0x%lx,0x%lx>)\n", + LogonLuid->HighPart, LogonLuid->LowPart); + + /* Allocate a new session structure */ + NewSession = ExAllocatePoolWithTag(PagedPool, + sizeof(SEP_LOGON_SESSION_REFERENCES), + SEP_LOGON_SESSION_TAG); + if (NewSession == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Initialize it */ + NewSession->LogonId = *LogonLuid; + NewSession->ReferenceCount = 0; + NewSession->Flags = 0; + NewSession->pDeviceMap = NULL; + InitializeListHead(&NewSession->TokenList); + + /* Acquire the database lock */ + KeAcquireGuardedMutex(&SepRmDbLock); + + /* Loop all existing sessions */ + for (CurrentSession = SepLogonSessions; + CurrentSession != NULL; + CurrentSession = CurrentSession->Next) + { + /* Check if the LUID matches the new one */ + if (RtlEqualLuid(&CurrentSession->LogonId, LogonLuid)) + { + Status = STATUS_LOGON_SESSION_EXISTS; + goto Leave; + } + } + + /* Insert the new session */ + NewSession->Next = SepLogonSessions; + SepLogonSessions = NewSession; + + Status = STATUS_SUCCESS; + +Leave: + /* Release the database lock */ + KeReleaseGuardedMutex(&SepRmDbLock); + + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(NewSession, SEP_LOGON_SESSION_TAG); + } + + return Status; +} + +static +NTSTATUS +SepRmDeleteLogonSession( + PLUID LogonLuid) +{ + DPRINT1("SepRmDeleteLogonSession(<0x%lx,0x%lx>)\n", + LogonLuid->HighPart, LogonLuid->LowPart); + + UNIMPLEMENTED; + NT_ASSERT(FALSE); + return STATUS_NOT_IMPLEMENTED; +} + + +BOOLEAN +NTAPI +SepRmCommandServerThreadInit(VOID) +{ + SECURITY_QUALITY_OF_SERVICE SecurityQos; + SEP_RM_API_MESSAGE Message; + UNICODE_STRING PortName; + REMOTE_PORT_VIEW RemotePortView; + PORT_VIEW PortView; + LARGE_INTEGER SectionSize; + HANDLE SectionHandle; + HANDLE PortHandle; + NTSTATUS Status; + BOOLEAN Result; + + SectionHandle = NULL; + PortHandle = NULL; + + /* Assume success */ + Result = TRUE; + + /* Wait until LSASS is ready */ + Status = ZwWaitForSingleObject(SeLsaInitEvent, FALSE, NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Security Rm Init: Waiting for LSA Init Event failed 0x%lx\n", Status); + goto Cleanup; + } + + /* We don't need this event anymore */ + ObCloseHandle(SeLsaInitEvent, KernelMode); + + /* Initialize the connection message */ + Message.Header.u1.s1.TotalLength = sizeof(Message); + Message.Header.u1.s1.DataLength = 0; + + /* Only LSASS can connect, so handle the connection right now */ + Status = ZwListenPort(SeRmCommandPort, &Message.Header); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Security Rm Init: Listen to Command Port failed 0x%lx\n", Status); + goto Cleanup; + } + + /* Set the Port View structure length */ + RemotePortView.Length = sizeof(RemotePortView); + + /* Accept the connection */ + Status = ZwAcceptConnectPort(&SepRmCommandMessagePort, + NULL, + &Message.Header, + TRUE, + NULL, + &RemotePortView); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Security Rm Init: Accept Connect to Command Port failed 0x%lx\n", Status); + goto Cleanup; + } + + /* Complete the connection */ + Status = ZwCompleteConnectPort(SepRmCommandMessagePort); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Security Rm Init: Complete Connect to Command Port failed 0x%lx\n", Status); + goto Cleanup; + } + + /* Create a section for messages */ + SectionSize.QuadPart = PAGE_SIZE; + Status = ZwCreateSection(&SectionHandle, + SECTION_ALL_ACCESS, + NULL, + &SectionSize, + PAGE_READWRITE, + SEC_COMMIT, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Security Rm Init: Create Memory Section for LSA port failed: %X\n", Status); + goto Cleanup; + } + + /* Setup the PORT_VIEW structure */ + PortView.Length = sizeof(PortView); + PortView.SectionHandle = SectionHandle; + PortView.SectionOffset = 0; + PortView.ViewSize = SectionSize.LowPart; + PortView.ViewBase = NULL; + PortView.ViewRemoteBase = NULL; + + /* Setup security QOS */ + SecurityQos.Length = sizeof(SecurityQos); + SecurityQos.ImpersonationLevel = SecurityImpersonation; + SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + SecurityQos.EffectiveOnly = TRUE; + + /* Connect to LSASS */ + RtlInitUnicodeString(&PortName, L"\\SeLsaCommandPort"); + Status = ZwConnectPort(&PortHandle, + &PortName, + &SecurityQos, + &PortView, + NULL, + 0, + 0, + 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Security Rm Init: Connect to LSA Port failed 0x%lx\n", Status); + goto Cleanup; + } + + /* Remember section base and view offset */ + SepCommandPortViewBase = PortView.ViewBase; + SepCommandPortViewRemoteBase = PortView.ViewRemoteBase; + SepCommandPortViewBaseOffset = (ULONG_PTR)SepCommandPortViewRemoteBase - + (ULONG_PTR)SepCommandPortViewBase; + + DPRINT("SepRmCommandServerThreadInit: done\n"); + +Cleanup: + /* Check for failure */ + if (!NT_SUCCESS(Status)) + { + if (PortHandle != NULL) + { + ObCloseHandle(PortHandle, KernelMode); + } + + Result = FALSE; + } + + /* Did we create a section? */ + if (SectionHandle != NULL) + { + ObCloseHandle(SectionHandle, KernelMode); + } + + return Result; +} + +VOID +NTAPI +SepRmCommandServerThread( + PVOID StartContext) +{ + SEP_RM_API_MESSAGE Message; + PPORT_MESSAGE ReplyMessage; + HANDLE DummyPortHandle; + NTSTATUS Status; + + /* Initialize the server thread */ + if (!SepRmCommandServerThreadInit()) + { + DPRINT1("Security: Terminating Rm Command Server Thread\n"); + return; + } + + /* No reply yet */ + ReplyMessage = NULL; + + /* Start looping */ + while (TRUE) + { + /* Wait for a message */ + Status = ZwReplyWaitReceivePort(SepRmCommandMessagePort, + NULL, + ReplyMessage, + &Message.Header); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to get message: 0x%lx", Status); + ReplyMessage = NULL; + continue; + } + + /* Check if this is a connection request */ + if (Message.Header.u2.s2.Type == LPC_CONNECTION_REQUEST) + { + /* Reject connection request */ + ZwAcceptConnectPort(&DummyPortHandle, + NULL, + &Message.Header, + FALSE, + NULL, + NULL); + + /* Start over */ + ReplyMessage = NULL; + continue; + } + + /* Check if the port died */ + if ((Message.Header.u2.s2.Type == LPC_PORT_CLOSED) || + (Message.Header.u2.s2.Type == LPC_CLIENT_DIED)) + { + /* LSASS is dead, so let's quit as well */ + break; + } + + /* Check if this is an actual request */ + if (Message.Header.u2.s2.Type != LPC_REQUEST) + { + DPRINT1("SepRmCommandServerThread: unexpected message type: 0x%lx\n", + Message.Header.u2.s2.Type); + + /* Restart without replying */ + ReplyMessage = NULL; + continue; + } + + ReplyMessage = &Message.Header; + + switch (Message.ApiNumber) + { + case RmAuditSetCommand: + Status = SepRmSetAuditEvent(&Message); + break; + + case RmCreateLogonSession: + Status = SepRmCreateLogonSession(&Message.u.LogonLuid); + break; + + case RmDeleteLogonSession: + Status = SepRmDeleteLogonSession(&Message.u.LogonLuid); + break; + + default: + DPRINT1("SepRmDispatchRequest: invalid API number: 0x%lx\n", + Message.ApiNumber); + ReplyMessage = NULL; + } + + Message.u.ResultStatus = Status; + } + + /* Close the port handles */ + ObCloseHandle(SepRmCommandMessagePort, KernelMode); + ObCloseHandle(SeRmCommandPort, KernelMode); +} -- 2.17.1