Пример #1
0
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.RmCommandPortHandle,
                 &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;

/* BugWarning - ScottBi - probably don't need the resource

    //
    // Create the resource serializing access to the port.  This
    // resource prevents the port and the shared memory from being
    // deleted while worker threads are processing requests.
    //

    if ( !SepRmState.LsaCommandPortResourceInitialized ) {

        ExInitializeResource( &SepRmState.LsaCommandPortResource );
        SepRmState.LsaCommandPortResourceInitialized = TRUE;
    }

    SepRmState.LsaCommandPortActive = TRUE;

*/

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;
}
Пример #2
0
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 ||
                Status == STATUS_INVALID_CID ||
                Status == STATUS_REPLY_MESSAGE_MISMATCH)
            {
                //
                // 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 );

}