/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    auproc.c

Abstract:

    This module provides logon process context management services within the
    LSA subsystem.

Author:

    Jim Kelly (JimK) 11-March-1991

Revision History:

--*/

#include "lsasrvp.h"
#include "ausrvp.h"
#include "adtp.h"




NTSTATUS
LsapValidLogonProcess(
    IN PCLIENT_ID ClientId,
    IN PLSAP_AU_REGISTER_CONNECT_INFO ConnectInfo,
    OUT PLSAP_LOGON_PROCESS *LogonProcessContext
    )

/*++

Routine Description:

    This function checks to see if a calling process qualifies as a logon
    process.  If so, a logon process context is created for the caller and
    returned.

    A logon process must hold the SeTcbPrivilege privilege.  Since there
    is no way to impersonate a connection requestor (that would be way
    too easy), we have to open the client thread and then open that thread's
    token.





Arguments:

    ClientId - Pointer to the client Id of the sender of the logon
        message.  This is used to locate and open the calling thread or
        process.

    ConnectInfo - Authentication port information.

    LogonProcessContext - If the caller is a legitimate logon process,
        this receives a pointer to new logon process context block.

Return Value:

    STATUS_SUCCESS - Indicates the caller is a legitimate logon process
        and a logon process context block is being returned.

    any other value - Indicates the caller is NOT a legitimate logon
        process and a logon process context block is NOT being returned.
        The value returned indicates the reason why the client is not
        acceptable.

--*/

{

    NTSTATUS Status, TempStatus;
    BOOLEAN PrivilegeHeld;
    HANDLE ClientThread, ClientProcess, ClientToken;
    PRIVILEGE_SET Privilege;
    OBJECT_ATTRIBUTES NullAttributes;

    InitializeObjectAttributes( &NullAttributes, NULL, 0, NULL, NULL );

    //
    // Open the client process.  This is needed to:
    //
    //         1) Access the client's virtual memory (to copy arguments),
    //         2) Duplicate token handles into the process,
    //         3) Open the process's token to see if it qualifies as
    //            a logon process.
    //

    Status = NtOpenProcess(
                 &ClientProcess,
                 PROCESS_QUERY_INFORMATION |       // To open primary token
                 PROCESS_VM_OPERATION |            // To allocate memory
                 PROCESS_VM_READ |                 // To read memory
                 PROCESS_VM_WRITE |                // To write memory
                 PROCESS_DUP_HANDLE,               // To duplicate a handle into
                 &NullAttributes,
                 ClientId
                 );
    if ( !NT_SUCCESS(Status) ) {
        return Status;
    }



    //
    // Open the client thread and that thread's token
    //


    Status = NtOpenThread(
                 &ClientThread,
                 THREAD_QUERY_INFORMATION,
                 &NullAttributes,
                 ClientId
                 );
    if ( !NT_SUCCESS(Status) ) {
        TempStatus = NtClose( ClientProcess );
        ASSERT( NT_SUCCESS(TempStatus) );
        return Status;
    }

    Status = NtOpenThreadToken(
                 ClientThread,
                 TOKEN_QUERY,
                 TRUE,
                 &ClientToken
                 );

    TempStatus = NtClose( ClientThread );
    ASSERT( NT_SUCCESS(TempStatus) );

    //
    // Make sure we succeeded in opening the token
    //

    if ( !NT_SUCCESS(Status) ) {
        if ( Status != STATUS_NO_TOKEN ) {
            TempStatus = NtClose( ClientProcess );
            ASSERT( NT_SUCCESS(TempStatus) );
            return Status;

        } else {

            //
            // The thread isn't impersonating...open the process's token.
            //

            Status = NtOpenProcessToken(
                         ClientProcess,
                         TOKEN_QUERY,
                         &ClientToken
                         );


            //
            // Make sure we succeeded in opening the token
            //

            if ( !NT_SUCCESS(Status) ) {
                TempStatus = NtClose( ClientProcess );
                ASSERT( NT_SUCCESS(TempStatus) );
                return Status;
            }

        }

    }

    //
    // OK, we have a token open
    //



    //
    // Check for the privilege to execute this service.
    //

    Privilege.PrivilegeCount = 1;
    Privilege.Control = PRIVILEGE_SET_ALL_NECESSARY;
    Privilege.Privilege[0].Luid = LsapTcbPrivilege;
    Privilege.Privilege[0].Attributes = 0;

    Status = NtPrivilegeCheck(
                 ClientToken,
                 &Privilege,
                 &PrivilegeHeld
                 );
    ASSERT( NT_SUCCESS(Status) );


    //
    // Generate any necessary audits
    //

    TempStatus = NtPrivilegedServiceAuditAlarm (
                     &LsapLsaAuName,
                     &LsapRegisterLogonServiceName,
                     ClientToken,
                     &Privilege,
                     PrivilegeHeld
                     );
    // ASSERT( NT_SUCCESS(TempStatus) );

    TempStatus = NtClose( ClientToken );
    ASSERT( NT_SUCCESS(TempStatus) );

    if ( !PrivilegeHeld ) {
        TempStatus = NtClose( ClientProcess );
        ASSERT( NT_SUCCESS(TempStatus) );
        return STATUS_PRIVILEGE_NOT_HELD;
    }






    //
    // Allocate and fill in a new logon process context.
    //

    (*LogonProcessContext) =
        LsapAllocateLsaHeap( (ULONG)sizeof(LSAP_LOGON_PROCESS) );
    if ( (*LogonProcessContext) == NULL ) {
        TempStatus = NtClose( ClientProcess );
        ASSERT( NT_SUCCESS(TempStatus) );
        return(STATUS_INSUFFICIENT_RESOURCES);
    }

    //
    // Save the handle to the client process.
    // The CommPort field of LogonProcessContext will be filled in
    // when the connection is accepted.
    //

    (*LogonProcessContext)->ClientProcess = ClientProcess;

    //
    // Audit the registration of the logon process
    //

    LsapAdtAuditLogonProcessRegistration( ConnectInfo );

    return(STATUS_SUCCESS);
}

NTSTATUS
LsapAuApiDeregisterLogonProcess(
    IN OUT PLSAP_CLIENT_REQUEST ClientRequest
    )

/*++

Routine Description:

    This function doesn't do anything.  All the interesting
    things are done as a result of dereferencing the client's
    context, and that is done in auloop.c



Arguments:

    ClientRequest - Represents the client's LPC request message and context.
        The request message contains a LSAP_AU_API_MESSAGE message
        block.

Return Value:

    STATUS_SUCCESS - Indicates the service completed successfully.



--*/

{

    return(STATUS_SUCCESS);

}



NTSTATUS
LsapAuRundownLogonProcess(
    PLSAP_LOGON_PROCESS Context
    )

/*++

Routine Description:

    This function performs Logon process rundown.
    It is to be called if a logon process exits without deregistering.

    This function deletes the logon process context specified
    by the caller.


Arguments:

    Context - The context of the logon process to run-down.

Return Value:

    STATUS_SUCCESS - Indicates the service completed successfully.



--*/

{

    NTSTATUS Status;


    //
    // Close the client process and the communication port used
    // to talk with this client.
    //

    Status = NtClose( Context->ClientProcess );
#if DBG
    if (!NT_SUCCESS(Status)) {
        DbgPrint("LsaSrv: Auproc.c - Close of logon process failed, 0x%lx\n", Status);
    }
#endif //DBG
    ASSERT(NT_SUCCESS(Status));

    Status = NtClose( Context->CommPort );
#if DBG
    if (!NT_SUCCESS(Status)) {
        DbgPrint("LsaSrv: Auproc.c - Close of comm port failed, 0x%lx\n", Status);
    }
#endif //DBG
    ASSERT(NT_SUCCESS(Status));


    //
    // And free the client's context block.
    //

    LsaFreeMemory( Context );

    return(Status);

}
