📄 nlpcache.c
字号:
RTL_CRITICAL_SECTION NlpLogonCacheCritSec;
HANDLE NlpCacheHandle = (HANDLE) INVALID_HANDLE_VALUE;
LSAPR_HANDLE NlpLsaHandle = (LSAPR_HANDLE) INVALID_HANDLE_VALUE;
LSAPR_HANDLE NlpSecretHandle = (LSAPR_HANDLE) INVALID_HANDLE_VALUE;
//
// control information about the cache (number of entries, etc).
//
NLP_CACHE_CONTROL NlpCacheControl;
//
// This structure is generated and maintained only in memory.
// It indicates which cache entries are valid and which aren't.
// It also indicates what time each entry was established so we
// know which order to discard them in.
//
// This field is a pointer to an array of CTEs. The number of CTEs
// in the array is in NlpCacheControl.Entries. This structure is
// allocated at initialization time.
//
PNLP_CTE NlpCteTable;
//
// The Cache Table Entries in NlpCteTable are linked on either an
// active or inactive list. The entries on the active list are in
// ascending time order - so the last one on the list is the first
// one to be discarded when a flush is needed to add a new entry.
//
LIST_ENTRY NlpActiveCtes;
LIST_ENTRY NlpInactiveCtes;
//
// global, per-machine key used for encrypting NT_5_0 version cache
// entries.
//
CHAR NlpCacheEncryptionKey[ NLP_CACHE_ENCRYPTION_KEY_LEN ];
#if DBG
#ifdef DUMP_CACHE_INFO
ULONG DumpCacheInfo = 1;
#else
ULONG DumpCacheInfo = 0;
#endif
#endif
////////////////////////////////////////////////////////////////////////
// //
// Services Exported by this module //
// //
////////////////////////////////////////////////////////////////////////
NTSTATUS
NlpCacheInitialize(
VOID
)
/*++
Routine Description:
This routine is called to initialize cached logon processing.
Unfortunately, there isn't much we can do when we are called.
(we can't open LSA, for example). So, defer initialization
until later.
Arguments:
None.
Return Value:
NTSTATUS
--*/
{
return RtlInitializeCriticalSection(&NlpLogonCacheCritSec);
}
NTSTATUS
NlpCacheTerminate(
VOID
)
/*++
Routine Description:
Called when process detaches
Arguments:
None.
Return Value:
NTSTATUS
--*/
{
#if DBG
if (DumpCacheInfo) {
DbgPrint("NlpCacheTerminate\n");
}
#endif
if (!NlpInitializationNotYetPerformed) {
NlpCloseCache();
NlpCloseSecret();
if (IS_VALID_HANDLE(NlpLsaHandle)) {
I_LsarClose( &NlpLsaHandle );
}
if (IS_VALID_HANDLE(NlpCacheHandle)) {
NtClose( NlpCacheHandle );
}
FreeToHeap( NlpCteTable );
}
return RtlDeleteCriticalSection(&NlpLogonCacheCritSec);
}
NTSTATUS
NlpGetCacheEntry(
IN PNETLOGON_LOGON_IDENTITY_INFO LogonInfo,
OUT PNETLOGON_VALIDATION_SAM_INFO2* AccountInfo,
OUT PCACHE_PASSWORDS Passwords,
OUT PVOID *ppSupplementalCacheData OPTIONAL ,
OUT PULONG SupplementalCacheDataLength OPTIONAL
)
/*++
Routine Description:
If the user logging on has information stored in the cache,
then it is retrieved. Also returns the cached password from
'secret' storage
Arguments:
LogonInfo - pointer to NETLOGON_IDENTITY_INFO structure which contains
the domain name, user name for this user
AccountInfo - pointer to NETLOGON_VALIDATION_SAM_INFO2 structure to
receive this user's specific interactive logon information
Passwords - pointer to CACHE_PASSWORDS structure to receive passwords
returned from secret storage
Return Value:
NTSTATUS
Success = STATUS_SUCCESS
*AccountInfo points to a NETLOGON_VALIDATION_SAM_INFO2
structure. This must be freed by caller
*Passwords contain USER_INTERNAL1_INFORMATION structure
which contains NT OWF password and LM OWF password. These
must be used to validate the logon
Failure = STATUS_LOGON_FAILURE
The user logging on isn't in the cache.
--*/
{
NTSTATUS
NtStatus;
PNETLOGON_VALIDATION_SAM_INFO2
SamInfo = NULL;
PLOGON_CACHE_ENTRY
CacheEntry = NULL;
ULONG
EntrySize,
Index;
PLSAPR_CR_CIPHER_VALUE
CurrentSecret = NULL,
OldSecret = NULL;
BOOLEAN fCacheLocked = FALSE;
*AccountInfo = NULL;
if( ppSupplementalCacheData )
*ppSupplementalCacheData = NULL;
#if DBG
if (DumpCacheInfo) {
DbgPrint("NlpGetCacheEntry\n");
DumpLogonInfo(LogonInfo);
}
#endif
if (NlpInitializationNotYetPerformed) {
NtStatus = NlpInternalCacheInitialize();
if (!NT_SUCCESS(NtStatus)) {
return(NtStatus);
}
}
if (NlpCacheControl.Entries == 0) {
return(STATUS_LOGON_FAILURE);
}
ENTER_CACHE();
fCacheLocked = TRUE;
//
// Find the cache entry and open its secret (if found)
//
NtStatus = NlpReadCacheEntry(&LogonInfo->LogonDomainName,
&LogonInfo->UserName,
&Index,
&CacheEntry,
&EntrySize);
if(!NT_SUCCESS(NtStatus)) {
LEAVE_CACHE();
return (NtStatus);
}
if( CacheEntry->Revision >= NLP_CACHE_REVISION_NT_5_0 ) {
//
// for NT5, we can release the cache lock now, since all data
// stored in one place.
//
LEAVE_CACHE();
fCacheLocked = FALSE;
//
// if caller wanted supplemental data, give it to them.
//
if( ppSupplementalCacheData && SupplementalCacheDataLength ) {
*SupplementalCacheDataLength = CacheEntry->SupplementalCacheDataLength;
*ppSupplementalCacheData = MIDL_user_allocate( *SupplementalCacheDataLength );
if( *ppSupplementalCacheData == NULL ) {
NtStatus = STATUS_NO_MEMORY;
} else {
LPBYTE Source;
//
// note: the decrypt operation that occurred during the
// ReadCacheEntry validates any data and pointers through
// integrity checking via HMAC. Having said that, we can be
// lazy and not do boundry checking.
//
Source = ((LPBYTE)CacheEntry + CacheEntry->SupplementalCacheDataOffset);
CopyMemory( *ppSupplementalCacheData,
Source,
*SupplementalCacheDataLength
);
}
}
}
NtStatus = NlpBuildAccountInfo(CacheEntry, EntrySize, &SamInfo);
if (NT_SUCCESS(NtStatus)) {
if( CacheEntry->Revision >= NLP_CACHE_REVISION_NT_5_0 ) {
//
// for NT5, the Passwords are stored in the CacheEntry.
// note: passwords are assumed to be salted.
//
RtlCopyMemory( Passwords, &(CacheEntry->CachePasswords), sizeof(*Passwords) );
} else {
//
// prior to NT5, the Passwords are stored separately in their
// own LSA secret.
//
NtStatus = NlpReadSecret(&CurrentSecret, &OldSecret);
//
// can release the cache lock now, since second data item fetched.
//
LEAVE_CACHE();
fCacheLocked = FALSE;
if (NT_SUCCESS(NtStatus)) {
if (CurrentSecret) {
//
// Check to see which version of the passwords are stored
// here - the normal or the salted.
//
RtlCopyMemory((PVOID)Passwords,
(PVOID)CurrentSecret->Buffer,
(ULONG)CurrentSecret->Length
);
if (CacheEntry->Revision < NLP_CACHE_REVISION_NT_4_SP4 ) {
if (Passwords->SecretPasswords.NtPasswordPresent) {
NtStatus = NlpComputeSaltedHashedPassword(
&Passwords->SecretPasswords.NtOwfPassword,
&Passwords->SecretPasswords.NtOwfPassword,
&SamInfo->EffectiveName
);
}
if (NT_SUCCESS(NtStatus) && Passwords->SecretPasswords.LmPasswordPresent) {
NtStatus = NlpComputeSaltedHashedPassword(
&Passwords->SecretPasswords.LmOwfPassword,
&Passwords->SecretPasswords.LmOwfPassword,
&SamInfo->EffectiveName
);
}
}
}
}
}
}
if( fCacheLocked ) {
LEAVE_CACHE();
}
//
// free structure allocated by NlpReadCacheEntry
//
if( CacheEntry ) {
ZeroMemory( CacheEntry, EntrySize );
FreeToHeap(CacheEntry);
}
//
// free structures allocated by NlpReadSecret
//
if (CurrentSecret) {
MIDL_user_free(CurrentSecret);
}
if (OldSecret) {
MIDL_user_free(OldSecret);
}
if( NT_SUCCESS( NtStatus ) ) {
*AccountInfo = SamInfo;
} else {
if ( SamInfo != NULL ) {
MIDL_user_free( SamInfo );
}
if( ppSupplementalCacheData && *ppSupplementalCacheData ) {
MIDL_user_free( *ppSupplementalCacheData );
*ppSupplementalCacheData = NULL;
}
}
return(NtStatus);
}
NTSTATUS
NlpAddCacheEntry(
IN PNETLOGON_INTERACTIVE_INFO LogonInfo,
IN PNETLOGON_VALIDATION_SAM_INFO2 AccountInfo,
IN PVOID SupplementalCacheData,
IN ULONG SupplementalCacheDataLength
)
/*++
Routine Description:
Adds this domain:user interactive logon information to the cache.
Arguments:
LogonInfo - pointer to NETLOGON_INTERACTIVE_INFO structure which contains
the domain name, user name and password for this user. These
are what the user typed to WinLogon
AccountInfo - pointer to NETLOGON_VALIDATION_SAM_INFO2 structure which
contains this user's specific interactive logon information
Return Value:
NTSTATUS
Success = STATUS_SUCCESS
AccountInfo successfully added to cache
Failure = STATUS_NO_MEMORY
--*/
{
NTSTATUS
NtStatus;
PLOGON_CACHE_ENTRY
CacheEntry = NULL;
PLOGON_CACHE_ENTRY
CacheEntryExisting = NULL;
ULONG
EntrySize,
EntrySizeExisting,
Index;
#if DBG
if (DumpCacheInfo) {
DbgPrint("NlpAddCacheEntry\n");
DumpLogonInfo(&LogonInfo->Identity);
DumpAccountInfo(AccountInfo);
}
#endif
if (NlpInitializationNotYetPerformed) {
NtStatus = NlpInternalCacheInitialize();
if (!NT_SUCCESS(NtStatus)) {
return(NtStatus);
}
}
if (NlpCacheControl.Entries == 0) {
return(STATUS_SUCCESS);
}
//
// build base cache entry.
//
NtStatus = NlpBuildCacheEntry(LogonInfo, AccountInfo, &CacheEntry, &EntrySize);
if(!NT_SUCCESS(NtStatus) )
return (NtStatus);
//
// add any supplemental data to the cache entry.
// (this is new for NT5).
//
NtStatus = NlpAddSupplementalCacheData(
SupplementalCacheData,
SupplementalCacheDataLength,
&CacheEntry,
&EntrySize
);
if(!NT_SUCCESS(NtStatus)) {
goto Cleanup;
}
//
// add in salted OWFs.
//
NtStatus = NlpMakeSecretPasswordNT5(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -