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

📄 nlpcache.c

📁 安全支持提供器接口(SSPI)源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    //
    //      A handle to the LsaPolicy object will be open (NlpLsaHandle).
    //
    //      A handle to the registry key in which all cache entries
    //      are held will be open (NlpCacheHandle).
    //
    //      A global structure defining how many cache entries there are
    //      will be initialized (NlpCacheControl).
    //
    //      The Cache Table Entry table (CTE table) will be initialized
    //      (NlpCteTable).
    //
    //      The active and inactive CTE lists will be built
    //      (NlpActiveCtes and NlpInactiveCtes).
    //
    //      A global cache encryption key will be initialized.
    //



    ENTER_CACHE();

    //
    // Check again if the cache is initialized now that the crit sect is locked.
    //

    if (NlpInitializationNotYetPerformed) {

        //
        // Open the local system's policy object
        //

        InitializeObjectAttributes(&ObjectAttributes,
                                   NULL,   // name
                                   0,
                                   0,
                                   NULL
                                   );
        NtStatus = I_LsaIOpenPolicyTrusted( &NlpLsaHandle );
        if (NT_SUCCESS(NtStatus)) {

            //
            // Successfully, or unsucessfully,
            // The definition of "initialized" is we could call LSA's RPC
            // routines.
            //

            NlpInitializationNotYetPerformed = FALSE;

            //
            // Open the registry key containing cache entries.
            // This will remain open.
            //

            NtStatus = NlpOpenCache();

            if (NT_SUCCESS(NtStatus)) {

                //
                // Get information on the current cache structure
                // (number of entries, et cetera).  This information is
                // placed in a global variable for use throughout this
                // module.
                //

                NtStatus = NlpGetCacheControlInfo();

                //
                // Initialize the per-machine cache encryption key.
                //

                if(NT_SUCCESS( NtStatus) ) {
                    NtStatus = NlpCacheKeyInitialize();
                }

                //
                // Now build the CTE table
                //

                if (NT_SUCCESS(NtStatus)) {
                    NtStatus = NlpBuildCteTable();
                }

                //
                // If we were successful, then see if we need to change
                // the cache due to new user-specified cache size.
                //

                if (NT_SUCCESS(NtStatus)) {
                    NtStatus = NlpChangeCacheSizeIfNecessary();
                }

                if (!NT_SUCCESS(NtStatus)) {
                    NlpCloseCache();
                }
            }

            if (!NT_SUCCESS(NtStatus)) {
                I_LsarClose( &NlpLsaHandle );
            }
        }

        //
        // If we had an error, then set our entry count to zero
        // to prevent using any cache information.
        //

        if (!NT_SUCCESS(NtStatus)) {
            NlpCacheControl.Entries = 0;
        }

    } else {
        NtStatus = STATUS_SUCCESS;
    }

    LEAVE_CACHE();

    return(NtStatus);
}


NTSTATUS
NlpCacheKeyInitialize(
    VOID
    )
/*++

Routine Description:

    Initializes the Global variable NlpCacheEncryptionKey with a per-machine
    cache encryption key.  If the per-machine key does not exist as an LSA
    secret, it is created.

--*/
{
    LSAPR_HANDLE SecretHandle;
    UNICODE_STRING ValueName;
    BOOLEAN SecretCreationNeeded = FALSE;
    NTSTATUS NtStatus;

    RtlInitUnicodeString( &ValueName, NLP_CACHE_ENCRYPTION_KEY_NAME );

    NtStatus = I_LsarOpenSecret(NlpLsaHandle,
                             (PLSAPR_UNICODE_STRING) &ValueName,
                             SECRET_QUERY_VALUE | SECRET_SET_VALUE,
                             &SecretHandle
                             );

    if (!NT_SUCCESS(NtStatus)) {

        //
        // create new key, if not present.
        //

        if (NtStatus != STATUS_OBJECT_NAME_NOT_FOUND) {
            return (NtStatus);
        }

        NtStatus = I_LsarCreateSecret(NlpLsaHandle,
                                   (PLSAPR_UNICODE_STRING) &ValueName,
                                   SECRET_SET_VALUE,
                                   &SecretHandle
                                   );

        if (!NT_SUCCESS(NtStatus)) {
            return (NtStatus);
        }

        SecretCreationNeeded = TRUE;

    } else {

        //
        // query current value...
        //

        LARGE_INTEGER
            CurrentTime;

        PLSAPR_CR_CIPHER_VALUE CurrentSecret = NULL;

        NtStatus = I_LsarQuerySecret(SecretHandle,
                                  &CurrentSecret,
                                  &CurrentTime,
                                  NULL,
                                  NULL
                                  );

        if(NT_SUCCESS( NtStatus ) ) {
            if( CurrentSecret == NULL ) {

                //
                // non existing data, create it.
                //

                SecretCreationNeeded = TRUE;
            } else {

                //
                // size of data is wrong, bail now and leave things as-is.
                //

                if( CurrentSecret->Length != sizeof( NlpCacheEncryptionKey ) ) {
                    NtStatus = STATUS_SECRET_TOO_LONG;
                } else {

                    //
                    // capture existing data into global.
                    //

                    CopyMemory( NlpCacheEncryptionKey, CurrentSecret->Buffer, CurrentSecret->Length );
                }

                MIDL_user_free(CurrentSecret);
            }
        }
    }


    if( SecretCreationNeeded ) {
        LSAPR_CR_CIPHER_VALUE SecretValue;

        SspGenerateRandomBits( NlpCacheEncryptionKey, sizeof(NlpCacheEncryptionKey) );

        //
        // write out secret...
        //

        SecretValue.Length = sizeof(NlpCacheEncryptionKey);
        SecretValue.MaximumLength = SecretValue.Length;
        SecretValue.Buffer = (PBYTE)NlpCacheEncryptionKey;

        NtStatus = I_LsarSetSecret(SecretHandle,
                                &SecretValue,
                                NULL
                                );

    }


    I_LsarClose( &SecretHandle );

    return (NtStatus);
}


NTSTATUS
NlpEncryptCacheEntry(
    IN  PLOGON_CACHE_ENTRY CacheEntry,
    IN  ULONG EntrySize
    )
/*++

Routine Description:

    Encrypts the sensitive portions of the input CacheEntry.

--*/
{
    HMACMD5_CTX hmacCtx;
    RC4_KEYSTRUCT rc4key;
    CHAR DerivedKey[ MD5DIGESTLEN ];

    PBYTE pbData;
    ULONG cbData;

    if( CacheEntry->Revision < NLP_CACHE_REVISION_NT_5_0 ) {
        return STATUS_SUCCESS;
    }


    //
    // derive encryption key from global machine LSA secret, and random
    // cache entry key.
    //

    HMACMD5Init(&hmacCtx, NlpCacheEncryptionKey, sizeof(NlpCacheEncryptionKey));
    HMACMD5Update(&hmacCtx, CacheEntry->RandomKey, sizeof(CacheEntry->RandomKey));
    HMACMD5Final(&hmacCtx, DerivedKey);


    //
    // begin encrypting at the cachepasswords field.
    //

    pbData = (PBYTE)&(CacheEntry->CachePasswords);

    //
    // data length is EntrySize - header up to CachePasswords.
    //

    cbData = EntrySize - (ULONG)( pbData - (PBYTE)CacheEntry );


    //
    // MAC the data for integrity checking.
    //

    HMACMD5Init(&hmacCtx, DerivedKey, sizeof(DerivedKey));
    HMACMD5Update(&hmacCtx, pbData, cbData);
    HMACMD5Final(&hmacCtx, CacheEntry->MAC);

    //
    // now encrypt it...
    //

    rc4_key( &rc4key, sizeof(DerivedKey), DerivedKey );
    rc4( &rc4key, cbData, pbData );

    ZeroMemory( DerivedKey, sizeof(DerivedKey) );

    return STATUS_SUCCESS;
}


NTSTATUS
NlpDecryptCacheEntry(
    IN  PLOGON_CACHE_ENTRY CacheEntry,
    IN  ULONG EntrySize
    )
/*++

Routine Description:

    Decrypts the sensitive portions of the input CacheEntry, and verified
    integrity of decrypted data.

--*/
{
    HMACMD5_CTX hmacCtx;
    RC4_KEYSTRUCT rc4key;
    CHAR DerivedKey[ MD5DIGESTLEN ];

    CHAR MAC[ MD5DIGESTLEN ];

    PBYTE pbData;
    ULONG cbData;

    if( CacheEntry->Revision < NLP_CACHE_REVISION_NT_5_0 ) {
        return STATUS_SUCCESS;
    }


    //
    // derive encryption key from global machine LSA secret, and random
    // cache entry key.
    //

    HMACMD5Init(&hmacCtx, NlpCacheEncryptionKey, sizeof(NlpCacheEncryptionKey));
    HMACMD5Update(&hmacCtx, CacheEntry->RandomKey, sizeof(CacheEntry->RandomKey));
    HMACMD5Final(&hmacCtx, DerivedKey);


    //
    // begin decrypting at the cachepasswords field.
    //

    pbData = (PBYTE)&(CacheEntry->CachePasswords);

    //
    // data length is EntrySize - header up to CachePasswords.
    //

    cbData = EntrySize - (ULONG)( pbData - (PBYTE)CacheEntry );

    //
    // now decrypt it...
    //

    rc4_key( &rc4key, sizeof(DerivedKey), DerivedKey );
    rc4( &rc4key, cbData, pbData );


    //
    // compute MAC on decrypted data for integrity checking.
    //

    HMACMD5Init(&hmacCtx, DerivedKey, sizeof(DerivedKey));
    HMACMD5Update(&hmacCtx, pbData, cbData);
    HMACMD5Final(&hmacCtx, MAC);

    ZeroMemory( DerivedKey, sizeof(DerivedKey) );


    //
    // verify MAC.
    //

    if( memcmp( MAC, CacheEntry->MAC, sizeof(MAC) ) != 0 ) {
        return STATUS_LOGON_FAILURE;
    }


    return STATUS_SUCCESS;
}




NTSTATUS
NlpBuildCacheEntry(
    IN  PNETLOGON_INTERACTIVE_INFO LogonInfo,
    IN  PNETLOGON_VALIDATION_SAM_INFO2 AccountInfo,
    OUT PLOGON_CACHE_ENTRY* ppCacheEntry,
    OUT PULONG pEntryLength
    )

/*++

Routine Description:

    Builds a LOGON_CACHE_ENTRY from a NETLOGON_VALIDATION_SAM_INFO2 structure.
    We only cache those fields that we cannot easily re-invent

Arguments:

    LogonInfo       - pointer to NETLOGON_INTERACTIVE_INFO structure containing
                      user's name and logon domain name

    AccountInfo     - pointer to NETLOGON_VALIDATION_SAM_INFO2 from successful
                      logon

    ppCacheEntry    - pointer to place to return pointer to allocated
                      LOGON_CACHE_ENTRY

    pEntryLength    - size of the buffer returned in *ppCacheEntry

Return Value:

    NTSTATUS
        Success = STATUS_SUCCESS
                    *ppCacheEntry contains pointer to allocated LOGON_CACHE_ENTRY
                    structure

        Failure = STATUS_NO_MEMORY
                    *ppCacheEntry undefined

--*/

{
    PLOGON_CACHE_ENTRY pEntry;
    ULONG length;
    PCHAR dataptr;

    UNICODE_STRING SamAccountName;
    UNICODE_STRING NetbiosDomainName;
    UNICODE_STRING DnsDomainName;
    UNICODE_STRING Upn;

    NTSTATUS NtStatus;


    //
    // Grab the various forms of the account name
    //

    NlpGetAccountNames( &LogonInfo->Identity,
                        AccountInfo,
                        &SamAccountName,
                        &NetbiosDomainName,
                        &DnsDomainName,
                        &Upn );

    //
    // assumes GROUP_MEMBERSHIP is integral multiple of DWORDs
    //

    length = ROUND_UP_COUNT(sizeof(LOGON_CACHE_ENTRY), sizeof(ULONG))
                + ROUND_UP_COUNT(NetbiosDomainName.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(SamAccountName.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(DnsDomainName.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(Upn.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(AccountInfo->EffectiveName.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(AccountInfo->FullName.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(AccountInfo->LogonScript.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(AccountInfo->ProfilePath.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(AccountInfo->HomeDirectory.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(AccountInfo->HomeDirectoryDrive.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(AccountInfo->LogonDomainName.Length, sizeof(ULONG))
                + ROUND_UP_COUNT(AccountInfo->GroupCount * sizeof(GROUP_MEMBERSHIP), sizeof(ULONG))
                + ROUND_UP_COUNT(RtlLengthSid(AccountInfo->LogonDomainId), sizeof(ULONG));

    if (AccountInfo->UserFlags & LOGON_EXTRA_SIDS) {
        if (AccountInfo->SidCount) {
            ULONG i;
            length += ROUND_UP_COUNT(AccountInfo->SidCount * sizeof(ULONG), sizeof(ULONG));
            for (i = 0; i < AccountInfo->SidCount ; i++ ) {
                length += ROUND_UP_COUNT(RtlLengthSid(AccountInfo->ExtraSids[i].Sid), sizeof(ULONG));
            }
        }
    }


    pEntry = AllocateCacheEntry(length);
    if (pEntry == NULL) {
        return STATUS_NO_MEMORY;
    }

    RtlZeroMemory( pEntry, length );
    pEntry->Revision = NLP_CACHE_REVISION;
    NtQuerySystemTime( &pEntry->Time );
    pEntry->Valid    = TRUE;
    pEntry->LogonPackage = LogonInfo->Identity.ParameterControl;


    dataptr = (PCHAR)(pEntry + 1);
    *pEntryLength = length;

    ASSERT(!((ULONG_PTR)dataptr & (sizeof(ULONG) - 1)));

    //
    // each of these (unicode) strings and other structures are copied to the
    // end of the fixed LOGON_CACHE_ENTRY structure, each aligned on DWORD
    // boundaries
    //

    length = pEntry->UserNameLength = SamAccountName.Length;
    RtlCopyMemory(dataptr, SamAccountName.Buffer, length);
    dataptr = ROUND_UP_POINTER(dataptr+length, sizeof(ULONG));

⌨️ 快捷键说明

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