|
|
//+--------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (c) Microsoft Corporation 1992 - 1996
//
// File: ntlm.cxx
//
// Contents: main entrypoints for the ntlm security package
// SpLsaModeInitialize
// SpInitialize
// SpShutdown
// SpGetInfo
//
// Helper functions:
// NtLmSetPolicyInfo
// NtLmPolicyChangeCallback
// NtLmRegisterForPolicyChange
// NtLmUnregisterForPolicyChange
//
// History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\kerberos.cxx
// ChandanS 16-Apr-1998 No reboot on domain name change
// JClark 28-Jun-2000 Added WMI Trace Logging Support
//
//---------------------------------------------------------------------
// Variables with the EXTERN storage class are declared here
#define NTLM_GLOBAL
#define DEBUG_ALLOCATE
#include <global.h>
#include <wow64t.h>
#include "trace.h"
extern "C" {
NTSTATUS LsaApInitializePackage( IN ULONG AuthenticationPackageId, IN PLSA_DISPATCH_TABLE LsaDispatchTable, IN PSTRING Database OPTIONAL, IN PSTRING Confidentiality OPTIONAL, OUT PSTRING *AuthenticationPackageName ); }
BOOLEAN NtLmCredentialInitialized; BOOLEAN NtLmContextInitialized; BOOLEAN NtLmRNGInitialized;
LIST_ENTRY NtLmProcessOptionsList; RTL_RESOURCE NtLmProcessOptionsLock;
//+--------------------------------------------------------------------
//
// Function: SpLsaModeInitialize
//
// Synopsis: This function is called by the LSA when this DLL is loaded.
// It returns security package function tables for all
// security packages in the DLL.
//
// Arguments: LsaVersion - Version number of the LSA
// PackageVersion - Returns version number of the package
// Tables - Returns array of function tables for the package
// TableCount - Returns number of entries in array of
// function tables.
//
// Returns: PackageVersion (as above)
// Tables (as above)
// TableCount (as above)
//
// Notes:
//
//---------------------------------------------------------------------
NTSTATUS NTAPI SpLsaModeInitialize( IN ULONG LsaVersion, OUT PULONG PackageVersion, OUT PSECPKG_FUNCTION_TABLE * Tables, OUT PULONG TableCount ) { #if DBG
// SspGlobalDbflag = SSP_CRITICAL| SSP_API| SSP_API_MORE |SSP_INIT| SSP_MISC | SSP_NO_LOCAL;
SspGlobalDbflag = SSP_CRITICAL ; InitializeCriticalSection(&SspGlobalLogFileCritSect); #endif
SspPrint((SSP_API, "Entering SpLsaModeInitialize\n"));
SECURITY_STATUS Status = SEC_E_OK;
if (LsaVersion != SECPKG_INTERFACE_VERSION) { SspPrint((SSP_CRITICAL, "Invalid LSA version: %d\n", LsaVersion)); Status = STATUS_INVALID_PARAMETER; goto CleanUp; }
NtLmFunctionTable.InitializePackage = NULL; NtLmFunctionTable.LogonUser = NULL; NtLmFunctionTable.CallPackage = LsaApCallPackage; NtLmFunctionTable.LogonTerminated = LsaApLogonTerminated; NtLmFunctionTable.CallPackageUntrusted = LsaApCallPackageUntrusted; NtLmFunctionTable.LogonUserEx = NULL; NtLmFunctionTable.LogonUserEx2 = LsaApLogonUserEx2; NtLmFunctionTable.Initialize = SpInitialize; NtLmFunctionTable.Shutdown = SpShutdown; NtLmFunctionTable.GetInfo = SpGetInfo; NtLmFunctionTable.AcceptCredentials = SpAcceptCredentials; NtLmFunctionTable.AcquireCredentialsHandle = SpAcquireCredentialsHandle; NtLmFunctionTable.FreeCredentialsHandle = SpFreeCredentialsHandle; NtLmFunctionTable.SaveCredentials = SpSaveCredentials; NtLmFunctionTable.GetCredentials = SpGetCredentials; NtLmFunctionTable.DeleteCredentials = SpDeleteCredentials; NtLmFunctionTable.InitLsaModeContext = SpInitLsaModeContext; NtLmFunctionTable.AcceptLsaModeContext = SpAcceptLsaModeContext; NtLmFunctionTable.DeleteContext = SpDeleteContext; NtLmFunctionTable.ApplyControlToken = SpApplyControlToken; NtLmFunctionTable.GetUserInfo = SpGetUserInfo; NtLmFunctionTable.QueryCredentialsAttributes = SpQueryCredentialsAttributes ; NtLmFunctionTable.GetExtendedInformation = SpGetExtendedInformation ; NtLmFunctionTable.SetExtendedInformation = SpSetExtendedInformation ; NtLmFunctionTable.CallPackagePassthrough = LsaApCallPackagePassthrough; #if 0
NtLmFunctionTable.QueryContextAttributes = SpQueryLsaModeContextAttributes; NtLmFunctionTable.SetContextAttributes = SpSetContextAttributes;
*PackageVersion = SECPKG_INTERFACE_VERSION_2; #else
*PackageVersion = SECPKG_INTERFACE_VERSION; #endif
*Tables = &NtLmFunctionTable; *TableCount = 1;
//
// Get the Event Trace logging on board
//
NtlmInitializeTrace();
SafeAllocaInitialize(SAFEALLOCA_USE_DEFAULT, SAFEALLOCA_USE_DEFAULT, NtLmAllocate, NtLmFree);
CleanUp:
SspPrint((SSP_API, "Leaving SpLsaModeInitialize\n"));
return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR)); }
//+-------------------------------------------------------------------------
//
// Function: NtLmSetPolicyInfo
//
// Synopsis: Function to be called when policy changes
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
// if fInit is TRUE, this is called by the init routine in ntlm
//
//
//+-------------------------------------------------------------------------
NTSTATUS NtLmSetPolicyInfo( IN PUNICODE_STRING DnsComputerName, IN PUNICODE_STRING ComputerName, IN PUNICODE_STRING DnsDomainName, IN PUNICODE_STRING DomainName, IN PSID DomainSid, IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass, IN BOOLEAN fInit ) { NTSTATUS Status = STATUS_SUCCESS;
// Buffers to delete on cleanup
STRING ComputerNameAnsiString; STRING DomainNameAnsiString;
UNICODE_STRING DnsTreeName = {0};
ComputerNameAnsiString.Buffer = NULL; DomainNameAnsiString.Buffer = NULL;
//
// grab the treename. don't do this during Init, because the SAM
// isn't initialized yet.
//
if(!fInit) { Status = SsprQueryTreeName( &DnsTreeName ); }
RtlAcquireResourceExclusive(&NtLmGlobalCritSect, TRUE);
if(!fInit && NT_SUCCESS( Status )) { if( NtLmGlobalUnicodeDnsTreeName.Buffer != NULL ) { NtLmFree( NtLmGlobalUnicodeDnsTreeName.Buffer ); }
RtlCopyMemory(&NtLmGlobalUnicodeDnsTreeName, &DnsTreeName, sizeof(DnsTreeName)); }
//
// Do this only if this is package init
//
if (fInit) { if (ComputerName && ComputerName->Buffer != NULL) { ULONG cLength = ComputerName->Length / sizeof(WCHAR);
if ((ComputerName->Length + sizeof(WCHAR)) > sizeof(NtLmGlobalUnicodeComputerName)) { // Bad ComputerName
Status = STATUS_INVALID_COMPUTER_NAME; SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Bad computer name length is %d\n", cLength)); goto CleanUp; }
wcsncpy(NtLmGlobalUnicodeComputerName, ComputerName->Buffer, cLength);
NtLmGlobalUnicodeComputerName[cLength] = UNICODE_NULL;
// make NtlmGlobalUnicodeComputerNameString a string form
RtlInitUnicodeString( &NtLmGlobalUnicodeComputerNameString, NtLmGlobalUnicodeComputerName );
// Save old buffers for deleting
ComputerNameAnsiString = NtLmGlobalOemComputerNameString;
Status = RtlUpcaseUnicodeStringToOemString( &NtLmGlobalOemComputerNameString, &NtLmGlobalUnicodeComputerNameString, TRUE );
if ( !NT_SUCCESS(Status) ) { Status = STATUS_SUCCESS; //SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Error from RtlUpcaseUnicodeStringToOemString is %d\n", Status));
ComputerNameAnsiString.Buffer = NULL; // goto CleanUp;
}
} }
//
// Initialize various forms of the primary domain name of the local system
// Do this only if this is package init or it's DnsDomain info
//
if (fInit || (ChangedInfoClass == PolicyNotifyDnsDomainInformation)) { if (DnsComputerName && DnsComputerName->Buffer != NULL ) { ULONG cLength = DnsComputerName->Length / sizeof(WCHAR);
if((DnsComputerName->Length + sizeof(WCHAR)) > sizeof(NtLmGlobalUnicodeDnsComputerName)) { // Bad ComputerName
Status = STATUS_INVALID_COMPUTER_NAME; SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Bad computer name length is %d\n", cLength)); goto CleanUp; }
wcsncpy(NtLmGlobalUnicodeDnsComputerName, DnsComputerName->Buffer, cLength);
NtLmGlobalUnicodeDnsComputerName[cLength] = UNICODE_NULL;
// make NtlmGlobalUnicodeDnsComputerNameString a string form
RtlInitUnicodeString( &NtLmGlobalUnicodeDnsComputerNameString, NtLmGlobalUnicodeDnsComputerName ); }
if (DnsDomainName && DnsDomainName->Buffer != NULL ) { ULONG cLength = DnsDomainName->Length / sizeof(WCHAR);
if((DnsDomainName->Length + sizeof(WCHAR)) > sizeof(NtLmGlobalUnicodeDnsDomainName)) { // Bad ComputerName
Status = STATUS_INVALID_COMPUTER_NAME; SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Bad domain name length is %d\n", cLength)); goto CleanUp; }
wcsncpy(NtLmGlobalUnicodeDnsDomainName, DnsDomainName->Buffer, cLength);
NtLmGlobalUnicodeDnsDomainName[cLength] = UNICODE_NULL;
// make NtlmGlobalUnicodeDnsDomainNameString a string form
RtlInitUnicodeString( &NtLmGlobalUnicodeDnsDomainNameString, NtLmGlobalUnicodeDnsDomainName ); }
if (DomainName && DomainName->Buffer != NULL) { ULONG cLength = DomainName->Length / sizeof(WCHAR);
if ((DomainName->Length + sizeof(WCHAR)) > sizeof(NtLmGlobalUnicodePrimaryDomainName)) { Status = STATUS_NAME_TOO_LONG; SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Bad domain name length is %d\n", cLength)); goto CleanUp; } wcsncpy(NtLmGlobalUnicodePrimaryDomainName, DomainName->Buffer, cLength); NtLmGlobalUnicodePrimaryDomainName[cLength] = UNICODE_NULL;
// make NtlmGlobalUnicodePrimaryDomainNameString a string form
RtlInitUnicodeString( &NtLmGlobalUnicodePrimaryDomainNameString, NtLmGlobalUnicodePrimaryDomainName );
// Save old buffers for deleting
DomainNameAnsiString = NtLmGlobalOemPrimaryDomainNameString;
Status = RtlUpcaseUnicodeStringToOemString( &NtLmGlobalOemPrimaryDomainNameString, &NtLmGlobalUnicodePrimaryDomainNameString, TRUE );
if ( !NT_SUCCESS(Status) ) { // SspPrint((SSP_CRITICAL, "NtLmSetPolicyInfo, Error from RtlUpcaseUnicodeStringToOemString is %d\n", Status));
DomainNameAnsiString.Buffer = NULL; // goto CleanUp;
Status = STATUS_SUCCESS; } } }
//
// If this is a standalone windows NT workstation,
// use the computer name as the Target name.
//
if ( DomainSid != NULL) { NtLmGlobalUnicodeTargetName = NtLmGlobalUnicodePrimaryDomainNameString; NtLmGlobalOemTargetName = NtLmGlobalOemPrimaryDomainNameString; NtLmGlobalTargetFlags = NTLMSSP_TARGET_TYPE_DOMAIN; NtLmGlobalDomainJoined = TRUE; } else { NtLmGlobalUnicodeTargetName = NtLmGlobalUnicodeComputerNameString; NtLmGlobalOemTargetName = NtLmGlobalOemComputerNameString; NtLmGlobalTargetFlags = NTLMSSP_TARGET_TYPE_SERVER; NtLmGlobalDomainJoined = FALSE; }
//
// update the GlobalNtlm3 targetinfo.
//
Status = SsprUpdateTargetInfo();
CleanUp:
RtlReleaseResource(&NtLmGlobalCritSect);
if (ComputerNameAnsiString.Buffer) { RtlFreeOemString(&ComputerNameAnsiString); }
if (DomainNameAnsiString.Buffer) { RtlFreeOemString(&DomainNameAnsiString); }
return Status; }
NET_API_STATUS NtLmFlushLogonCache ( VOID ) /*++
Routine Description:
This function flushes the logon cache. This is done on unjoin.
If the cache were not flushed, a user could logon to cached credentials after the unjoin. That is especially bad since Winlogon now tries a cached logon to improve boot times.
Return Value:
NERR_Success -- Success
--*/ { NET_API_STATUS NetStatus; HKEY hKey = NULL;
#define NETSETUPP_LOGON_CACHE_PATH L"SECURITY\\Cache"
#define NETSETUPP_LOGON_CACHE_VALUE L"NL$Control"
//
// Open the key containing the cache
//
NetStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, NETSETUPP_LOGON_CACHE_PATH, 0, KEY_SET_VALUE, &hKey );
if ( NetStatus == ERROR_SUCCESS ) {
//
// Delete the value describing the size of the cache
// This ensures the values cannot be used
//
RegDeleteValue( hKey, NETSETUPP_LOGON_CACHE_VALUE );
RegCloseKey( hKey ); }
return NetStatus; }
//+-------------------------------------------------------------------------
//
// Function: NtLmPolicyChangeCallback
//
// Synopsis: Function to be called when domain policy changes
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID NTAPI NtLmPolicyChangeCallback( IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass ) { NTSTATUS Status = STATUS_SUCCESS; PLSAPR_POLICY_INFORMATION Policy = NULL;
switch (ChangedInfoClass) { case PolicyNotifyDnsDomainInformation: {
WCHAR UnicodeDnsComputerName[DNS_MAX_NAME_LENGTH + 1]; UNICODE_STRING UnicodeDnsComputerNameString; ULONG DnsComputerNameLength = sizeof(UnicodeDnsComputerName) / sizeof(WCHAR);
//
// Get the new domain information
//
Status = I_LsaIQueryInformationPolicyTrusted( PolicyDnsDomainInformation, &Policy );
if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL, "NtLmPolicyChangeCallback, Error from I_LsaIQueryInformationPolicyTrusted is %d\n", Status)); goto Cleanup; }
//
// get the new DNS computer name
//
if ( !GetComputerNameExW( ComputerNameDnsFullyQualified, UnicodeDnsComputerName, &DnsComputerNameLength ) ) { UnicodeDnsComputerName[ 0 ] = L'\0'; }
RtlInitUnicodeString( &UnicodeDnsComputerNameString, UnicodeDnsComputerName);
Status = NtLmSetPolicyInfo( &UnicodeDnsComputerNameString, NULL, (PUNICODE_STRING) &Policy->PolicyDnsDomainInfo.DnsDomainName, (PUNICODE_STRING) &Policy->PolicyDnsDomainInfo.Name, (PSID) Policy->PolicyDnsDomainInfo.Sid, ChangedInfoClass, FALSE);
if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL, "NtLmPolicyChangeCallback, Error from NtLmSetDomainName is %d\n", Status)); goto Cleanup; }
{ BOOLEAN FlushLogonCache = FALSE;
if( NtLmSecPkg.DomainSid == NULL && Policy->PolicyDnsDomainInfo.Sid != NULL ) { FlushLogonCache = TRUE; }
if( NtLmSecPkg.DomainSid != NULL && Policy->PolicyDnsDomainInfo.Sid == NULL ) { FlushLogonCache = TRUE; }
if( NtLmSecPkg.DomainSid != NULL && Policy->PolicyDnsDomainInfo.Sid != NULL ) { if(!RtlEqualSid( NtLmSecPkg.DomainSid, Policy->PolicyDnsDomainInfo.Sid )) { FlushLogonCache = TRUE; } }
if( FlushLogonCache ) { //
// flush the logon cache...
//
NtLmFlushLogonCache(); } }
} break; default: break; }
Cleanup:
if (Policy != NULL) { switch (ChangedInfoClass) { case PolicyNotifyDnsDomainInformation: { I_LsaIFree_LSAPR_POLICY_INFORMATION( PolicyDnsDomainInformation, Policy ); } break; default: break; } } return;
}
//+-------------------------------------------------------------------------
//
// Function: NtLmRegisterForPolicyChange
//
// Synopsis: Register with the LSA to be notified of policy changes
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS NtLmRegisterForPolicyChange( IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass ) { NTSTATUS Status = STATUS_SUCCESS; Status = I_LsaIRegisterPolicyChangeNotificationCallback( NtLmPolicyChangeCallback, ChangedInfoClass ); if (!NT_SUCCESS(Status)) { SspPrint((SSP_CRITICAL, "NtLmRegisterForPolicyChange, Error from I_LsaIRegisterPolicyChangeNotificationCallback is %d\n", Status)); } SspPrint((SSP_MISC, "I_LsaIRegisterPolicyChangeNotificationCallback called with %d\n", ChangedInfoClass)); return(Status);
}
//+-------------------------------------------------------------------------
//
// Function: NtLmUnregisterForPolicyChange
//
// Synopsis: Unregister for policy change notification
//
// Effects:
//
// Arguments:
//
// Requires:
//
// Returns:
//
// Notes:
//
//
//--------------------------------------------------------------------------
VOID NtLmUnregisterForPolicyChange( IN POLICY_NOTIFICATION_INFORMATION_CLASS ChangedInfoClass ) { (VOID) I_LsaIUnregisterPolicyChangeNotificationCallback( NtLmPolicyChangeCallback, ChangedInfoClass );
}
//+--------------------------------------------------------------------
//
// Function: SpInitialize
//
// Synopsis: Initializes the Security package
//
// Arguments: PackageId - Contains ID for this package assigned by LSA
// Parameters - Contains machine-specific information
// FunctionTable - Contains table of LSA helper routines
//
// Returns: None
//
// Notes: Everything that was done in LsaApInitializePackage
// should be done here. Lsa assures us that only
// one thread is executing this at a time. Don't
// have to worry about concurrency problems.
// Most of the stuff was taken from SspCommonInitialize()
// from svcdlls\ntlmssp\common\initcomn.c
//
//---------------------------------------------------------------------
NTSTATUS NTAPI SpInitialize( IN ULONG_PTR PackageId, IN PSECPKG_PARAMETERS Parameters, IN PLSA_SECPKG_FUNCTION_TABLE FunctionTable ) { SspPrint((SSP_API, "Entering SpInitialize\n"));
SECURITY_STATUS Status = SEC_E_OK; WCHAR UnicodeComputerName[CNLEN + 1]; UNICODE_STRING UnicodeComputerNameString; ULONG ComputerNameLength = (sizeof(UnicodeComputerName)/sizeof(WCHAR));
WCHAR UnicodeDnsComputerName[DNS_MAX_NAME_LENGTH + 1]; UNICODE_STRING UnicodeDnsComputerNameString; ULONG DnsComputerNameLength = sizeof(UnicodeDnsComputerName) / sizeof(WCHAR);
//
// Init the global crit section
//
RtlInitializeResource(&NtLmGlobalCritSect);
RtlInitializeResource(&NtLmProcessOptionsLock); InitializeListHead( &NtLmProcessOptionsList );
//
// All the following are global
//
NtLmState = NtLmLsaMode; NtLmPackageId = PackageId;
// We really need this to be a day less than maxtime so when callers
// of sspi convert to utc, they won't get time in the past.
NtLmGlobalForever.HighPart = 0x7FFFFF36; NtLmGlobalForever.LowPart = 0xD5969FFF;
//
// Following are local
//
NtLmCredentialInitialized = FALSE; NtLmContextInitialized = FALSE; NtLmRNGInitialized = FALSE;
//
// Save away the Lsa functions
//
LsaFunctions = FunctionTable;
//
// Save the Parameters info
//
NtLmSecPkg.MachineState = Parameters->MachineState; NtLmSecPkg.SetupMode = Parameters->SetupMode;
//
// allocate a locally unique ID rereferencing the machine logon.
//
Status = NtAllocateLocallyUniqueId( &NtLmGlobalLuidMachineLogon );
if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtAllocateLocallyUniqueId is %d\n", Status)); goto CleanUp; }
//
// create a logon session for the machine logon.
//
Status = LsaFunctions->CreateLogonSession( &NtLmGlobalLuidMachineLogon ); if( !NT_SUCCESS(Status) ) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from CreateLogonSession is %d\n", Status)); goto CleanUp; }
Status = NtLmDuplicateUnicodeString( &NtLmSecPkg.DomainName, &Parameters->DomainName);
if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmDuplicateUnicodeString is %d\n", Status)); goto CleanUp; }
Status = NtLmDuplicateUnicodeString( &NtLmSecPkg.DnsDomainName, &Parameters->DnsDomainName);
if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmDuplicateUnicodeString is %d\n", Status)); goto CleanUp; }
if (Parameters->DomainSid != NULL) { Status = NtLmDuplicateSid( &NtLmSecPkg.DomainSid, Parameters->DomainSid );
if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmDuplicateSid is %d\n", Status)); goto CleanUp; } }
//
// Determine if this machine is running NT Workstation or NT Server
//
if (!RtlGetNtProductType (&NtLmGlobalNtProductType)) { SspPrint((SSP_API_MORE, "RtlGetNtProductType defaults to NtProductWinNt\n")); }
//
// Determine if we are running Personal SKU
//
{ OSVERSIONINFOEXW osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); if(GetVersionExW((OSVERSIONINFOW*)&osvi)) { NtLmGlobalPersonalSKU = ( osvi.wProductType == VER_NT_WORKSTATION && (osvi.wSuiteMask & VER_SUITE_PERSONAL)); } else { SspPrint((SSP_API_MORE, "GetVersionEx defaults to non-personal\n")); } }
Status = I_LsaIOpenPolicyTrusted(&NtLmGlobalPolicyHandle);
if ( !NT_SUCCESS(Status) ) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from I_LsaIOpenPolicyTrusted is %d\n", Status)); goto CleanUp; }
if ( !GetComputerNameW( UnicodeComputerName, &ComputerNameLength ) ) { Status = STATUS_INVALID_COMPUTER_NAME; SspPrint((SSP_CRITICAL, "SpInitialize, Error from GetComputerNameW is %d\n", Status)); goto CleanUp; }
if ( !GetComputerNameExW( ComputerNameDnsFullyQualified, UnicodeDnsComputerName, &DnsComputerNameLength ) ) {
//
// per CliffV, failure is legal.
//
UnicodeDnsComputerName[ 0 ] = L'\0'; }
{ SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
(VOID)AllocateAndInitializeSid( &siaNtAuthority, 1, SECURITY_ANONYMOUS_LOGON_RID, 0, 0, 0, 0, 0, 0, 0, &NtLmGlobalAnonymousSid ); }
//
// pickup a copy of the Local System access token.
//
{ HANDLE hProcessToken; NTSTATUS StatusToken;
StatusToken = NtOpenProcessToken( NtCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE, &hProcessToken );
if( NT_SUCCESS( StatusToken ) ) {
TOKEN_STATISTICS LocalTokenStatistics; DWORD TokenStatisticsSize = sizeof(LocalTokenStatistics); LUID LogonIdSystem = SYSTEM_LUID;
Status = NtQueryInformationToken( hProcessToken, TokenStatistics, &LocalTokenStatistics, TokenStatisticsSize, &TokenStatisticsSize );
if( NT_SUCCESS( Status ) ) {
//
// see if it's SYSTEM.
//
if(RtlEqualLuid( &LogonIdSystem, &(LocalTokenStatistics.AuthenticationId) )) {
Status = SspDuplicateToken( hProcessToken, SecurityImpersonation, &NtLmGlobalAccessTokenSystem ); } }
NtClose( hProcessToken ); } }
if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, could not acquire SYSTEM token %d\n", Status)); goto CleanUp; }
//
// Init the Credential stuff
//
Status = SspCredentialInitialize(); if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from SspCredentialInitializeis %d\n", Status)); goto CleanUp; } NtLmCredentialInitialized = TRUE;
//
// Init the Context stuff
//
Status = SspContextInitialize(); if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from SspContextInitializeis %d\n", Status)); goto CleanUp; } NtLmContextInitialized = TRUE;
//
// Get the locale and check if it is FRANCE, which doesn't allow
// encryption
//
NtLmGlobalEncryptionEnabled = IsEncryptionPermitted();
//
// Init the random number generator stuff
//
if( !NtLmInitializeRNG() ) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmInitializeRNG\n")); Status = STATUS_UNSUCCESSFUL; goto CleanUp; } NtLmRNGInitialized = TRUE;
NtLmCheckLmCompatibility();
if( NtLmSecPkg.DomainSid != NULL ) { NtLmGlobalDomainJoined = TRUE; }
NtLmQueryMappedDomains();
//
// Set all the globals relating to computer name, domain name, sid etc.
// This routine is also used by the callback for notifications from the lsa
//
RtlInitUnicodeString( &UnicodeComputerNameString, UnicodeComputerName);
RtlInitUnicodeString( &UnicodeDnsComputerNameString, UnicodeDnsComputerName);
Status = NtLmSetPolicyInfo( &UnicodeDnsComputerNameString, &UnicodeComputerNameString, &NtLmSecPkg.DnsDomainName, &NtLmSecPkg.DomainName, NtLmSecPkg.DomainSid, PolicyNotifyAuditEventsInformation, // Ignored
TRUE ); // yes, package init
if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmSetDomainInfo %d\n", Status)); goto CleanUp; }
// Do the Init stuff for the MSV authentication package
// Passing FunctionTable as a (PLSA_DISPATCH_TABLE).
// Well, the first 11 entries are the same. Cheating a
// bit.
Status = LsaApInitializePackage( (ULONG) PackageId, (PLSA_DISPATCH_TABLE)FunctionTable, NULL, NULL, NULL);
if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from LsaApInitializePackage is %d\n", Status)); goto CleanUp; }
Status = NtLmRegisterForPolicyChange(PolicyNotifyDnsDomainInformation); if (!NT_SUCCESS (Status)) { SspPrint((SSP_CRITICAL, "SpInitialize, Error from NtLmRegisterForPolicyChange is %d\n", Status)); goto CleanUp; }
CleanUp:
if (!NT_SUCCESS (Status)) { SpShutdown(); }
SspPrint((SSP_API, "Leaving SpInitialize\n"));
return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR)); }
//+--------------------------------------------------------------------
//
// Function: SpShutdown
//
// Synopsis: Exported function to shutdown the Security package.
//
// Effects: Forces the freeing of all credentials, contexts
// and frees all global data
//
// Arguments: none
//
// Returns:
//
// Notes: SEC_E_OK in all cases
// Most of the stuff was taken from SspCommonShutdown()
// from svcdlls\ntlmssp\common\initcomn.c
//
//
//---------------------------------------------------------------------
NTSTATUS NTAPI SpShutdown( VOID ) { SspPrint((SSP_API, "Entering SpShutdown\n"));
//
// comment out LSA mode cleanup code, per NTBUG 400026,
// which can result in access violations during shutdown when
// calls into package are still occuring during shutdown.
//
#if 0
if (NtLmContextInitialized) { SspContextTerminate(); NtLmContextInitialized = FALSE; }
if (NtLmCredentialInitialized) { SspCredentialTerminate(); NtLmCredentialInitialized = FALSE; }
if (NtLmGlobalOemComputerNameString.Buffer != NULL) { RtlFreeOemString(&NtLmGlobalOemComputerNameString); NtLmGlobalOemComputerNameString.Buffer = NULL; }
if (NtLmGlobalOemPrimaryDomainNameString.Buffer != NULL) { RtlFreeOemString(&NtLmGlobalOemPrimaryDomainNameString); NtLmGlobalOemPrimaryDomainNameString.Buffer = NULL; }
if (NtLmGlobalNtLm3TargetInfo.Buffer != NULL) { NtLmFree (NtLmGlobalNtLm3TargetInfo.Buffer); NtLmGlobalNtLm3TargetInfo.Buffer = NULL; }
if ( NtLmSecPkg.DomainName.Buffer != NULL ) { NtLmFree (NtLmSecPkg.DomainName.Buffer); }
if ( NtLmSecPkg.DnsDomainName.Buffer != NULL ) { NtLmFree (NtLmSecPkg.DnsDomainName.Buffer); }
if ( NtLmSecPkg.DomainSid != NULL ) { NtLmFree (NtLmSecPkg.DomainSid); }
if (NtLmGlobalLocalSystemSid != NULL) { FreeSid( NtLmGlobalLocalSystemSid); NtLmGlobalLocalSystemSid = NULL; }
if (NtLmGlobalAliasAdminsSid != NULL) { FreeSid( NtLmGlobalAliasAdminsSid); NtLmGlobalAliasAdminsSid = NULL; }
if (NtLmGlobalProcessUserSid != NULL) { NtLmFree( NtLmGlobalProcessUserSid ); NtLmGlobalProcessUserSid = NULL; }
if( NtLmGlobalAnonymousSid ) { FreeSid( NtLmGlobalAnonymousSid ); NtLmGlobalAnonymousSid = NULL; }
if (NtLmRNGInitialized) { NtLmCleanupRNG(); NtLmRNGInitialized = FALSE; }
NtLmFreeMappedDomains();
NtLmUnregisterForPolicyChange(PolicyNotifyDnsDomainInformation);
if (NtLmGlobalAccessTokenSystem != NULL) { NtClose( NtLmGlobalAccessTokenSystem ); NtLmGlobalAccessTokenSystem = NULL; }
RtlDeleteResource(&NtLmGlobalCritSect);
if (NtLmGlobalPolicyHandle != NULL) { (VOID) I_LsarClose( &NtLmGlobalPolicyHandle ); }
SspPrint((SSP_API, "Leaving SpShutdown\n")); #if DBG
DeleteCriticalSection(&SspGlobalLogFileCritSect); #endif
#endif // NTBUG 400026
return(SEC_E_OK); }
//+--------------------------------------------------------------------
//
// Function: SpGetInfo
//
// Synopsis: Returns information about the package
//
// Effects: returns pointers to global data
//
// Arguments: PackageInfo - Receives security package information
//
// Returns: SEC_E_OK in all cases
//
// Notes: Pointers to constants ok. Lsa will copy the data
// before sending it to someone else
//
//---------------------------------------------------------------------
NTSTATUS NTAPI SpGetInfo( OUT PSecPkgInfo PackageInfo ) { SspPrint((SSP_API, "Entering SpGetInfo\n"));
PackageInfo->fCapabilities = NTLMSP_CAPS; PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION; PackageInfo->wRPCID = RPC_C_AUTHN_WINNT; PackageInfo->cbMaxToken = NTLMSP_MAX_TOKEN_SIZE; PackageInfo->Name = NTLMSP_NAME; PackageInfo->Comment = NTLMSP_COMMENT;
SspPrint((SSP_API, "Leaving SpGetInfo\n"));
return(SEC_E_OK); }
NTSTATUS NTAPI SpGetExtendedInformation( IN SECPKG_EXTENDED_INFORMATION_CLASS Class, OUT PSECPKG_EXTENDED_INFORMATION * ppInformation ) { NTSTATUS Status = STATUS_SUCCESS; PSECPKG_EXTENDED_INFORMATION Information = NULL; ULONG Size ;
switch ( Class ) { case SecpkgContextThunks:
Information = (PSECPKG_EXTENDED_INFORMATION) NtLmAllocate(sizeof(SECPKG_EXTENDED_INFORMATION) + sizeof(DWORD)); if (Information == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; goto Cleanup; } Information->Class = SecpkgContextThunks; Information->Info.ContextThunks.InfoLevelCount = 1; Information->Info.ContextThunks.Levels[0] = SECPKG_ATTR_CREDENTIAL_NAME; *ppInformation = Information; Information = NULL; break;
case SecpkgWowClientDll:
//
// This indicates that we're smart enough to handle wow client processes
//
Information = (PSECPKG_EXTENDED_INFORMATION) NtLmAllocate( sizeof( SECPKG_EXTENDED_INFORMATION ) + (MAX_PATH * sizeof(WCHAR) ) );
if ( Information == NULL ) { Status = STATUS_INSUFFICIENT_RESOURCES ; goto Cleanup ; }
Information->Class = SecpkgWowClientDll ; Information->Info.WowClientDll.WowClientDllPath.Buffer = (PWSTR) (Information + 1); Size = ExpandEnvironmentStrings( L"%SystemRoot%\\" WOW64_SYSTEM_DIRECTORY_U L"\\msv1_0.DLL", Information->Info.WowClientDll.WowClientDllPath.Buffer, MAX_PATH ); Information->Info.WowClientDll.WowClientDllPath.Length = (USHORT) (Size * sizeof(WCHAR)); Information->Info.WowClientDll.WowClientDllPath.MaximumLength = (USHORT) ((Size + 1) * sizeof(WCHAR) ); *ppInformation = Information ; Information = NULL ;
break;
default: Status = SEC_E_UNSUPPORTED_FUNCTION ; }
Cleanup:
if ( Information != NULL ) { NtLmFree( Information ); }
return Status ; }
NTSTATUS NTAPI SpSetExtendedInformation( IN SECPKG_EXTENDED_INFORMATION_CLASS Class, IN PSECPKG_EXTENDED_INFORMATION Info ) { NTSTATUS Status ;
switch ( Class ) { case SecpkgMutualAuthLevel: NtLmGlobalMutualAuthLevel = Info->Info.MutualAuthLevel.MutualAuthLevel ; Status = SEC_E_OK ; break;
default: Status = SEC_E_UNSUPPORTED_FUNCTION ; break; }
return Status ; }
VOID NtLmCheckLmCompatibility( ) /*++
Routine Description:
This routine checks to see if we should support the LM challenge response protocol by looking in the registry under system\currentcontrolset\Control\Lsa\LmCompatibilityLevel. The level indicates whether to send the LM reponse by default and whether to ever send the LM response
Arguments:
none.
Return Value:
None
--*/ { NTSTATUS NtStatus; UNICODE_STRING KeyName; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE KeyHandle;
//
// initialize defaults
// Assume that LM is supported.
//
NtLmGlobalLmProtocolSupported = 0; NtLmGlobalRequireNtlm2 = FALSE; NtLmGlobalDatagramUse128BitEncryption = FALSE; NtLmGlobalDatagramUse56BitEncryption = FALSE;
//
// Open the Lsa key in the registry
//
RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa" );
InitializeObjectAttributes( &ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL );
NtStatus = NtOpenKey( &KeyHandle, KEY_READ, &ObjectAttributes );
if (!NT_SUCCESS(NtStatus)) { return; }
//
// save away registry key so we can use it for notification events.
//
NtLmGlobalLsaKey = (HKEY)KeyHandle;
// now open the MSV1_0 subkey...
RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Lsa\\Msv1_0" );
InitializeObjectAttributes( &ObjectAttributes, &KeyName, OBJ_CASE_INSENSITIVE, 0, NULL );
NtStatus = NtOpenKey( &KeyHandle, KEY_READ, &ObjectAttributes );
if (!NT_SUCCESS(NtStatus)) { return; }
//
// save away registry key so we can use it for notification events.
//
NtLmGlobalLsaMsv1_0Key = (HKEY)KeyHandle;
}
ULONG NtLmValidMinimumSecurityFlagsMask( IN ULONG MinimumSecurity ) /*++
This routine takes a NtLmMinimumClientSec or NtLmMinimumServerSec registry value and masks off the bits that are not relevant for enforcing the supported options.
--*/ {
return (MinimumSecurity & ( NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL | NTLMSSP_NEGOTIATE_NTLM2 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_56 ));
}
VOID NTAPI NtLmQueryDynamicGlobals( PVOID pvContext, BOOLEAN f ) { SspPrint((SSP_API, "Entering NtLmQueryDynamicGlobals\n"));
HKEY KeyHandle; // open registry key to Lsa\MSV1_0
LONG RegStatus;
DWORD RegValueType; DWORD RegValue; DWORD RegValueSize;
KeyHandle = NtLmGlobalLsaKey;
if( KeyHandle != NULL ) { //
// lm compatibility level.
//
RegValueSize = sizeof( RegValue );
RegStatus = RegQueryValueExW( KeyHandle, L"LmCompatibilityLevel", NULL, &RegValueType, (PUCHAR)&RegValue, &RegValueSize );
if ( RegStatus == ERROR_SUCCESS ) {
//
// Check that the data is the correct size and type - a ULONG.
//
if ((RegValueSize >= sizeof(ULONG)) && (RegValueType == REG_DWORD)) {
NtLmGlobalLmProtocolSupported = (ULONG)RegValue; } } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
//
// value was deleted - resort to default.
//
NtLmGlobalLmProtocolSupported = 0; }
//
// handle ForceGuest
//
if( NtLmGlobalNtProductType != NtProductLanManNt ) { RegValueSize = sizeof( RegValue );
if( NtLmGlobalPersonalSKU ) { //
// personal product always has ForceGuest turned on.
//
RegValueSize = sizeof(ULONG); RegValueType = REG_DWORD; RegValue = 1; RegStatus = ERROR_SUCCESS;
} else {
if( NtLmGlobalDomainJoined ) { //
// joined product always has ForceGuest turned off.
//
RegValueSize = sizeof(ULONG); RegValueType = REG_DWORD; RegValue = 0; RegStatus = ERROR_SUCCESS;
} else {
RegStatus = RegQueryValueExW( KeyHandle, L"ForceGuest", NULL, &RegValueType, (PUCHAR)&RegValue, &RegValueSize ); } }
} else {
//
// insure ForceGuest is disabled for domain controllers.
//
RegStatus = ERROR_FILE_NOT_FOUND; }
if ( RegStatus == ERROR_SUCCESS ) {
//
// Check that the data is the correct size and type - a ULONG.
//
if ( (RegValueSize >= sizeof(ULONG)) && (RegValueType == REG_DWORD) ) { if( RegValue == 1 ) { NtLmGlobalForceGuest = TRUE; } else { NtLmGlobalForceGuest = FALSE; } } } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
//
// value was deleted - resort to default.
//
NtLmGlobalForceGuest = FALSE; }
//
// handle LimitBlankPasswordUse
//
if( NtLmGlobalNtProductType != NtProductLanManNt ) { RegValueSize = sizeof( RegValue );
RegStatus = RegQueryValueExW( KeyHandle, L"LimitBlankPasswordUse", NULL, &RegValueType, (PUCHAR)&RegValue, &RegValueSize );
} else { //
// domain controllers always allow blank.
//
NtLmGlobalAllowBlankPassword = TRUE; RegStatus = ERROR_INVALID_PARAMETER; }
if ( RegStatus == ERROR_SUCCESS ) {
//
// Check that the data is the correct size and type - a ULONG.
//
if ( (RegValueSize >= sizeof(ULONG)) && (RegValueType == REG_DWORD) ) { if( RegValue == 0 ) { NtLmGlobalAllowBlankPassword = TRUE; } else { NtLmGlobalAllowBlankPassword = FALSE; } } } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
//
// value was deleted - resort to default.
//
NtLmGlobalAllowBlankPassword = FALSE; }
}
KeyHandle = NtLmGlobalLsaMsv1_0Key;
if( KeyHandle != NULL ) { //
// get minimum client security flag.
//
RegValueSize = sizeof( RegValue );
RegStatus = RegQueryValueExW( KeyHandle, L"NtlmMinClientSec", NULL, &RegValueType, (PUCHAR)&RegValue, &RegValueSize );
if ( RegStatus == ERROR_SUCCESS ) {
//
// Check that the data is the correct size and type - a ULONG.
//
if ((RegValueSize >= sizeof(ULONG)) && (RegValueType == REG_DWORD)) {
NtLmGlobalMinimumClientSecurity = NtLmValidMinimumSecurityFlagsMask( (ULONG)RegValue ); } } else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
//
// value was deleted - resort to default.
//
NtLmGlobalMinimumClientSecurity = 0 ; }
//
// get minimum server security flags.
//
RegValueSize = sizeof( RegValueSize );
RegStatus = RegQueryValueExW( KeyHandle, L"NtlmMinServerSec", NULL, &RegValueType, (PUCHAR)&RegValue, &RegValueSize );
if ( RegStatus == ERROR_SUCCESS ) {
//
// Check that the data is the correct size and type - a ULONG.
//
if ((RegValueSize >= sizeof(ULONG)) && (RegValueType == REG_DWORD)) {
NtLmGlobalMinimumServerSecurity = NtLmValidMinimumSecurityFlagsMask( (ULONG)RegValue ); }
} else if( RegStatus == ERROR_FILE_NOT_FOUND ) {
//
// value was deleted - resort to default.
//
NtLmGlobalMinimumServerSecurity = 0; }
//
// All datagram related flags need to be set.
//
if (NtLmGlobalMinimumClientSecurity & NTLMSSP_NEGOTIATE_NTLM2) { NtLmGlobalRequireNtlm2 = TRUE; }
if ((NtLmGlobalMinimumClientSecurity & NTLMSSP_NEGOTIATE_128) && (NtLmSecPkg.MachineState & SECPKG_STATE_STRONG_ENCRYPTION_PERMITTED)) { NtLmGlobalDatagramUse128BitEncryption = TRUE; } else if (NtLmGlobalMinimumClientSecurity & NTLMSSP_NEGOTIATE_56) { NtLmGlobalDatagramUse56BitEncryption = TRUE; }
#if DBG
//
// get the debugging flag
//
RegValueSize = sizeof( RegValueSize );
RegStatus = RegQueryValueExW( KeyHandle, L"DBFlag", NULL, &RegValueType, (PUCHAR)&RegValue, &RegValueSize );
if ( RegStatus == ERROR_SUCCESS ) {
//
// Check that the data is the correct size and type - a ULONG.
//
if ((RegValueSize >= sizeof(ULONG)) && (RegValueType == REG_DWORD)) {
SspGlobalDbflag = (ULONG)RegValue; }
}
#endif
}
//
// (re)register the wait events.
//
if( NtLmGlobalRegChangeNotifyEvent ) { if( NtLmGlobalLsaKey ) { RegNotifyChangeKeyValue( NtLmGlobalLsaKey, FALSE, REG_NOTIFY_CHANGE_LAST_SET, NtLmGlobalRegChangeNotifyEvent, TRUE ); }
#if DBG
if( NtLmGlobalLsaMsv1_0Key ) { RegNotifyChangeKeyValue( NtLmGlobalLsaMsv1_0Key, FALSE, REG_NOTIFY_CHANGE_LAST_SET, NtLmGlobalRegChangeNotifyEvent, TRUE ); } #endif
}
SspPrint((SSP_API, "Leaving NtLmQueryDynamicGlobals\n"));
return; }
VOID NtLmQueryMappedDomains( VOID ) { HKEY KeyHandle; // open registry key to Lsa\MSV1_0
LONG RegStatus; DWORD RegValueType; WCHAR RegDomainName[DNS_MAX_NAME_LENGTH+1]; DWORD RegDomainSize;
//
// register the workitem that waits for the RegChangeNotifyEvent
// to be signalled. This supports dynamic refresh of configuration
// parameters.
//
NtLmGlobalRegChangeNotifyEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
//
// query the globals once prior to registering the wait
// if a registry change occurs, the globals will be re-read by the worker
// thread.
//
NtLmQueryDynamicGlobals( NULL, FALSE );
NtLmGlobalRegWaitObject = RegisterWaitForSingleObjectEx( NtLmGlobalRegChangeNotifyEvent, NtLmQueryDynamicGlobals, NULL, INFINITE, 0 // dwFlags
);
KeyHandle = NtLmGlobalLsaMsv1_0Key;
if( KeyHandle == NULL ) return;
//
// we only support loading the following globals once during initialization;
// they are not re-read until next reboot.
//
//
// Check the registry for a domain name to map
//
RegDomainSize = sizeof( RegDomainName ); RegStatus = RegQueryValueExW( KeyHandle, L"MappedDomain", NULL, &RegValueType, (PUCHAR) RegDomainName, &RegDomainSize );
if (RegStatus == ERROR_SUCCESS && RegDomainSize <= 0xFFFF) {
NtLmLocklessGlobalMappedDomainString.Length = (USHORT)(RegDomainSize - sizeof(WCHAR)); NtLmLocklessGlobalMappedDomainString.MaximumLength = (USHORT)RegDomainSize; NtLmLocklessGlobalMappedDomainString.Buffer = (PWSTR)NtLmAllocate( RegDomainSize );
if( NtLmLocklessGlobalMappedDomainString.Buffer != NULL ) CopyMemory( NtLmLocklessGlobalMappedDomainString.Buffer, RegDomainName, RegDomainSize ); } else { RtlInitUnicodeString( &NtLmLocklessGlobalMappedDomainString, NULL ); }
//
// Check the registry for a domain name to use
//
RegDomainSize = sizeof( RegDomainName ); RegStatus = RegQueryValueExW( KeyHandle, L"PreferredDomain", NULL, &RegValueType, (PUCHAR) RegDomainName, &RegDomainSize );
if (RegStatus == ERROR_SUCCESS && RegDomainSize <= 0xFFFF) {
NtLmLocklessGlobalPreferredDomainString.Length = (USHORT)(RegDomainSize - sizeof(WCHAR)); NtLmLocklessGlobalPreferredDomainString.MaximumLength = (USHORT)RegDomainSize; NtLmLocklessGlobalPreferredDomainString.Buffer = (PWSTR)NtLmAllocate( RegDomainSize );
if( NtLmLocklessGlobalPreferredDomainString.Buffer != NULL ) CopyMemory( NtLmLocklessGlobalPreferredDomainString.Buffer, RegDomainName, RegDomainSize ); } else { RtlInitUnicodeString( &NtLmLocklessGlobalPreferredDomainString, NULL ); }
return; }
VOID NtLmFreeMappedDomains( VOID ) { if( NtLmGlobalRegWaitObject ) UnregisterWait( NtLmGlobalRegWaitObject );
if( NtLmGlobalRegChangeNotifyEvent ) CloseHandle( NtLmGlobalRegChangeNotifyEvent );
if( NtLmLocklessGlobalMappedDomainString.Buffer ) { NtLmFree( NtLmLocklessGlobalMappedDomainString.Buffer ); NtLmLocklessGlobalMappedDomainString.Buffer = NULL; }
if( NtLmLocklessGlobalPreferredDomainString.Buffer ) { NtLmFree( NtLmLocklessGlobalPreferredDomainString.Buffer ); NtLmLocklessGlobalPreferredDomainString.Buffer = NULL; } }
ULONG NtLmCheckProcessOption( IN ULONG OptionRequest ) { SECPKG_CALL_INFO CallInfo; ULONG OptionMask = 0; PLIST_ENTRY ListHead; PLIST_ENTRY ListEntry;
if(!LsaFunctions->GetCallInfo(&CallInfo)) { goto Cleanup; }
RtlAcquireResourceShared( &NtLmProcessOptionsLock, TRUE ); ListHead = &NtLmProcessOptionsList; //
// Now walk the list looking for a match.
//
for ( ListEntry = ListHead->Flink; ListEntry != ListHead; ListEntry = ListEntry->Flink ) { PSSP_PROCESSOPTIONS ProcessOptions; ProcessOptions = CONTAINING_RECORD( ListEntry, SSP_PROCESSOPTIONS, Next ); if( ProcessOptions->ClientProcessID == CallInfo.ProcessId ) { OptionMask = ProcessOptions->ProcessOptions; break; } } RtlReleaseResource( &NtLmProcessOptionsLock );
Cleanup:
return OptionMask; }
BOOLEAN NtLmSetProcessOption( IN ULONG OptionRequest, IN BOOLEAN DisableOption ) { SECPKG_CALL_INFO CallInfo; PSSP_PROCESSOPTIONS pProcessOption = NULL; PLIST_ENTRY ListHead; PLIST_ENTRY ListEntry; BOOLEAN fExisting = FALSE; BOOLEAN fSuccess = FALSE;
if(!LsaFunctions->GetCallInfo(&CallInfo)) { goto Cleanup; }
pProcessOption = (PSSP_PROCESSOPTIONS)NtLmAllocate( sizeof(*pProcessOption) ); if( pProcessOption == NULL ) { goto Cleanup; }
pProcessOption->ClientProcessID = CallInfo.ProcessId; pProcessOption->ProcessOptions = OptionRequest;
RtlAcquireResourceExclusive( &NtLmProcessOptionsLock, TRUE ); ListHead = &NtLmProcessOptionsList; //
// Now walk the list looking for a match.
//
for ( ListEntry = ListHead->Flink; ListEntry != ListHead; ListEntry = ListEntry->Flink ) { PSSP_PROCESSOPTIONS ProcessOptions; ProcessOptions = CONTAINING_RECORD( ListEntry, SSP_PROCESSOPTIONS, Next ); if( ProcessOptions->ClientProcessID == CallInfo.ProcessId ) { if( DisableOption ) { ProcessOptions->ProcessOptions &= ~OptionRequest; } else { ProcessOptions->ProcessOptions |= OptionRequest; } fExisting = TRUE; break; } }
if( !fExisting && !DisableOption ) { InsertHeadList( &NtLmProcessOptionsList, &pProcessOption->Next ); pProcessOption = NULL; }
RtlReleaseResource( &NtLmProcessOptionsLock );
fSuccess = TRUE;
Cleanup:
if( pProcessOption != NULL ) { NtLmFree( pProcessOption ); }
return fSuccess; }
|