⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nlmain.c

📁 安全支持提供器接口(SSPI)源码
💻 C
📖 第 1 页 / 共 5 页
字号:
        NlpSamInitialized = TRUE;
    }

    LeaveCriticalSection(&NtLmGlobalCritSect);


Cleanup:

    if ( PrimaryDomainName.Buffer != NULL ) {
        RtlFreeHeap( MspHeap, 0, PrimaryDomainName.Buffer );
    }

    if ( SamDomainName.Buffer != NULL ) {
        RtlFreeHeap( MspHeap, 0, SamDomainName.Buffer );
    }

    if ( SamDomainHandle != NULL ) {
        (VOID) I_SamrCloseHandle( &SamDomainHandle );
    }

    if ( SamDomainId != NULL ) {
        RtlFreeHeap( MspHeap, 0, SamDomainId );
    }

    if (PolicyHandle != NULL) {
        (VOID) I_LsarClose( &PolicyHandle );
    }

    if ( PolicyAccountDomainInfo != NULL ) {
        I_LsaIFree_LSAPR_POLICY_INFORMATION( PolicyAccountDomainInformation,
                                             PolicyAccountDomainInfo );
    }

    if ( PolicyPrimaryDomainInfo != NULL ) {
        I_LsaIFree_LSAPR_POLICY_INFORMATION( PolicyPrimaryDomainInformation,
                                             PolicyPrimaryDomainInfo );
    }

    if ( SamHandle != NULL ) {
        (VOID) I_SamrCloseHandle( &SamHandle );
    }


    return Status;

}



NTSTATUS
MspLm20Challenge (
    IN PLSA_CLIENT_REQUEST ClientRequest,
    IN PVOID ProtocolSubmitBuffer,
    IN PVOID ClientBufferBase,
    IN ULONG SubmitBufferSize,
    OUT PVOID *ProtocolReturnBuffer,
    OUT PULONG ReturnBufferSize,
    OUT PNTSTATUS ProtocolStatus
    )

/*++

Routine Description:

    This routine is the dispatch routine for LsaCallAuthenticationPackage()
    with a message type of MsV1_0Lm20ChallengeRequest.  It is called by
    the LanMan server to determine the Challenge to pass back to a
    redirector trying to establish a connection to the server.  The server
    is responsible remembering this Challenge and passing in back to this
    authentication package on a subsequent MsV1_0Lm20Logon request.

Arguments:

    The arguments to this routine are identical to those of LsaApCallPackage.
    Only the special attributes of these parameters as they apply to
    this routine are mentioned here.

Return Value:

    STATUS_SUCCESS - Indicates the service completed successfully.

    STATUS_QUOTA_EXCEEDED -  This error indicates that the logon
        could not be completed because the client does not have
        sufficient quota to allocate the return buffer.




--*/

{
    NTSTATUS Status;
    PMSV1_0_LM20_CHALLENGE_REQUEST ChallengeRequest;
    PMSV1_0_LM20_CHALLENGE_RESPONSE ChallengeResponse;
    CLIENT_BUFFER_DESC ClientBufferDesc;

/*
    ULONG Seed[2];
    CYPHER_BLOCK Challenge;
*/

    UNREFERENCED_PARAMETER( ClientBufferBase );

    ASSERT( sizeof(LM_CHALLENGE) == MSV1_0_CHALLENGE_LENGTH );
/*
    ASSERT( sizeof(LM_CHALLENGE) == sizeof(CYPHER_BLOCK) );
*/
    NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );

    //
    // Ensure the specified Submit Buffer is of reasonable size and
    // relocate all of the pointers to be relative to the LSA allocated
    // buffer.
    //

    if ( SubmitBufferSize < sizeof(MSV1_0_LM20_CHALLENGE_REQUEST) ) {
        Status = STATUS_INVALID_PARAMETER;
        goto Cleanup;
    }

    ChallengeRequest = (PMSV1_0_LM20_CHALLENGE_REQUEST) ProtocolSubmitBuffer;

    ASSERT( ChallengeRequest->MessageType == MsV1_0Lm20ChallengeRequest );

    //
    // Allocate a buffer to return to the caller.
    //

    *ReturnBufferSize = sizeof(MSV1_0_LM20_CHALLENGE_RESPONSE);

    Status = NlpAllocateClientBuffer( &ClientBufferDesc,
                                      sizeof(MSV1_0_LM20_CHALLENGE_RESPONSE),
                                      *ReturnBufferSize );


    if ( !NT_SUCCESS( Status ) ) {
        goto Cleanup;
    }

    ChallengeResponse = (PMSV1_0_LM20_CHALLENGE_RESPONSE) ClientBufferDesc.MsvBuffer;

    //
    // Fill in the return buffer.
    //

    ChallengeResponse->MessageType = MsV1_0Lm20ChallengeRequest;

    //
    // Compute a random seed.
    //

    Status = SspGenerateRandomBits(
                    ChallengeResponse->ChallengeToClient,
                    MSV1_0_CHALLENGE_LENGTH
                    );

    if ( !NT_SUCCESS( Status ) ) {
        goto Cleanup;
    }

    //
    // Flush the buffer to the client's address space.
    //

    Status = NlpFlushClientBuffer( &ClientBufferDesc,
                                   ProtocolReturnBuffer );


Cleanup:

    //
    // If we weren't successful, free the buffer in the clients address space.
    //

    if ( !NT_SUCCESS(Status) ) {
        NlpFreeClientBuffer( &ClientBufferDesc );
    }

    //
    // Return status to the caller.
    //

    *ProtocolStatus = Status;
    return STATUS_SUCCESS;

}

#define NULL_SESSION_REQUESTED RETURN_RESERVED_PARAMETER

NTSTATUS
MspLm20GetChallengeResponse (
    IN PLSA_CLIENT_REQUEST ClientRequest,
    IN PVOID ProtocolSubmitBuffer,
    IN PVOID ClientBufferBase,
    IN ULONG SubmitBufferSize,
    OUT PVOID *ProtocolReturnBuffer,
    OUT PULONG ReturnBufferSize,
    OUT PNTSTATUS ProtocolStatus
    )

/*++

Routine Description:

    This routine is the dispatch routine for LsaCallAuthenticationPackage()
    with a message type of MsV1_0Lm20GetChallengeResponse.  It is called by
    the LanMan redirector to determine the Challenge Response to pass to a
    server when trying to establish a connection to the server.

    This routine is passed a Challenge from the server.  This routine encrypts
    the challenge with either the specified password or with the password
    implied by the specified Logon Id.

    Two Challenge responses are returned.  One is based on the Unicode password
    as given to the Authentication package.  The other is based on that
    password converted to a multi-byte character set (e.g., ASCII) and upper
    cased.  The redirector should use whichever (or both) challenge responses
    as it needs them.

Arguments:

    The arguments to this routine are identical to those of LsaApCallPackage.
    Only the special attributes of these parameters as they apply to
    this routine are mentioned here.

Return Value:

    STATUS_SUCCESS - Indicates the service completed successfully.

    STATUS_QUOTA_EXCEEDED -  This error indicates that the logon
        could not be completed because the client does not have
        sufficient quota to allocate the return buffer.

--*/

{
    NTSTATUS Status;
    PMSV1_0_GETCHALLENRESP_REQUEST GetRespRequest;

    CLIENT_BUFFER_DESC ClientBufferDesc;
    PMSV1_0_GETCHALLENRESP_RESPONSE GetRespResponse;

    PMSV1_0_PRIMARY_CREDENTIAL Credential = NULL;
    PMSV1_0_PRIMARY_CREDENTIAL PrimaryCredential = NULL;
    MSV1_0_PRIMARY_CREDENTIAL BuiltCredential;

    //
    // Responses to return to the caller.
    //
    LM_RESPONSE LmResponse;
    STRING LmResponseString;

    NT_RESPONSE NtResponse;
    STRING NtResponseString;

    PMSV1_0_NTLM3_RESPONSE pNtlm3Response = NULL;

    UNICODE_STRING UserName;
    UNICODE_STRING LogonDomainName;
    USER_SESSION_KEY UserSessionKey;
    UCHAR LanmanSessionKey[MSV1_0_LANMAN_SESSION_KEY_LENGTH];

    UCHAR ChallengeToClient[MSV1_0_CHALLENGE_LENGTH];
    UCHAR ChallengeFromClient[MSV1_0_CHALLENGE_LENGTH];
    ULONG NtLmProtocolSupported;

    //
    // Initialization
    //

    NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );

    RtlInitUnicodeString( &UserName, NULL );
    RtlInitUnicodeString( &LogonDomainName, NULL );

    RtlZeroMemory( &UserSessionKey, sizeof(UserSessionKey) );
    RtlZeroMemory( LanmanSessionKey, sizeof(LanmanSessionKey) );

    //
    // If no credentials are associated with the client, a null session
    // will be used.  For a downlevel server, the null session response is
    // a 1-byte null string (\0).  Initialize LmResponseString to the
    // null session response.
    //

    RtlInitString( &LmResponseString, "" );
    LmResponseString.Length = 1;

    //
    // Initialize the NT response to the NT null session credentials,
    // which are zero length.
    //

    RtlInitString( &NtResponseString, NULL );

    //
    // Ensure the specified Submit Buffer is of reasonable size and
    // relocate all of the pointers to be relative to the LSA allocated
    // buffer.
    //

    if ( SubmitBufferSize < sizeof(MSV1_0_GETCHALLENRESP_REQUEST_V1) ) {
        Status = STATUS_INVALID_PARAMETER;
        goto Cleanup;
    }

    GetRespRequest = (PMSV1_0_GETCHALLENRESP_REQUEST) ProtocolSubmitBuffer;

    ASSERT( GetRespRequest->MessageType == MsV1_0Lm20GetChallengeResponse );

    if ( (GetRespRequest->ParameterControl & USE_PRIMARY_PASSWORD) == 0 ) {
        RELOCATE_ONE( &GetRespRequest->Password );
    }



    //
    // If we don't support the request (such as the caller is asking for an
    // LM challenge response and we do't support it, return an error here.
    //

    NtLmProtocolSupported = NtLmGlobalLmProtocolSupported;

    if( (GetRespRequest->ParameterControl & RETURN_NON_NT_USER_SESSION_KEY) &&
        NtLmProtocolSupported == NoLm ) {

        Status = STATUS_NOT_SUPPORTED;
        goto Cleanup;
    }

    //
    // if caller wants NTLM++, so be it...
    //

    if ( (GetRespRequest->ParameterControl & GCR_NTLM3_PARMS) ) {
        PMSV1_0_AV_PAIR pAV;

        UCHAR TargetInfoBuffer[3*sizeof(MSV1_0_AV_PAIR) + (DNS_MAX_NAME_LENGTH+CNLEN+2)*sizeof(WCHAR)];

        NULL_RELOCATE_ONE( &GetRespRequest->UserName );
        NULL_RELOCATE_ONE( &GetRespRequest->LogonDomainName );
        NULL_RELOCATE_ONE( &GetRespRequest->ServerName );

        //
        // if no target provided and we're config'd to use NTLMv2, then complain
        //

        if ((NtLmProtocolSupported >= UseNtlm3) &&
            (GetRespRequest->ServerName.Length == 0)) {
            Status = STATUS_INVALID_PARAMETER;
            goto Cleanup;
        }

        // if target is just a domain name or domain name followed by
        //  server name, make it into an AV pair list
        if (!(GetRespRequest->ParameterControl & GCR_TARGET_INFO)) {
            UNICODE_STRING DomainName;
            UNICODE_STRING ServerName;
            unsigned int i;

            //
            // check length of name to make sure it fits in my buffer
            //

            if (GetRespRequest->ServerName.Length > (DNS_MAX_NAME_LENGTH+CNLEN+2)*sizeof(WCHAR)) {
                Status = STATUS_INVALID_PARAMETER;
                goto Cleanup;
            }

            //
            // init AV list in temp buffer
            //

            pAV = MsvpAvlInit(TargetInfoBuffer);

            //
            // see if there's a NULL in the middle of the server name
            //  that indicates that it's really a domain name followed by a server name
            //

            DomainName = GetRespRequest->ServerName;
            ServerName.Length = 0;

            for (i = 0; i < (DomainName.Length/sizeof(WCHAR)); i++) {
                if (DomainName.Buffer[i] == 0) {
                    // take length of domain name without the NULL
                    DomainName.Length = (USHORT) i*sizeof(WCHAR);
                    // adjust server name and length to point after the domain name
                    ServerName.Length = GetRespRequest->ServerName.Length - (i+1)*sizeof(WCHAR);
                    ServerName.Buffer = GetRespRequest->ServerName.Buffer + (i+1);
                    break;
                }
            }

            //
            // strip off possible trailing null after the server name
            //

            for (i = 0; i < (ServerName.Length / sizeof(WCHAR)); i++) {
                if (ServerName.Buffer[i] == 0) {
                    ServerName.Length = (USHORT)i*sizeof(WCHAR);
                    break;
                }
            }

            //
            // put both names in the AV list (if both exist)
            //

            MsvpAvlAdd(pAV, MsvAvNbDomainName, &DomainName, sizeof(TargetInfoBuffer));
            if (ServerName.Length > 0) {
                MsvpAvlAdd(pAV, MsvAvNbComputerName, &ServerName, sizeof(TargetInfoBuffer));
            }

            //
            // make the request point at AV list instead of names.
            //

            GetRespRequest->ServerName.Length = (USHORT)MsvpAvlLen(pAV, sizeof(TargetInfoBuffer));
            GetRespRequest->ServerName.Buffer = (PWCHAR)pAV;
        }

        //
        // if we're only using NTLMv2 or better, then complain if either
        //  computer name or server name missing
        //

        if (NtLmProtocolSupported >= RefuseNtlm3NoTarget) {
            pAV = (PMSV1_0_AV_PAIR)GetRespRequest->ServerName.Buffer;
            if (MsvpAvlGet(pAV, MsvAvNbDomainName, GetRespRequest->ServerName.Length) == NULL ||
                MsvpAvlGet(pAV, MsvAvNbComputerName, GetRespRequest->ServerName.Length) == NULL) {
                Status = STATUS_INVALID_PARAMETER;
                goto Cleanup;
            }
        }
    }


    //
    // If the caller wants information from the credentials of a specified
    //  LogonId, get those credentials from the LSA.
    //
    // If there are no such credentials,
    //  tell the caller to use the NULL session.
    //

#define PRIMARY_CREDENTIAL_NEEDED \
        (RETURN_PRIMARY_LOGON_DOMAINNAME | \
        RETURN_PRIMARY_USERNAME | \
        USE_PRIMARY_PASSWORD )

    if ( ((GetRespRequest->ParameterControl & PRIMARY_CREDENTIAL_NEEDED) != 0 ) && ((GetRespRequest->ParameterControl & NULL_SESSION_REQUESTED) == 0)) {

        Status = NlpGetPrimaryCredential(
                        &GetRespRequest->LogonId,
                        &PrimaryCredential,
                        NULL );

        if ( NT_SUCCESS(Status) ) {

            if ( GetRespRequest->ParameterControl & RETURN_PRIMARY_USERNAME ) {
                UserName = PrimaryCredential->UserName;
            }

            if ( GetRespRequest->ParameterControl &
                 RETURN_PRIMARY_LOGON_DOMAINNAME ) {

#ifndef DONT_MAP_DOMAIN_ON_REQUEST

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -