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

📄 krnlapi.cxx

📁 安全支持提供器接口(SSPI)源码
💻 CXX
📖 第 1 页 / 共 5 页
字号:
//+-------------------------------------------------------------------------
//
//  Function:   NtLmInitKernelContext
//
//  Synopsis:   Creates a kernel-mode context from a packed LSA mode context
//
//  Arguments:  LsaContextHandle - Lsa mode context handle for the context
//              PackedContext - A marshalled buffer containing the LSA
//                  mode context.
//
//  Requires:
//
//  Returns:    STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
//
//  Notes:
//
//--------------------------------------------------------------------------

NTSTATUS NTAPI
NtLmInitKernelContext(
    IN ULONG_PTR LsaContextHandle,
    IN PSecBuffer PackedContext,
    OUT PULONG_PTR NewContextHandle
    )
{

    NTSTATUS Status = STATUS_SUCCESS;
    PNTLM_KERNEL_CONTEXT pContext = NULL;
    unsigned int Length = 0;

    PNTLM_KERNEL_CONTEXT pTmpContext  = (PNTLM_KERNEL_CONTEXT) PackedContext->pvBuffer;

    PAGED_CODE();

    DebugLog(( DEB_TRACE, "Entering NtLmInitKernelContext\n" ));

    *NewContextHandle = NULL;

    if (PackedContext->cbBuffer < sizeof(NTLM_KERNEL_CONTEXT))
    {
        Status = STATUS_INVALID_PARAMETER;
        DebugLog(( DEB_ERROR,
          "Bad size of Packed context 0x%lx\n", PackedContext->cbBuffer));
        goto Cleanup;
    }

    pContext = (PNTLM_KERNEL_CONTEXT) NtLmAllocate( sizeof(NTLM_KERNEL_CONTEXT) );

    if (!pContext)
    {
        Status = STATUS_INSUFFICIENT_RESOURCES;
        DebugLog(( DEB_ERROR, "Allocation error for pContext\n"));
        goto Cleanup;
    }

    RtlZeroMemory(
        pContext,
        sizeof(NTLM_KERNEL_CONTEXT)
        );

    KsecInitializeListEntry( &pContext->List, NTLM_CONTEXT_SIGNATURE );

    // Copy contents of PackedContext->pvBuffer to pContext

    pContext->ClientTokenHandle = pTmpContext->ClientTokenHandle;
    pContext->LsaContext = LsaContextHandle;
    pContext->NegotiateFlags = pTmpContext->NegotiateFlags;

    //
    // keep all 128 bits here, so signing can be strong even if encrypt can't be
    //

    RtlCopyMemory(  pContext->SessionKey,
                        pTmpContext->SessionKey,
                        MSV1_0_USER_SESSION_KEY_LENGTH);

    //
    // if doing full duplex as part of NTLM2, generate different sign
    // and seal keys for each direction
    //  all we do is MD5 the base session key with a different magic constant
    //

    if ( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2 ) {
        MD5_CTX Md5Context;
        ULONG KeyLen;

        ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);

        if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_128 )
            KeyLen = 16;
        else if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_56 )
            KeyLen = 7;
        else
            KeyLen = 5;

//        DebugLog(( SSP_SESSION_KEYS, "NTLMv2 session key size: %lu\n", KeyLen));

        //
        // make client to server encryption key
        //

        MD5Init(&Md5Context);
        MD5Update(&Md5Context, pContext->SessionKey, KeyLen);
        MD5Update(&Md5Context, (unsigned char*)CSSEALMAGIC, sizeof(CSSEALMAGIC));
        MD5Final(&Md5Context);

        //
        // if TokenHandle == NULL, this is the client side
        //  put key in the right place: for client it's seal, for server it's unseal
        //

        if (pContext->ClientTokenHandle == NULL)
            RtlCopyMemory(pContext->SealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
        else
            RtlCopyMemory(pContext->UnsealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);

        //
        // make server to client encryption key
        //

        MD5Init(&Md5Context);
        MD5Update(&Md5Context, pContext->SessionKey, KeyLen);
        MD5Update(&Md5Context, (unsigned char*)SCSEALMAGIC, sizeof(SCSEALMAGIC));
        MD5Final(&Md5Context);
        ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
        if (pContext->ClientTokenHandle == NULL)
            RtlCopyMemory(pContext->UnsealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
        else
            RtlCopyMemory(pContext->SealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);

        //
        // make client to server signing key -- always 128 bits!
        //

        MD5Init(&Md5Context);
        MD5Update(&Md5Context, pContext->SessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
        MD5Update(&Md5Context, (unsigned char*)CSSIGNMAGIC, sizeof(CSSIGNMAGIC));
        MD5Final(&Md5Context);
        if (pContext->ClientTokenHandle == NULL)
            RtlCopyMemory(pContext->SignSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
        else
            RtlCopyMemory(pContext->VerifySessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);

        //
        // make server to client signing key
        //

        MD5Init(&Md5Context);
        MD5Update(&Md5Context, pContext->SessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
        MD5Update(&Md5Context, (unsigned char*)SCSIGNMAGIC, sizeof(SCSIGNMAGIC));
        MD5Final(&Md5Context);
        if (pContext->ClientTokenHandle == NULL)
            RtlCopyMemory(pContext->VerifySessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
        else
            RtlCopyMemory(pContext->SignSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);

        //
        // set pointers to different key schedule and nonce for each direction
        //  key schedule will be filled in later...
        //

        pContext->pSealRc4Sched = &pContext->SealRc4Sched;
        pContext->pUnsealRc4Sched = &pContext->UnsealRc4Sched;
        pContext->pSendNonce = &pContext->SendNonce;
        pContext->pRecvNonce = &pContext->RecvNonce;
   } else {

        //
        // just copy session key to all four keys
        //  leave them 128 bits -- they get cut to 40 bits later
        //

        RtlCopyMemory(  pContext->SealSessionKey,
                        pContext->SessionKey,
                        MSV1_0_USER_SESSION_KEY_LENGTH);
        RtlCopyMemory(  pContext->UnsealSessionKey,
                        pContext->SessionKey,
                        MSV1_0_USER_SESSION_KEY_LENGTH);
        RtlCopyMemory(  pContext->SignSessionKey,
                        pContext->SessionKey,
                        MSV1_0_USER_SESSION_KEY_LENGTH);
        RtlCopyMemory(  pContext->VerifySessionKey,
                        pContext->SessionKey,
                        MSV1_0_USER_SESSION_KEY_LENGTH);

        //
        // set pointers to share a key schedule and nonce for each direction
        //  (OK because half duplex!)
        //

        pContext->pSealRc4Sched = &pContext->SealRc4Sched;
        pContext->pUnsealRc4Sched = &pContext->SealRc4Sched;
        pContext->pSendNonce = &pContext->SendNonce;
        pContext->pRecvNonce = &pContext->SendNonce;
    }


    Length = (unsigned int) (PackedContext->cbBuffer -
                             sizeof(NTLM_KERNEL_CONTEXT));

    if (Length == 0)
    {
        //There's no string after the NTLM_KERNEL_CONTEXT struct
        pContext->ContextNames = NULL;
    }
    else
    {
        pContext->ContextNames = (LPWSTR) NtLmAllocate(Length + sizeof(WCHAR));

        if (!pContext->ContextNames)
        {
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto Cleanup;
        }

        RtlCopyMemory(pContext->ContextNames,
                      pTmpContext + 1,
                      Length );

        // null terminate the string

        *(pContext->ContextNames + (Length/sizeof(WCHAR))) = L'\0';
    }

    pContext->SendNonce = pTmpContext->SendNonce;
    pContext->RecvNonce = pTmpContext->RecvNonce;

    SspRc4Key(pContext->NegotiateFlags, &pContext->SealRc4Sched, pContext->SealSessionKey);
    SspRc4Key(pContext->NegotiateFlags, &pContext->UnsealRc4Sched, pContext->UnsealSessionKey);


    pContext->PasswordExpiry = pTmpContext->PasswordExpiry;
    pContext->UserFlags = pTmpContext->UserFlags;

    KSecInsertListEntry(
            NtlmActiveList,
            &pContext->List );

    NtlmDerefContext( pContext );

    *NewContextHandle = (ULONG_PTR) pContext;

Cleanup:

    if (!NT_SUCCESS(Status))
    {
        if (pContext != NULL)
        {
            NtlmFreeKernelContext( pContext );
        }
    }

    if (PackedContext->pvBuffer != NULL)
    {
        LsaKernelFunctions->FreeHeap(PackedContext->pvBuffer);
        PackedContext->pvBuffer = NULL;
    }

    DebugLog(( DEB_TRACE, "Leaving NtLmInitKernelContext 0x%lx\n", Status ));
    return(Status);
}


//+-------------------------------------------------------------------------
//
//  Function:   NtLmMapKernelHandle
//
//  Synopsis:   Maps a kernel handle into an LSA handle
//
//  Arguments:  KernelContextHandle - Kernel context handle of the context to map
//              LsaContextHandle - Receives LSA context handle of the context
//                      to map
//
//  Returns:    STATUS_SUCCESS on success
//
//  Notes:
//
//--------------------------------------------------------------------------

NTSTATUS NTAPI
NtLmMapKernelHandle(
    IN ULONG_PTR KernelContextHandle,
    OUT PULONG_PTR LsaContextHandle
    )
{

    NTSTATUS Status = STATUS_SUCCESS;
    PNTLM_KERNEL_CONTEXT Context = NULL;

    PAGED_CODE();

    DebugLog((DEB_TRACE,"Entering NtLmMapKernelhandle\n"));

    Status = NtlmReferenceContext( KernelContextHandle, FALSE );

    if ( NT_SUCCESS( Status ) )
    {
        Context = (PNTLM_KERNEL_CONTEXT) KernelContextHandle ;

        *LsaContextHandle = Context->LsaContext ;

        NtlmDerefContext( Context );

    }
    else
    {
        DebugLog(( DEB_WARN, "Invalid context handle - %x\n",
                    KernelContextHandle ));
        *LsaContextHandle = KernelContextHandle ;
    }

    DebugLog((DEB_TRACE,"Leaving NtLmMapKernelhandle 0x%lx\n", Status));

    return (Status);
}


//
// Bogus add-shift check sum
//

void
SspGenCheckSum(
    IN  PSecBuffer  pMessage,
    OUT PNTLMSSP_MESSAGE_SIGNATURE  pSig
    )

/*++

RoutineDescription:

    Generate a crc-32 checksum for a buffer

Arguments:

Return Value:
Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
       routine SspGenCheckSum. It's possible that
       bugs got copied too

--*/

{
    MAYBE_PAGED_CODE();

    Crc32(pSig->CheckSum,pMessage->cbBuffer,pMessage->pvBuffer,&pSig->CheckSum);
}


VOID
SspEncryptBuffer(
    IN PNTLM_KERNEL_CONTEXT pContext,
    IN struct RC4_KEYSTRUCT * pRc4Key,
    IN ULONG BufferSize,
    IN OUT PVOID Buffer
    )

/*++

RoutineDescription:

    Encrypts a buffer with the RC4 key in the context.  If the context
    is for a datagram session, then the key is copied before being used
    to encrypt the buffer.

Arguments:

    pContext - Context containing the key to encrypt the data

    BufferSize - Length of buffer in bytes

    Buffer - Buffer to encrypt.
    Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
           routine SspEncryptBuffer. It's possible that
           bugs got copied too

Return Value:

--*/

{
    MAYBE_PAGED_CODE();

    struct RC4_KEYSTRUCT TemporaryKey;
    struct RC4_KEYSTRUCT * EncryptionKey = pRc4Key;

    if (BufferSize == 0)
    {
        return;
    }

    //
    // For datagram (application supplied sequence numbers) before NTLM2
    // we used to copy the key before encrypting so we don't
    // have a changing key; but that reused the key stream. Now we only
    // do that when backwards compatibility is explicitly called for.
    //

    if (((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) != 0) &&
        ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) == 0) ) {

        RtlCopyMemory(
            &TemporaryKey,
            EncryptionKey,
            sizeof(TemporaryKey)
            );
        EncryptionKey = &TemporaryKey;

    }

    rc4(
        EncryptionKey,
        BufferSize,
        (PUCHAR) Buffer
        );

}


VOID
SspRc4Key(
    IN ULONG                NegotiateFlags,
    OUT struct RC4_KEYSTRUCT *pRc4Key,
    IN PUCHAR               pSessionKey
    )
/*++

RoutineDescription:

    Create an RC4 key schedule, making sure key length is OK for export

Arguments:

    NegotiateFlags  negotiate feature flags; NTLM2 bit is only one looked at
    pRc4Key         pointer to RC4 key schedule structure; filled in by this routine
    pSessionKey     pointer to session key -- must be full 16 bytes

Return Value:

--*/
{
    PAGED_CODE();

    //
    // For NTLM2, effective length was already cut down
    //

    if ((NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) != 0) {

        rc4_key(pRc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pSessionKey);

    } else if( NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY ) {
        UCHAR Key[MSV1_0_LANMAN_SESSION_KEY_LENGTH];
        ULONG KeyLen;

        ASSERT(MSV1_0_LANMAN_SESSION_KEY_LENGTH == 8);

        // prior to Win2k, negotiated key strength had no bearing on
        // key size.  So, to allow proper interop to NT4, we don't
        // worry about 128bit.  56bit and 40bit are the only supported options.

⌨️ 快捷键说明

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