1212 lines
36 KiB
C
1212 lines
36 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
rmmain.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Security Reference Monitor - Init, Control and State Change
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Scott Birrell (ScottBi) March 12, 1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pch.h"
|
|||
|
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT,SeRmInitPhase1)
|
|||
|
#pragma alloc_text(PAGE,SepRmCommandServerThread)
|
|||
|
#pragma alloc_text(PAGE,SepRmCommandServerThreadInit)
|
|||
|
#pragma alloc_text(PAGE,SepRmCallLsa)
|
|||
|
#pragma alloc_text(INIT,SepRmInitPhase0)
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Reference Monitor Command Worker Table
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Keep this in sync with RM_COMMAND_NUMBER in ntrmlsa.h
|
|||
|
//
|
|||
|
|
|||
|
#ifdef ALLOC_DATA_PRAGMA
|
|||
|
#pragma const_seg("PAGECONST")
|
|||
|
#endif
|
|||
|
|
|||
|
const SEP_RM_COMMAND_WORKER SepRmCommandDispatch[] = {
|
|||
|
NULL,
|
|||
|
SepRmSetAuditEventWrkr,
|
|||
|
SepRmCreateLogonSessionWrkr,
|
|||
|
SepRmDeleteLogonSessionWrkr
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
SeRmInitPhase1(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called by Phase 1 System Initialization to initialize
|
|||
|
the Security Reference Monitor. Note that initialization of the
|
|||
|
Reference Monitor Global State has already been performed in Phase 0
|
|||
|
initialization to allow access validation routines to operate without
|
|||
|
having to check that Reference Monitor Initialization is complete.
|
|||
|
|
|||
|
The steps listed below are performed in this routine. The remainder
|
|||
|
of Reference Monitor initialization requires the LSA subsystem to have run,
|
|||
|
so that initialization is performed in a separate thread (the RM Command
|
|||
|
Server Thread, see below), so that the present thread can create the
|
|||
|
Session Manager which execs the LSA.
|
|||
|
|
|||
|
o Create the Reference Monitor Command LPC port. The LSA subsystem sends
|
|||
|
commands (e.g. turn on auditing) which change the Reference Monitor
|
|||
|
Global State.
|
|||
|
o Create an Event for use in synchronizing with the LSA subsystem. The
|
|||
|
LSA will signal the event when the portion of LSA initialization upon
|
|||
|
with the Reference Monitor depends is complete. The Reference Monitor
|
|||
|
uses another LPC port, called the LSA Command Port to send commands
|
|||
|
to the LSA, so the RM must know that this port has been created before
|
|||
|
trying to connect to it.
|
|||
|
o Create the Reference Monitor Command Server Thread. This thread is
|
|||
|
a permanent thread of the System Init process that fields the Reference
|
|||
|
Monitor State Change commands described above.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - TRUE if Rm Initialization (Phase 1) succeeded, else FALSE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
STRING RmCommandPortName;
|
|||
|
UNICODE_STRING UnicodeRmCommandPortName;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
STRING LsaInitEventName;
|
|||
|
UNICODE_STRING UnicodeLsaInitEventName;
|
|||
|
OBJECT_ATTRIBUTES LsaInitEventObjectAttributes;
|
|||
|
SECURITY_DESCRIPTOR LsaInitEventSecurityDescriptor;
|
|||
|
ULONG AclSize;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Create an LPC port called the Reference Monitor Command Port.
|
|||
|
// This will be used by the LSA to send commands to the Reference
|
|||
|
// Monitor to update its state data.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitString( &RmCommandPortName, "\\SeRmCommandPort" );
|
|||
|
Status = RtlAnsiStringToUnicodeString(
|
|||
|
&UnicodeRmCommandPortName,
|
|||
|
&RmCommandPortName,
|
|||
|
TRUE );
|
|||
|
ASSERT( NT_SUCCESS(Status) );
|
|||
|
InitializeObjectAttributes(
|
|||
|
&ObjectAttributes,
|
|||
|
&UnicodeRmCommandPortName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
Status = ZwCreatePort(
|
|||
|
&SepRmState.RmCommandServerPortHandle,
|
|||
|
&ObjectAttributes,
|
|||
|
sizeof(SEP_RM_CONNECT_INFO),
|
|||
|
sizeof(RM_COMMAND_MESSAGE),
|
|||
|
sizeof(RM_COMMAND_MESSAGE) * 32
|
|||
|
);
|
|||
|
RtlFreeUnicodeString( &UnicodeRmCommandPortName );
|
|||
|
|
|||
|
if( !NT_SUCCESS(Status) ) {
|
|||
|
|
|||
|
KdPrint(("Security: Rm Create Command Port failed 0x%lx\n", Status));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Prepare to create an event for synchronizing with the LSA.
|
|||
|
// First, build the Security Descriptor for the Init Event Object
|
|||
|
//
|
|||
|
|
|||
|
Status = RtlCreateSecurityDescriptor(
|
|||
|
&LsaInitEventSecurityDescriptor,
|
|||
|
SECURITY_DESCRIPTOR_REVISION
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security: Creating Lsa Init Event Desc failed 0x%lx\n",
|
|||
|
Status));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a temporary buffer from the paged pool. It is a fatal
|
|||
|
// system error if the allocation fails since security cannot be
|
|||
|
// enabled.
|
|||
|
//
|
|||
|
|
|||
|
AclSize = sizeof(ACL) +
|
|||
|
sizeof(ACCESS_ALLOWED_ACE) +
|
|||
|
SeLengthSid(SeLocalSystemSid);
|
|||
|
LsaInitEventSecurityDescriptor.Dacl =
|
|||
|
ExAllocatePoolWithTag(PagedPool, AclSize, 'cAeS');
|
|||
|
|
|||
|
if (LsaInitEventSecurityDescriptor.Dacl == NULL) {
|
|||
|
|
|||
|
KdPrint(("Security LSA: Insufficient resources to initialize\n"));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now create the Discretionary ACL within the Security Descriptor
|
|||
|
//
|
|||
|
|
|||
|
Status = RtlCreateAcl(
|
|||
|
LsaInitEventSecurityDescriptor.Dacl,
|
|||
|
AclSize,
|
|||
|
ACL_REVISION2
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security: Creating Lsa Init Event Dacl failed 0x%lx\n",
|
|||
|
Status));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now add an ACE giving GENERIC_ALL access to the User ID
|
|||
|
//
|
|||
|
|
|||
|
Status = RtlAddAccessAllowedAce(
|
|||
|
LsaInitEventSecurityDescriptor.Dacl,
|
|||
|
ACL_REVISION2,
|
|||
|
GENERIC_ALL,
|
|||
|
SeLocalSystemSid
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security: Adding Lsa Init Event ACE failed 0x%lx\n",
|
|||
|
Status));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up the Object Attributes for the Lsa Initialization Event
|
|||
|
//
|
|||
|
|
|||
|
RtlInitString( &LsaInitEventName, "\\SeLsaInitEvent" );
|
|||
|
Status = RtlAnsiStringToUnicodeString(
|
|||
|
&UnicodeLsaInitEventName,
|
|||
|
&LsaInitEventName,
|
|||
|
TRUE ); ASSERT( NT_SUCCESS(Status) );
|
|||
|
InitializeObjectAttributes(
|
|||
|
&LsaInitEventObjectAttributes,
|
|||
|
&UnicodeLsaInitEventName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
&LsaInitEventSecurityDescriptor
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Create an event for use in synchronizing with the LSA. The LSA will
|
|||
|
// signal this event when LSA initialization has reached the point
|
|||
|
// where the LSA's Reference Monitor Server Port has been created.
|
|||
|
//
|
|||
|
|
|||
|
Status = ZwCreateEvent(
|
|||
|
&(SepRmState.LsaInitEventHandle),
|
|||
|
EVENT_MODIFY_STATE,
|
|||
|
&LsaInitEventObjectAttributes,
|
|||
|
NotificationEvent,
|
|||
|
FALSE);
|
|||
|
|
|||
|
RtlFreeUnicodeString( &UnicodeLsaInitEventName );
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security: LSA init event creation failed.0x%xl\n",
|
|||
|
Status));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Deallocate the pool memory used for the Init Event DACL
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool( LsaInitEventSecurityDescriptor.Dacl );
|
|||
|
|
|||
|
//
|
|||
|
// Create a permanent thread of the Sysinit Process, called the
|
|||
|
// Reference Monitor Server Thread. This thread is dedicated to
|
|||
|
// receiving Reference Monitor commands and dispatching them.
|
|||
|
//
|
|||
|
|
|||
|
Status = PsCreateSystemThread(
|
|||
|
&SepRmState.SepRmThreadHandle,
|
|||
|
THREAD_GET_CONTEXT |
|
|||
|
THREAD_SET_CONTEXT |
|
|||
|
THREAD_SET_INFORMATION,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
SepRmCommandServerThread,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security: Rm Server Thread creation failed 0x%lx\n", Status));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize data from the registry. This must go here because all other
|
|||
|
// Se initialization takes place before the registry is initialized.
|
|||
|
//
|
|||
|
|
|||
|
SepAdtInitializeCrashOnFail();
|
|||
|
SepAdtInitializePrivilegeAuditing();
|
|||
|
SepAdtInitializeAuditingOptions();
|
|||
|
|
|||
|
//
|
|||
|
// Reference Monitor initialization is successful if we get to here.
|
|||
|
//
|
|||
|
|
|||
|
ZwClose( SepRmState.SepRmThreadHandle );
|
|||
|
SepRmState.SepRmThreadHandle = NULL;
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SepRmCommandServerThread(
|
|||
|
IN PVOID StartContext
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is executed indefinitely by a dedicated permanent thread
|
|||
|
of the Sysinit Process, called the Reference Monitor Server Thread.
|
|||
|
This thread updates Reference Monitor Global State Data by dispatching
|
|||
|
commands sent from the LSA through the the Reference Monitor LPC Command
|
|||
|
Port. The following steps are repeated indefinitely:
|
|||
|
|
|||
|
o Initialize RM Command receive and reply buffer headers
|
|||
|
o Perform remaining Reference Monitor initialization involving LSA
|
|||
|
o Wait for RM command sent from LSA, send reply to previous command
|
|||
|
(if any)
|
|||
|
o Validate command
|
|||
|
o Dispatch to command worker routine to execute command.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
PRM_REPLY_MESSAGE Reply;
|
|||
|
RM_COMMAND_MESSAGE CommandMessage;
|
|||
|
RM_REPLY_MESSAGE ReplyMessage;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Perform the rest of the Reference Monitor initialization, involving
|
|||
|
// synchronization with the LSA or dependency on the LSA having run.
|
|||
|
//
|
|||
|
|
|||
|
if (!SepRmCommandServerThreadInit()) {
|
|||
|
|
|||
|
KdPrint(("Security: Terminating Rm Command Server Thread\n"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Status = PoRequestShutdownEvent (NULL);
|
|||
|
if (!NT_SUCCESS (Status)) {
|
|||
|
ZwClose (SepRmState.RmCommandPortHandle);
|
|||
|
ZwClose (SepRmState.RmCommandServerPortHandle);
|
|||
|
ZwClose (SepRmState.LsaCommandPortHandle);
|
|||
|
ZwClose (SepLsaHandle);
|
|||
|
SepRmState.RmCommandPortHandle = NULL;
|
|||
|
SepRmState.RmCommandServerPortHandle = NULL;
|
|||
|
SepRmState.LsaCommandPortHandle = NULL;
|
|||
|
SepLsaHandle = NULL;
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize LPC port message header type and length fields for the
|
|||
|
// received command message.
|
|||
|
//
|
|||
|
|
|||
|
CommandMessage.MessageHeader.u2.ZeroInit = 0;
|
|||
|
CommandMessage.MessageHeader.u1.s1.TotalLength =
|
|||
|
(CSHORT) sizeof(RM_COMMAND_MESSAGE);
|
|||
|
CommandMessage.MessageHeader.u1.s1.DataLength =
|
|||
|
CommandMessage.MessageHeader.u1.s1.TotalLength -
|
|||
|
(CSHORT) sizeof(PORT_MESSAGE);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the LPC port message header type and data sizes for
|
|||
|
// for the reply message.
|
|||
|
//
|
|||
|
|
|||
|
ReplyMessage.MessageHeader.u2.ZeroInit = 0;
|
|||
|
ReplyMessage.MessageHeader.u1.s1.TotalLength =
|
|||
|
(CSHORT) sizeof(RM_COMMAND_MESSAGE);
|
|||
|
ReplyMessage.MessageHeader.u1.s1.DataLength =
|
|||
|
ReplyMessage.MessageHeader.u1.s1.TotalLength -
|
|||
|
(CSHORT) sizeof(PORT_MESSAGE);
|
|||
|
|
|||
|
//
|
|||
|
// First time through, there is no reply.
|
|||
|
//
|
|||
|
|
|||
|
Reply = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Now loop indefinitely, processing incoming Rm commands from the LSA.
|
|||
|
//
|
|||
|
|
|||
|
for(;;) {
|
|||
|
|
|||
|
//
|
|||
|
// Wait for Command, send reply to previous command (if any)
|
|||
|
//
|
|||
|
|
|||
|
Status = ZwReplyWaitReceivePort(
|
|||
|
SepRmState.RmCommandPortHandle,
|
|||
|
NULL,
|
|||
|
(PPORT_MESSAGE) Reply,
|
|||
|
(PPORT_MESSAGE) &CommandMessage
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// malicious user apps can try to connect to this port. We will
|
|||
|
// fail later, but if their thread vanishes, we'll get a failure
|
|||
|
// here. Ignore it:
|
|||
|
//
|
|||
|
|
|||
|
if ( Status == STATUS_UNSUCCESSFUL )
|
|||
|
{
|
|||
|
//
|
|||
|
// skip it:
|
|||
|
//
|
|||
|
|
|||
|
Reply = NULL ;
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
KdPrint(("Security: RM message receive from Lsa failed %lx\n",
|
|||
|
Status));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now dispatch to a routine to handle the command. Allow
|
|||
|
// command errors to occur without bringing system down just now.
|
|||
|
//
|
|||
|
|
|||
|
CommandMessage.MessageHeader.u2.s2.Type &= ~LPC_KERNELMODE_MESSAGE;
|
|||
|
|
|||
|
if ( CommandMessage.MessageHeader.u2.s2.Type == LPC_REQUEST ) {
|
|||
|
|
|||
|
if ( (CommandMessage.CommandNumber >= RmAuditSetCommand) &&
|
|||
|
(CommandMessage.CommandNumber <= RmDeleteLogonSession) ) {
|
|||
|
|
|||
|
(*(SepRmCommandDispatch[CommandMessage.CommandNumber]))
|
|||
|
(&CommandMessage, &ReplyMessage);
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the client thread info and message id for the
|
|||
|
// reply message. First time through, the reply message structure
|
|||
|
// is not used.
|
|||
|
//
|
|||
|
|
|||
|
ReplyMessage.MessageHeader.ClientId =
|
|||
|
CommandMessage.MessageHeader.ClientId;
|
|||
|
ReplyMessage.MessageHeader.MessageId =
|
|||
|
CommandMessage.MessageHeader.MessageId;
|
|||
|
|
|||
|
Reply = &ReplyMessage;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ASSERT( (CommandMessage.CommandNumber >= RmAuditSetCommand) &&
|
|||
|
(CommandMessage.CommandNumber <= RmDeleteLogonSession) );
|
|||
|
Reply = NULL;
|
|||
|
}
|
|||
|
|
|||
|
} else if (CommandMessage.MessageHeader.u2.s2.Type == LPC_PORT_CLOSED ) {
|
|||
|
KEVENT Event;
|
|||
|
BOOLEAN Wait;
|
|||
|
|
|||
|
KeInitializeEvent (&Event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
SepLockLsaQueue();
|
|||
|
|
|||
|
SepAdtLsaDeadEvent = &Event;
|
|||
|
|
|||
|
Wait = !SepWorkListEmpty ();
|
|||
|
|
|||
|
SepUnlockLsaQueue();
|
|||
|
|
|||
|
if (Wait) {
|
|||
|
KeWaitForSingleObject (&Event,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
}
|
|||
|
//
|
|||
|
// Our only client closed its handle. Tidy up and exit.
|
|||
|
//
|
|||
|
ZwClose (SepRmState.LsaCommandPortHandle);
|
|||
|
ZwClose (SepRmState.RmCommandPortHandle);
|
|||
|
ZwClose (SepRmState.RmCommandServerPortHandle);
|
|||
|
ZwClose (SepLsaHandle);
|
|||
|
SepRmState.LsaCommandPortHandle = NULL;
|
|||
|
SepRmState.RmCommandPortHandle = NULL;
|
|||
|
SepRmState.RmCommandServerPortHandle = NULL;
|
|||
|
SepLsaHandle = NULL;
|
|||
|
break;
|
|||
|
} else if (CommandMessage.MessageHeader.u2.s2.Type == LPC_CONNECTION_REQUEST) {
|
|||
|
HANDLE tmp;
|
|||
|
//
|
|||
|
// Reject extra connection attempts
|
|||
|
//
|
|||
|
Status = ZwAcceptConnectPort(&tmp,
|
|||
|
NULL,
|
|||
|
(PPORT_MESSAGE) &CommandMessage,
|
|||
|
FALSE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
} else {
|
|||
|
|
|||
|
Reply = NULL;
|
|||
|
}
|
|||
|
} // end_for
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( StartContext );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
SepRmCommandServerThreadInit(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function performs initialization of the Reference Monitor Server
|
|||
|
thread. The following steps are performed.
|
|||
|
|
|||
|
o Wait on the LSA signalling the event. When the event is signalled,
|
|||
|
the LSA has already created the LSA Command Server LPC Port
|
|||
|
o Close the LSA Init Event Handle. The event is not used again.
|
|||
|
o Listen for the LSA to connect to the Port
|
|||
|
o Accept the connection.
|
|||
|
o Connect to the LSA Command Server LPC Port
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
UNICODE_STRING LsaCommandPortName;
|
|||
|
PORT_MESSAGE ConnectionRequest;
|
|||
|
SECURITY_QUALITY_OF_SERVICE DynamicQos;
|
|||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|||
|
PORT_VIEW ClientView;
|
|||
|
REMOTE_PORT_VIEW LsaClientView;
|
|||
|
BOOLEAN BooleanStatus = TRUE;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Save a pointer to our process so we can get back into this process
|
|||
|
// to send commands to the LSA (using a handle to an LPC port created
|
|||
|
// below).
|
|||
|
//
|
|||
|
|
|||
|
SepRmLsaCallProcess = PsGetCurrentProcess();
|
|||
|
|
|||
|
ObReferenceObject(SepRmLsaCallProcess);
|
|||
|
|
|||
|
//
|
|||
|
// Wait on the LSA signalling the event. This means that the LSA
|
|||
|
// has created its command port, not that LSA initialization is
|
|||
|
// complete.
|
|||
|
//
|
|||
|
|
|||
|
Status = ZwWaitForSingleObject(
|
|||
|
SepRmState.LsaInitEventHandle,
|
|||
|
FALSE,
|
|||
|
NULL);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Status) ) {
|
|||
|
|
|||
|
KdPrint(("Security Rm Init: Waiting for LSA Init Event failed 0x%lx\n", Status));
|
|||
|
goto RmCommandServerThreadInitError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Close the LSA Init Event Handle. The event is not used again.
|
|||
|
//
|
|||
|
|
|||
|
ZwClose(SepRmState.LsaInitEventHandle);
|
|||
|
|
|||
|
//
|
|||
|
// Listen for a connection to be made by the LSA to the Reference Monitor
|
|||
|
// Command Port. This connection will be made by the LSA process.
|
|||
|
//
|
|||
|
|
|||
|
ConnectionRequest.u1.s1.TotalLength = sizeof(ConnectionRequest);
|
|||
|
ConnectionRequest.u1.s1.DataLength = (CSHORT)0;
|
|||
|
Status = ZwListenPort(
|
|||
|
SepRmState.RmCommandServerPortHandle,
|
|||
|
&ConnectionRequest
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security Rm Init: Listen to Command Port failed 0x%lx\n",
|
|||
|
Status));
|
|||
|
goto RmCommandServerThreadInitError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Obtain a handle to the LSA process for use when auditing.
|
|||
|
//
|
|||
|
|
|||
|
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
|
|||
|
|
|||
|
Status = ZwOpenProcess(
|
|||
|
&SepLsaHandle,
|
|||
|
PROCESS_VM_OPERATION | PROCESS_VM_WRITE,
|
|||
|
&ObjectAttributes,
|
|||
|
&ConnectionRequest.ClientId
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security Rm Init: Open Listen to Command Port failed 0x%lx\n",
|
|||
|
Status));
|
|||
|
goto RmCommandServerThreadInitError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Accept the connection made by the LSA process.
|
|||
|
//
|
|||
|
|
|||
|
LsaClientView.Length = sizeof(LsaClientView);
|
|||
|
|
|||
|
|
|||
|
Status = ZwAcceptConnectPort(
|
|||
|
&SepRmState.RmCommandPortHandle,
|
|||
|
NULL,
|
|||
|
&ConnectionRequest,
|
|||
|
TRUE,
|
|||
|
NULL,
|
|||
|
&LsaClientView
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security Rm Init: Accept Connect to Command Port failed 0x%lx\n",
|
|||
|
Status));
|
|||
|
|
|||
|
goto RmCommandServerThreadInitError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Complete the connection.
|
|||
|
//
|
|||
|
|
|||
|
Status = ZwCompleteConnectPort(SepRmState.RmCommandPortHandle);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security Rm Init: Complete Connect to Command Port failed 0x%lx\n",
|
|||
|
Status));
|
|||
|
goto RmCommandServerThreadInitError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up the security quality of service parameters to use over the
|
|||
|
// Lsa Command LPC port. Use the most efficient (least overhead) - which
|
|||
|
// is dynamic rather than static tracking.
|
|||
|
//
|
|||
|
|
|||
|
DynamicQos.ImpersonationLevel = SecurityImpersonation;
|
|||
|
DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|||
|
DynamicQos.EffectiveOnly = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Create the section to be used as unnamed shared memory for
|
|||
|
// communication between the RM and LSA.
|
|||
|
//
|
|||
|
|
|||
|
SepRmState.LsaCommandPortSectionSize.LowPart = PAGE_SIZE;
|
|||
|
SepRmState.LsaCommandPortSectionSize.HighPart = 0;
|
|||
|
|
|||
|
Status = ZwCreateSection(
|
|||
|
&SepRmState.LsaCommandPortSectionHandle,
|
|||
|
SECTION_ALL_ACCESS,
|
|||
|
NULL, // ObjectAttributes
|
|||
|
&SepRmState.LsaCommandPortSectionSize,
|
|||
|
PAGE_READWRITE,
|
|||
|
SEC_COMMIT,
|
|||
|
NULL // FileHandle
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security Rm Init: Create Memory Section for LSA port failed: %X\n", Status));
|
|||
|
goto RmCommandServerThreadInitError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up for a call to NtConnectPort and connect to the LSA port.
|
|||
|
// This setup includes a description of the port memory section so that
|
|||
|
// the LPC connection logic can make the section visible to both the
|
|||
|
// client and server processes.
|
|||
|
//
|
|||
|
|
|||
|
ClientView.Length = sizeof(ClientView);
|
|||
|
ClientView.SectionHandle = SepRmState.LsaCommandPortSectionHandle;
|
|||
|
ClientView.SectionOffset = 0;
|
|||
|
ClientView.ViewSize = SepRmState.LsaCommandPortSectionSize.LowPart;
|
|||
|
ClientView.ViewBase = 0;
|
|||
|
ClientView.ViewRemoteBase = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Set up the security quality of service parameters to use over the
|
|||
|
// port. Use dynamic tracking so that XACTSRV will impersonate the
|
|||
|
// user that we are impersonating when we call NtRequestWaitReplyPort.
|
|||
|
// If we used static tracking, XACTSRV would impersonate the context
|
|||
|
// when the connection is made.
|
|||
|
//
|
|||
|
|
|||
|
DynamicQos.ImpersonationLevel = SecurityImpersonation;
|
|||
|
DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|||
|
DynamicQos.EffectiveOnly = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Connect to the Lsa Command LPC Port. This port is used to send
|
|||
|
// commands from the RM to the LSA.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString( &LsaCommandPortName, L"\\SeLsaCommandPort" );
|
|||
|
|
|||
|
Status = ZwConnectPort(
|
|||
|
&SepRmState.LsaCommandPortHandle,
|
|||
|
&LsaCommandPortName,
|
|||
|
&DynamicQos,
|
|||
|
&ClientView,
|
|||
|
NULL, // ServerView
|
|||
|
NULL, // MaxMessageLength
|
|||
|
NULL, // ConnectionInformation
|
|||
|
NULL // ConnectionInformationLength
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
KdPrint(("Security Rm Init: Connect to LSA Port failed 0x%lx\n", Status));
|
|||
|
goto RmCommandServerThreadInitError;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Store information about the section so that we can create pointers
|
|||
|
// meaningful to LSA.
|
|||
|
//
|
|||
|
|
|||
|
SepRmState.RmViewPortMemory = ClientView.ViewBase;
|
|||
|
SepRmState.LsaCommandPortMemoryDelta =
|
|||
|
(LONG)((ULONG_PTR)ClientView.ViewRemoteBase - (ULONG_PTR) ClientView.ViewBase );
|
|||
|
SepRmState.LsaViewPortMemory = ClientView.ViewRemoteBase;
|
|||
|
|
|||
|
|
|||
|
RmCommandServerThreadInitFinish:
|
|||
|
|
|||
|
//
|
|||
|
// Dont need this section handle any more, even if returning
|
|||
|
// success.
|
|||
|
//
|
|||
|
|
|||
|
if ( SepRmState.LsaCommandPortSectionHandle != NULL ) {
|
|||
|
|
|||
|
NtClose( SepRmState.LsaCommandPortSectionHandle );
|
|||
|
SepRmState.LsaCommandPortSectionHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The Reference Monitor Thread has successfully initialized.
|
|||
|
//
|
|||
|
|
|||
|
return BooleanStatus;
|
|||
|
|
|||
|
RmCommandServerThreadInitError:
|
|||
|
|
|||
|
if ( SepRmState.LsaCommandPortHandle != NULL ) {
|
|||
|
|
|||
|
NtClose( SepRmState.LsaCommandPortHandle );
|
|||
|
SepRmState.LsaCommandPortHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
BooleanStatus = FALSE;
|
|||
|
goto RmCommandServerThreadInitFinish;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SepRmCallLsa(
|
|||
|
PSEP_WORK_ITEM SepWorkItem
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function sends a command to the LSA via the LSA Reference Monitor
|
|||
|
Server Command LPC Port. If the command has parameters, they will be
|
|||
|
copied directly into a message structure and sent via LPC, therefore,
|
|||
|
the supplied parameters may not contain any absolute pointers. A caller
|
|||
|
must remove pointers by "marshalling" them into the buffer CommandParams.
|
|||
|
|
|||
|
This function will create a queue of requests. This is in order to allow
|
|||
|
greater throughput for the majority if its callers. If a thread enters
|
|||
|
this routine and finds the queue empty, it is the responsibility of that
|
|||
|
thread to service all requests that come in while it is working until the
|
|||
|
queue is empty again. Other threads that enter will simply hook their work
|
|||
|
item onto the queue and exit.
|
|||
|
|
|||
|
|
|||
|
To implement a new LSA command, do the following:
|
|||
|
================================================
|
|||
|
|
|||
|
(1) If the command takes no parameters, just call this routine directly
|
|||
|
and provide an LSA worker routine called Lsap<command>Wrkr. See
|
|||
|
file lsa\server\lsarm.c for examples
|
|||
|
|
|||
|
(2) If the command takes parameters, provide a routine called
|
|||
|
SepRmSend<command>Command that takes the parameters in unmarshalled
|
|||
|
form and calls SepRmCallLsa() with the command id, marshalled
|
|||
|
parameters, length of marshalled parameters and pointer to
|
|||
|
optional reply message. The marshalled parameters are free format:
|
|||
|
the only restriction is that there must be no absolute address
|
|||
|
pointers. These parameters are all placed in the passed LsaWorkItem
|
|||
|
structure.
|
|||
|
|
|||
|
(3) In file private\inc\ntrmlsa.h, append a command name to the
|
|||
|
enumerated type LSA_COMMAND_NUMBER defined in file
|
|||
|
private\inc\ntrmlsa.h. Change the #define for LsapMaximumCommand
|
|||
|
to reference the new command.
|
|||
|
|
|||
|
(4) Add the Lsap<command>Wrkr to the command dispatch table structure
|
|||
|
LsapCommandDispatch[] in file lsarm.c.
|
|||
|
|
|||
|
(5) Add function prototypes to lsap.h and sep.h.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
LsaWorkItem - Supplies a pointer to an SE_LSA_WORK_ITEM containing the
|
|||
|
information to be passed to LSA. This structure will be freed
|
|||
|
asynchronously by some invocation of this routine, not necessarily
|
|||
|
in the current context.
|
|||
|
|
|||
|
!THIS PARAMETER MUST BE ALLOCATED OUT OF NONPAGED POOL!
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - Result Code. This is either a result code returned from
|
|||
|
trying to send the command/receive the reply, or a status code
|
|||
|
from the command itself.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status = STATUS_SUCCESS;
|
|||
|
LSA_COMMAND_MESSAGE CommandMessage;
|
|||
|
LSA_REPLY_MESSAGE ReplyMessage;
|
|||
|
PSEP_LSA_WORK_ITEM WorkQueueItem;
|
|||
|
ULONG LocalListLength = 0;
|
|||
|
SIZE_T RegionSize;
|
|||
|
PVOID CopiedCommandParams = NULL;
|
|||
|
PVOID LsaViewCopiedCommandParams = NULL;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( SepWorkItem );
|
|||
|
|
|||
|
#if 0
|
|||
|
DbgPrint("Entering SepRmCallLsa\n");
|
|||
|
#endif
|
|||
|
|
|||
|
WorkQueueItem = SepWorkListHead();
|
|||
|
|
|||
|
KeAttachProcess( &SepRmLsaCallProcess->Pcb );
|
|||
|
|
|||
|
while ( WorkQueueItem ) {
|
|||
|
|
|||
|
#if 0
|
|||
|
DbgPrint("Got a work item from head of queue, processing\n");
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Construct a message for LPC. First, fill in the message header
|
|||
|
// fields for LPC, specifying the message type and data sizes for
|
|||
|
// the outgoing CommandMessage and the incoming ReplyMessage.
|
|||
|
//
|
|||
|
|
|||
|
CommandMessage.MessageHeader.u2.ZeroInit = 0;
|
|||
|
CommandMessage.MessageHeader.u1.s1.TotalLength =
|
|||
|
((CSHORT) RM_COMMAND_MESSAGE_HEADER_SIZE +
|
|||
|
(CSHORT) WorkQueueItem->CommandParamsLength);
|
|||
|
CommandMessage.MessageHeader.u1.s1.DataLength =
|
|||
|
CommandMessage.MessageHeader.u1.s1.TotalLength -
|
|||
|
(CSHORT) sizeof(PORT_MESSAGE);
|
|||
|
|
|||
|
ReplyMessage.MessageHeader.u2.ZeroInit = 0;
|
|||
|
ReplyMessage.MessageHeader.u1.s1.DataLength = (CSHORT) WorkQueueItem->ReplyBufferLength;
|
|||
|
ReplyMessage.MessageHeader.u1.s1.TotalLength =
|
|||
|
ReplyMessage.MessageHeader.u1.s1.DataLength +
|
|||
|
(CSHORT) sizeof(PORT_MESSAGE);
|
|||
|
|
|||
|
//
|
|||
|
// Next, fill in the header info needed by the LSA.
|
|||
|
//
|
|||
|
|
|||
|
CommandMessage.CommandNumber = WorkQueueItem->CommandNumber;
|
|||
|
ReplyMessage.ReturnedStatus = STATUS_SUCCESS;
|
|||
|
|
|||
|
//
|
|||
|
// Set up the Command Parameters either in the LPC Command Message
|
|||
|
// itself, in the preallocated Lsa shared memory block, or in a
|
|||
|
// specially allocated block. The parameters are either
|
|||
|
// immediate (i.e. in the WorkQueueItem itself, or are in a buffer
|
|||
|
// pointed to by the address in the WorkQueueItem.
|
|||
|
//
|
|||
|
|
|||
|
switch (WorkQueueItem->CommandParamsMemoryType) {
|
|||
|
|
|||
|
case SepRmImmediateMemory:
|
|||
|
|
|||
|
//
|
|||
|
// The Command Parameters are in the CommandParams buffer
|
|||
|
// in the Work Queue Item. Just copy them to the corresponding
|
|||
|
// buffer in the CommandMessage buffer.
|
|||
|
//
|
|||
|
|
|||
|
CommandMessage.CommandParamsMemoryType = SepRmImmediateMemory;
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
CommandMessage.CommandParams,
|
|||
|
&WorkQueueItem->CommandParams,
|
|||
|
WorkQueueItem->CommandParamsLength
|
|||
|
);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case SepRmPagedPoolMemory:
|
|||
|
case SepRmUnspecifiedMemory:
|
|||
|
|
|||
|
//
|
|||
|
// The Command Parameters are contained in paged pool memory.
|
|||
|
// Since this memory is is not accessible by the LSA, we must
|
|||
|
// copy of them either to the LPC Command Message Block, or
|
|||
|
// into LSA shared memory.
|
|||
|
//
|
|||
|
|
|||
|
if (WorkQueueItem->CommandParamsLength <= LSA_MAXIMUM_COMMAND_PARAM_SIZE) {
|
|||
|
|
|||
|
//
|
|||
|
// Parameters will fit into the LPC Command Message block.
|
|||
|
//
|
|||
|
|
|||
|
CopiedCommandParams = CommandMessage.CommandParams;
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
CopiedCommandParams,
|
|||
|
WorkQueueItem->CommandParams.BaseAddress,
|
|||
|
WorkQueueItem->CommandParamsLength
|
|||
|
);
|
|||
|
|
|||
|
CommandMessage.CommandParamsMemoryType = SepRmImmediateMemory;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Parameters too large for LPC Command Message block.
|
|||
|
// If possible, copy them to the preallocated Lsa Shared
|
|||
|
// Memory block. If they are too large to fit, copy them
|
|||
|
// to an individually allocated chunk of Shared Virtual
|
|||
|
// Memory.
|
|||
|
//
|
|||
|
|
|||
|
if (WorkQueueItem->CommandParamsLength <= SEP_RM_LSA_SHARED_MEMORY_SIZE) {
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
SepRmState.RmViewPortMemory,
|
|||
|
WorkQueueItem->CommandParams.BaseAddress,
|
|||
|
WorkQueueItem->CommandParamsLength
|
|||
|
);
|
|||
|
|
|||
|
LsaViewCopiedCommandParams = SepRmState.LsaViewPortMemory;
|
|||
|
CommandMessage.CommandParamsMemoryType = SepRmLsaCommandPortSharedMemory;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = SepAdtCopyToLsaSharedMemory(
|
|||
|
SepLsaHandle,
|
|||
|
WorkQueueItem->CommandParams.BaseAddress,
|
|||
|
WorkQueueItem->CommandParamsLength,
|
|||
|
&LsaViewCopiedCommandParams
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// An error occurred, most likely in allocating
|
|||
|
// shared virtual memory. For now, just ignore
|
|||
|
// the error and discard the Audit Record. Later,
|
|||
|
// we may consider generating a warning record
|
|||
|
// indicating some records lost.
|
|||
|
//
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
CommandMessage.CommandParamsMemoryType = SepRmLsaCustomSharedMemory;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Buffer has been successfully copied to a shared Lsa
|
|||
|
// memory buffer. Place the address of the buffer valid in
|
|||
|
// the LSA's process context in the Command Message.
|
|||
|
//
|
|||
|
|
|||
|
*((PVOID *) CommandMessage.CommandParams) =
|
|||
|
LsaViewCopiedCommandParams;
|
|||
|
|
|||
|
CommandMessage.MessageHeader.u1.s1.TotalLength =
|
|||
|
((CSHORT) RM_COMMAND_MESSAGE_HEADER_SIZE +
|
|||
|
(CSHORT) sizeof( LsaViewCopiedCommandParams ));
|
|||
|
CommandMessage.MessageHeader.u1.s1.DataLength =
|
|||
|
CommandMessage.MessageHeader.u1.s1.TotalLength -
|
|||
|
(CSHORT) sizeof(PORT_MESSAGE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free input command params buffer if Paged Pool.
|
|||
|
//
|
|||
|
|
|||
|
if (WorkQueueItem->CommandParamsMemoryType == SepRmPagedPoolMemory) {
|
|||
|
|
|||
|
ExFreePool( WorkQueueItem->CommandParams.BaseAddress );
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
Status = STATUS_INVALID_PARAMETER;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Send Message to the LSA via the LSA Server Command LPC Port.
|
|||
|
// This must be done in the process in which the handle was created.
|
|||
|
//
|
|||
|
|
|||
|
Status = ZwRequestWaitReplyPort(
|
|||
|
SepRmState.LsaCommandPortHandle,
|
|||
|
(PPORT_MESSAGE) &CommandMessage,
|
|||
|
(PPORT_MESSAGE) &ReplyMessage
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// If the command was successful, copy the data back to the output
|
|||
|
// buffer.
|
|||
|
//
|
|||
|
|
|||
|
if (NT_SUCCESS(Status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Move output from command (if any) to buffer. Note that this
|
|||
|
// is done even if the command returns status, because some status
|
|||
|
// values are not errors.
|
|||
|
//
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(WorkQueueItem->ReplyBuffer)) {
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
WorkQueueItem->ReplyBuffer,
|
|||
|
ReplyMessage.ReplyBuffer,
|
|||
|
WorkQueueItem->ReplyBufferLength
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return status from command.
|
|||
|
//
|
|||
|
|
|||
|
Status = ReplyMessage.ReturnedStatus;
|
|||
|
|
|||
|
if (!NT_SUCCESS(Status)) {
|
|||
|
KdPrint(("Security: Command sent from RM to LSA returned 0x%lx\n",
|
|||
|
Status));
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
KdPrint(("Security: Sending Command RM to LSA failed 0x%lx\n", Status));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// On return from the LPC call to the LSA, we expect the called
|
|||
|
// LSA worker routine to have copied the Command Parameters
|
|||
|
// buffer (if any). If a custom shared memory boffer was allocated,
|
|||
|
// free it now.
|
|||
|
//
|
|||
|
|
|||
|
if (CommandMessage.CommandParamsMemoryType == SepRmLsaCustomSharedMemory) {
|
|||
|
|
|||
|
RegionSize = 0;
|
|||
|
|
|||
|
Status = ZwFreeVirtualMemory(
|
|||
|
SepLsaHandle,
|
|||
|
(PVOID *) &CommandMessage.CommandParams,
|
|||
|
&RegionSize,
|
|||
|
MEM_RELEASE
|
|||
|
);
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(Status));
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Clean up. We must call the cleanup functions on its parameter
|
|||
|
// and then free the used WorkQueueItem itself.
|
|||
|
//
|
|||
|
|
|||
|
if ( ARGUMENT_PRESENT( WorkQueueItem->CleanupFunction)) {
|
|||
|
|
|||
|
(WorkQueueItem->CleanupFunction)(WorkQueueItem->CleanupParameter);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine if there is more work to do on this list
|
|||
|
//
|
|||
|
|
|||
|
WorkQueueItem = SepDequeueWorkItem();
|
|||
|
#if 0
|
|||
|
if ( WorkQueueItem ) {
|
|||
|
DbgPrint("Got another item from list, going back\n");
|
|||
|
} else {
|
|||
|
DbgPrint("List is empty, leaving\n");
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
KeDetachProcess();
|
|||
|
|
|||
|
if ( LocalListLength > SepLsaQueueLength ) {
|
|||
|
SepLsaQueueLength = LocalListLength;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
SepRmInitPhase0(
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function performs Reference Monitor Phase 0 initialization.
|
|||
|
This includes initializing the reference monitor database to a state
|
|||
|
which allows access validation routines to operate (always granting
|
|||
|
access) prior to the main init of the Reference Monitor in Phase 1
|
|||
|
initialization, without having to check if the RM is initialized.
|
|||
|
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - TRUE if successful, else FALSE
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
BOOLEAN CompletionStatus;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
CompletionStatus = SepRmDbInitialization();
|
|||
|
|
|||
|
return CompletionStatus;
|
|||
|
}
|