849 lines
24 KiB
C++
849 lines
24 KiB
C++
//+--------------------------------------------------------------------
|
||
//
|
||
// Microsoft Windows
|
||
//
|
||
// Copyright (c) Microsoft Corporation 2000
|
||
//
|
||
// File: ntdigest.c
|
||
//
|
||
// Contents: main entrypoints for the digest security package
|
||
// SpLsaModeInitialize
|
||
// SpInitialize
|
||
// SpShutdown
|
||
// SpGetInfo
|
||
//
|
||
// Helper functions:
|
||
//
|
||
// History: KDamour 10Mar00 Stolen from msv_sspi\ntlm.cxx
|
||
//
|
||
//---------------------------------------------------------------------
|
||
#define NTDIGEST_GLOBAL
|
||
#include "global.h"
|
||
|
||
|
||
/* Debugging information setup */
|
||
DEFINE_DEBUG2(Digest);
|
||
|
||
DEBUG_KEY MyDebugKeys[] = {{DEB_ERROR, "Error"},
|
||
{DEB_WARN, "Warning"},
|
||
{DEB_TRACE, "Trace"},
|
||
{DEB_TRACE_ASC, "TraceASC"},
|
||
{DEB_TRACE_ISC, "TraceISC"},
|
||
{DEB_TRACE_LSA, "TraceLSA"},
|
||
{DEB_TRACE_USER, "TraceUser"},
|
||
{DEB_TRACE_FUNC, "TraceFuncs"},
|
||
{DEB_TRACE_MEM, "TraceMem"},
|
||
{TRACE_STUFF, "Stuff"},
|
||
{0, NULL}
|
||
};
|
||
|
||
// set to TRUE once initialized
|
||
BOOL l_bDebugInitialized = FALSE;
|
||
BOOL l_bDigestInitialized = FALSE;
|
||
|
||
// Registry reading
|
||
HKEY g_hkBase = NULL;
|
||
HANDLE g_hParamEvent = NULL;
|
||
HANDLE g_hWait = NULL;
|
||
|
||
#define COMPUTER_NAME_SIZE (MAX_COMPUTERNAME_LENGTH + 1)
|
||
|
||
|
||
|
||
//+--------------------------------------------------------------------
|
||
//
|
||
// 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
|
||
DebugInitialize();
|
||
#endif
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "SpLsaModeInitialize: Entering\n"));
|
||
|
||
|
||
SECURITY_STATUS Status = SEC_E_OK;
|
||
|
||
if (LsaVersion != SECPKG_INTERFACE_VERSION)
|
||
{
|
||
DebugLog((DEB_ERROR, "SpLsaModeInitialize: Invalid LSA version: %d\n", LsaVersion));
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto CleanUp;
|
||
}
|
||
|
||
// Fill in the dispatch table for functions exported by ssp
|
||
g_NtDigestFunctionTable.InitializePackage = NULL;
|
||
g_NtDigestFunctionTable.LogonUser = NULL;
|
||
g_NtDigestFunctionTable.CallPackage = LsaApCallPackage;
|
||
g_NtDigestFunctionTable.LogonTerminated = LsaApLogonTerminated;
|
||
g_NtDigestFunctionTable.CallPackageUntrusted = LsaApCallPackageUntrusted;
|
||
g_NtDigestFunctionTable.LogonUserEx = NULL;
|
||
g_NtDigestFunctionTable.LogonUserEx2 = LsaApLogonUserEx2;
|
||
g_NtDigestFunctionTable.Initialize = SpInitialize;
|
||
g_NtDigestFunctionTable.Shutdown = SpShutdown;
|
||
g_NtDigestFunctionTable.GetInfo = SpGetInfo;
|
||
g_NtDigestFunctionTable.AcceptCredentials = SpAcceptCredentials;
|
||
g_NtDigestFunctionTable.AcquireCredentialsHandle = SpAcquireCredentialsHandle;
|
||
g_NtDigestFunctionTable.FreeCredentialsHandle = SpFreeCredentialsHandle;
|
||
g_NtDigestFunctionTable.SaveCredentials = SpSaveCredentials;
|
||
g_NtDigestFunctionTable.GetCredentials = SpGetCredentials;
|
||
g_NtDigestFunctionTable.DeleteCredentials = SpDeleteCredentials;
|
||
g_NtDigestFunctionTable.InitLsaModeContext = SpInitLsaModeContext;
|
||
g_NtDigestFunctionTable.AcceptLsaModeContext = SpAcceptLsaModeContext;
|
||
g_NtDigestFunctionTable.DeleteContext = SpDeleteContext;
|
||
g_NtDigestFunctionTable.ApplyControlToken = SpApplyControlToken;
|
||
g_NtDigestFunctionTable.GetUserInfo = SpGetUserInfo;
|
||
g_NtDigestFunctionTable.QueryCredentialsAttributes = SpQueryCredentialsAttributes ;
|
||
g_NtDigestFunctionTable.GetExtendedInformation = SpGetExtendedInformation ;
|
||
g_NtDigestFunctionTable.SetExtendedInformation = SpSetExtendedInformation ;
|
||
g_NtDigestFunctionTable.CallPackagePassthrough = LsaApCallPackagePassthrough;
|
||
|
||
|
||
*PackageVersion = SECPKG_INTERFACE_VERSION;
|
||
*Tables = &g_NtDigestFunctionTable;
|
||
*TableCount = 1;
|
||
|
||
CleanUp:
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "SpLsaModeInitialize:Leaving\n"));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
//+--------------------------------------------------------------------
|
||
//
|
||
// 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.(BUGBUG verify)
|
||
//
|
||
//---------------------------------------------------------------------
|
||
NTSTATUS NTAPI
|
||
SpInitialize(
|
||
IN ULONG_PTR pPackageId,
|
||
IN PSECPKG_PARAMETERS pParameters,
|
||
IN PLSA_SECPKG_FUNCTION_TABLE pFunctionTable
|
||
)
|
||
{
|
||
|
||
SECURITY_STATUS Status = SEC_E_OK;
|
||
DWORD dwWinErr = 0;
|
||
NT_PRODUCT_TYPE NtProductType = NtProductWinNt;
|
||
WCHAR wszComputerName[COMPUTER_NAME_SIZE];
|
||
DWORD dwComputerNameLen = COMPUTER_NAME_SIZE;
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "SpInitialize: Entering\n"));
|
||
|
||
// Indicate that we completed initialization
|
||
ASSERT(l_bDigestInitialized == FALSE); // never called more than once
|
||
l_bDigestInitialized = TRUE;
|
||
|
||
// Initialize global values
|
||
ZeroMemory(&g_strNtDigestUTF8ServerRealm, sizeof(g_strNtDigestUTF8ServerRealm));
|
||
ZeroMemory(&g_strNTDigestISO8859ServerRealm, sizeof(g_strNTDigestISO8859ServerRealm));
|
||
|
||
|
||
// Define time for AcquirCredentialHandle
|
||
// 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.
|
||
|
||
g_TimeForever.HighPart = 0x7FFFFFFF;
|
||
g_TimeForever.LowPart = 0xFFFFFFFF;
|
||
|
||
//
|
||
// All the following are global
|
||
//
|
||
|
||
g_NtDigestState = NtDigestLsaMode; /* enum */
|
||
g_NtDigestPackageId = pPackageId;
|
||
|
||
//
|
||
// Save away the Lsa functions
|
||
//
|
||
|
||
g_LsaFunctions = pFunctionTable;
|
||
|
||
|
||
//
|
||
// Establish the packagename
|
||
//
|
||
RtlInitUnicodeString(
|
||
&g_ustrNtDigestPackageName,
|
||
WDIGEST_SP_NAME
|
||
);
|
||
|
||
|
||
// Set the WorkstationName
|
||
if (!GetComputerNameExW(ComputerNameNetBIOS, wszComputerName, &dwComputerNameLen))
|
||
{
|
||
ZeroMemory(&g_ustrWorkstationName, sizeof(g_ustrWorkstationName));
|
||
DebugLog((DEB_ERROR, "SpInitialize: Get ComputerName error 0x%x\n", GetLastError()));
|
||
}
|
||
else
|
||
{
|
||
Status = UnicodeStringWCharDuplicate(&g_ustrWorkstationName, wszComputerName);
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
DebugLog((DEB_ERROR, "SpInitialize: ComputerName copy status 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
}
|
||
|
||
|
||
// Need to initialize Crypto stuff and nonce creations
|
||
Status = NonceInitialize();
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
DebugLog((DEB_ERROR, "SpInitialize: Error from NonceInitialize status 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
|
||
|
||
//
|
||
// Determine if this machine is running Windows NT or Lanman NT.
|
||
// LanMan NT runs on a domain controller.
|
||
//
|
||
|
||
if ( !RtlGetNtProductType( &NtProductType ) ) {
|
||
// Nt Product Type undefined - WinNt assumed
|
||
NtProductType = NtProductWinNt;
|
||
}
|
||
|
||
if (NtProductType == NtProductLanManNt)
|
||
{
|
||
g_fDomainController = TRUE; // Allow password checking only on DomainControllers
|
||
}
|
||
|
||
//
|
||
// Save the Parameters info to a global struct
|
||
//
|
||
g_NtDigestSecPkg.MachineState = pParameters->MachineState;
|
||
g_NtDigestSecPkg.SetupMode = pParameters->SetupMode;
|
||
g_NtDigestSecPkg.Version = pParameters->Version;
|
||
|
||
Status = UnicodeStringDuplicate(
|
||
&g_NtDigestSecPkg.DnsDomainName,
|
||
&(pParameters->DnsDomainName));
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
DebugLog((DEB_ERROR, "SpInitialize: Error from UnicodeStringDuplicate status 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
|
||
Status = UnicodeStringDuplicate(
|
||
&g_NtDigestSecPkg.DomainName,
|
||
&(pParameters->DomainName));
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
DebugLog((DEB_ERROR, "SpInitialize: Error from UnicodeStringDuplicate status 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
|
||
|
||
if (pParameters->DomainSid != NULL) {
|
||
Status = SidDuplicate( &g_NtDigestSecPkg.DomainSid,
|
||
pParameters->DomainSid );
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
DebugLog((DEB_ERROR, "SpInitialize: Error from SidDuplicate status 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
}
|
||
else
|
||
g_NtDigestSecPkg.DomainSid = NULL;
|
||
|
||
DebugLog((DEB_TRACE, "SpInitialize: DNSDomain = %wZ, Domain = %wZ\n", &(g_NtDigestSecPkg.DnsDomainName),
|
||
&(g_NtDigestSecPkg.DomainName)));
|
||
|
||
|
||
// For server challenges, precalculate the UTF-8 and ISO versions of the realm
|
||
|
||
Status = EncodeUnicodeString(&(g_NtDigestSecPkg.DnsDomainName), CP_8859_1, &g_strNTDigestISO8859ServerRealm, NULL);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
DebugLog((DEB_WARN, "SpInitialize: Error in encoding domain in ISO-8859-1\n"));
|
||
ZeroMemory(&g_strNTDigestISO8859ServerRealm, sizeof(STRING));
|
||
}
|
||
|
||
Status = EncodeUnicodeString(&(g_NtDigestSecPkg.DnsDomainName), CP_UTF8, &g_strNtDigestUTF8ServerRealm, NULL);
|
||
if (!NT_SUCCESS(Status))
|
||
{
|
||
DebugLog((DEB_WARN, "SpInitialize: Error in encoding domain in UTF-8\n"));
|
||
ZeroMemory(&g_strNtDigestUTF8ServerRealm, sizeof(STRING));
|
||
}
|
||
|
||
//
|
||
// Initialize the digest token source
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
g_DigestSource.SourceName,
|
||
NTDIGEST_TOKEN_NAME_A,
|
||
sizeof(NTDIGEST_TOKEN_NAME_A)
|
||
);
|
||
|
||
NtAllocateLocallyUniqueId(&g_DigestSource.SourceIdentifier);
|
||
|
||
|
||
//
|
||
// Init the LogonSession stuff
|
||
//
|
||
Status = LogSessHandlerInit();
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
DebugLog((DEB_ERROR, "SpInitialize: Error from LogSessHandlerInit status 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
|
||
//
|
||
// Init the Credential stuff
|
||
//
|
||
Status = CredHandlerInit();
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
DebugLog((DEB_ERROR, "SpInitialize: Error from CredHandlerInit status 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
|
||
//
|
||
// Init the Context stuff
|
||
//
|
||
Status = CtxtHandlerInit();
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
DebugLog((DEB_ERROR, "SpInitialize: Error from ContextInitialize status 0x%x\n", Status));
|
||
goto CleanUp;
|
||
}
|
||
|
||
//
|
||
// Read in the registry values for SSP configuration - in LSA space
|
||
//
|
||
SPLoadRegOptions();
|
||
|
||
CleanUp:
|
||
|
||
if (!NT_SUCCESS (Status))
|
||
{
|
||
SPUnloadRegOptions();
|
||
SpShutdown();
|
||
}
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "SpInitialize: Leaving\n"));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
//+--------------------------------------------------------------------
|
||
//
|
||
// 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
|
||
)
|
||
{
|
||
DebugLog((DEB_TRACE_FUNC, "SpShutdown: Entering\n"));
|
||
|
||
// Need to identify how to shutdown without causing faults with
|
||
// incoming messages
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "SpShutdown: Leaving\n"));
|
||
|
||
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. This function required
|
||
// to return SUCCESS for the package to stay loaded.
|
||
//
|
||
//---------------------------------------------------------------------
|
||
NTSTATUS NTAPI
|
||
SpGetInfo(
|
||
OUT PSecPkgInfo PackageInfo
|
||
)
|
||
{
|
||
DebugLog((DEB_TRACE_FUNC, "SpGetInfo: Entering\n"));
|
||
|
||
PackageInfo->fCapabilities = NTDIGEST_SP_CAPS;
|
||
PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
|
||
PackageInfo->wRPCID = RPC_C_AUTHN_DIGEST;
|
||
PackageInfo->cbMaxToken = NTDIGEST_SP_MAX_TOKEN_SIZE;
|
||
PackageInfo->Name = WDIGEST_SP_NAME;
|
||
PackageInfo->Comment = NTDIGEST_SP_COMMENT;
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "SpGetInfo: Leaving\n"));
|
||
|
||
return(SEC_E_OK);
|
||
}
|
||
|
||
// Misc SECPKG Functions
|
||
|
||
NTSTATUS NTAPI
|
||
SpGetUserInfo(
|
||
IN PLUID LogonId,
|
||
IN ULONG Flags,
|
||
OUT PSecurityUserData * UserData
|
||
)
|
||
{
|
||
DebugLog((DEB_TRACE_FUNC, "SpGetUserInfo: Entering/Leaving\n"));
|
||
|
||
// FIXIFX Fields of UserData are username, domain, server
|
||
|
||
UNREFERENCED_PARAMETER(LogonId);
|
||
UNREFERENCED_PARAMETER(Flags);
|
||
UNREFERENCED_PARAMETER(UserData);
|
||
|
||
return(SEC_E_UNSUPPORTED_FUNCTION);
|
||
}
|
||
|
||
//+---------------------------------------------------------------------------
|
||
//
|
||
// Function: SpGetExtendedInformation
|
||
//
|
||
// Synopsis: Return extended information to the LSA
|
||
//
|
||
// Arguments: [Class] -- Information Class
|
||
// [pInfo] -- Returned Information Pointer
|
||
//
|
||
//
|
||
// Notes:
|
||
//
|
||
//----------------------------------------------------------------------------
|
||
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 = 0;
|
||
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "SpGetExtendedInformation: Entering\n"));
|
||
|
||
switch ( Class )
|
||
{
|
||
|
||
case SecpkgWowClientDll:
|
||
|
||
//
|
||
// This indicates that we're smart enough to handle wow client processes
|
||
//
|
||
|
||
Information = (PSECPKG_EXTENDED_INFORMATION)
|
||
DigestAllocateMemory( 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"\\" NTDIGEST_DLL_NAME,
|
||
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 )
|
||
{
|
||
DigestFreeMemory( Information );
|
||
}
|
||
|
||
DebugLog((DEB_TRACE_FUNC, "SpGetExtendedInformation: Leaving Status %d\n", Status));
|
||
|
||
return Status ;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS NTAPI
|
||
SpSetExtendedInformation(
|
||
IN SECPKG_EXTENDED_INFORMATION_CLASS Class,
|
||
IN PSECPKG_EXTENDED_INFORMATION Info
|
||
)
|
||
{
|
||
DebugLog((DEB_TRACE_FUNC, "SpSetExtendedInformation: Entering/Leaving \n"));
|
||
|
||
UNREFERENCED_PARAMETER(Class);
|
||
UNREFERENCED_PARAMETER(Info);
|
||
return(SEC_E_UNSUPPORTED_FUNCTION) ;
|
||
}
|
||
|
||
//
|
||
// Registry Reading routines
|
||
// This routine is called in single-threaded mode from the LSA for SpInitialize and SPInstanceInit
|
||
// In user applications only SPInstanceInit calls this function
|
||
//
|
||
BOOL SPLoadRegOptions(void)
|
||
{
|
||
if (NULL != g_hParamEvent)
|
||
{
|
||
// Already called - no need to re-execute
|
||
DebugLog((DEB_TRACE, "SPLoadRegOptions: Already initialized - Leaving \n"));
|
||
return TRUE;
|
||
}
|
||
|
||
g_hParamEvent = CreateEvent(NULL,
|
||
FALSE,
|
||
FALSE,
|
||
NULL);
|
||
|
||
DigestWatchParamKey(g_hParamEvent, FALSE);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
void SPUnloadRegOptions(void)
|
||
{
|
||
if (NULL != g_hWait)
|
||
{
|
||
RtlDeregisterWaitEx(g_hWait, (HANDLE)-1);
|
||
g_hWait = NULL;
|
||
}
|
||
|
||
if(NULL != g_hkBase)
|
||
{
|
||
RegCloseKey(g_hkBase);
|
||
g_hkBase = NULL;
|
||
}
|
||
|
||
if(NULL != g_hParamEvent)
|
||
{
|
||
CloseHandle(g_hParamEvent);
|
||
g_hParamEvent = NULL;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
// Helper function to read in a DWORD - sets value if not present in registry
|
||
void
|
||
ReadDwordRegistrySetting(
|
||
HKEY hReadKey,
|
||
HKEY hWriteKey,
|
||
LPCTSTR pszValueName,
|
||
DWORD * pdwValue,
|
||
DWORD dwDefaultValue)
|
||
{
|
||
DWORD dwSize = 0;
|
||
DWORD dwType = 0;
|
||
|
||
dwSize = sizeof(DWORD);
|
||
if(RegQueryValueEx(hReadKey,
|
||
pszValueName,
|
||
NULL,
|
||
&dwType,
|
||
(PUCHAR)pdwValue,
|
||
&dwSize) != STATUS_SUCCESS)
|
||
{
|
||
*pdwValue = dwDefaultValue;
|
||
|
||
if(hWriteKey)
|
||
{
|
||
RegSetValueEx(hWriteKey,
|
||
pszValueName,
|
||
0,
|
||
REG_DWORD,
|
||
(PUCHAR)pdwValue,
|
||
sizeof(DWORD));
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// Can be called at any time to change the default values
|
||
// As long as a DWORD assignment can be done in a single step
|
||
BOOL
|
||
NtDigestReadRegistry(BOOL fFirstTime)
|
||
{
|
||
DWORD dwBool = 0;
|
||
DWORD dwDebug = 0;
|
||
|
||
HKEY hWriteKey = 0;
|
||
|
||
|
||
// Open top-level key that has write access.
|
||
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
||
REG_DIGEST_BASE,
|
||
0,
|
||
KEY_READ | KEY_SET_VALUE,
|
||
&hWriteKey) != STATUS_SUCCESS)
|
||
{
|
||
hWriteKey = 0;
|
||
}
|
||
|
||
|
||
// "LifeTime"
|
||
ReadDwordRegistrySetting(
|
||
g_hkBase,
|
||
hWriteKey,
|
||
REG_DIGEST_OPT_LIFETIME,
|
||
&g_dwParameter_Lifetime,
|
||
PARAMETER_LIFETIME);
|
||
|
||
// "Negotiate" Supported - BOOL value
|
||
ReadDwordRegistrySetting(
|
||
g_hkBase,
|
||
hWriteKey,
|
||
REG_DIGEST_OPT_NEGOTIATE,
|
||
&dwBool,
|
||
PARAMETER_NEGOTIATE);
|
||
if (dwBool)
|
||
g_fParameter_Negotiate = TRUE;
|
||
else
|
||
g_fParameter_Negotiate = FALSE;
|
||
|
||
// UTF8 Supported in HTTP mode - BOOL value
|
||
ReadDwordRegistrySetting(
|
||
g_hkBase,
|
||
hWriteKey,
|
||
REG_DIGEST_OPT_UTF8HTTP,
|
||
&dwBool,
|
||
PARAMETER_UTF8_HTTP);
|
||
if (dwBool)
|
||
g_fParameter_UTF8HTTP = TRUE;
|
||
else
|
||
g_fParameter_UTF8HTTP = FALSE;
|
||
|
||
// UTF8 supported in SASL - BOOL value
|
||
ReadDwordRegistrySetting(
|
||
g_hkBase,
|
||
hWriteKey,
|
||
REG_DIGEST_OPT_UTF8SASL,
|
||
&dwBool,
|
||
PARAMETER_UTF8_SASL);
|
||
if (dwBool)
|
||
g_fParameter_UTF8SASL = TRUE;
|
||
else
|
||
g_fParameter_UTF8SASL = FALSE;
|
||
|
||
// MaxContextCount
|
||
/*
|
||
ReadDwordRegistrySetting(
|
||
g_hkBase,
|
||
hWriteKey,
|
||
REG_DIGEST_OPT_MAXCTXTCOUNT,
|
||
&g_dwParameter_MaxCtxtCount,
|
||
PARAMETER_MAXCTXTCOUNT);
|
||
*/
|
||
|
||
#if DBG
|
||
// DebugLevel
|
||
ReadDwordRegistrySetting(
|
||
g_hkBase,
|
||
hWriteKey,
|
||
REG_DIGEST_OPT_DEBUGLEVEL,
|
||
&dwDebug,
|
||
0);
|
||
DigestInfoLevel = dwDebug; // Turn on/off selected messages
|
||
|
||
#endif
|
||
|
||
if(hWriteKey)
|
||
{
|
||
RegCloseKey(hWriteKey);
|
||
hWriteKey = 0;
|
||
}
|
||
|
||
DebugLog((DEB_TRACE, "NtDigestReadRegistry: Lifetime %lu, Negotiate %d, UTF-8 HTTP %d, UTF-8 SASL %d, DebugLevel 0x%x\n",
|
||
g_dwParameter_Lifetime,
|
||
g_fParameter_Negotiate,
|
||
g_fParameter_UTF8HTTP,
|
||
g_fParameter_UTF8SASL,
|
||
dwDebug));
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
// This routine is called in single-threaded mode from the LSA for SpLsaModeInitialize and SPInstanceInit
|
||
// In user applications only SPInstanceInit calls this function
|
||
void
|
||
DebugInitialize(void)
|
||
{
|
||
#if DBG
|
||
if (l_bDebugInitialized == TRUE)
|
||
{
|
||
return;
|
||
}
|
||
l_bDebugInitialized = TRUE;
|
||
DigestInitDebug(MyDebugKeys);
|
||
DigestInfoLevel = 0x0; // Turn on OFF messages - Registry read will adjust which ones to keep on
|
||
#endif
|
||
return;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////
|
||
//
|
||
// Name: DigestWatchParamKey
|
||
//
|
||
// Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
|
||
// debug level, then utilizes thread pool to wait on
|
||
// changes to this registry key. Enables dynamic debug
|
||
// level changes, as this function will also be callback
|
||
// if registry key modified.
|
||
//
|
||
// Arguments: pCtxt is actually a HANDLE to an event. This event
|
||
// will be triggered when key is modified.
|
||
//
|
||
// Notes: .
|
||
//
|
||
VOID
|
||
DigestWatchParamKey(
|
||
PVOID pCtxt,
|
||
BOOLEAN fWaitStatus)
|
||
{
|
||
NTSTATUS Status;
|
||
LONG lRes = ERROR_SUCCESS;
|
||
BOOL fFirstTime = FALSE;
|
||
DWORD disp;
|
||
|
||
if(g_hkBase == NULL)
|
||
{
|
||
// First time we've been called.
|
||
Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
|
||
REG_DIGEST_BASE,
|
||
0,
|
||
TEXT(""),
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ,
|
||
NULL,
|
||
&g_hkBase,
|
||
&disp);
|
||
if(Status)
|
||
{
|
||
DebugLog((DEB_WARN,"Failed to open WDigest key: 0x%x\n", Status));
|
||
return;
|
||
}
|
||
|
||
fFirstTime = TRUE;
|
||
}
|
||
|
||
if(pCtxt != NULL)
|
||
{
|
||
if (NULL != g_hWait)
|
||
{
|
||
Status = RtlDeregisterWait(g_hWait);
|
||
if(!NT_SUCCESS(Status))
|
||
{
|
||
DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
|
||
goto Reregister;
|
||
}
|
||
}
|
||
|
||
lRes = RegNotifyChangeKeyValue(
|
||
g_hkBase,
|
||
TRUE,
|
||
REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
|
||
(HANDLE)pCtxt,
|
||
TRUE);
|
||
|
||
if (ERROR_SUCCESS != lRes)
|
||
{
|
||
DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
|
||
// we're tanked now. No further notifications, so get this one
|
||
}
|
||
}
|
||
|
||
NtDigestReadRegistry(fFirstTime);
|
||
|
||
Reregister:
|
||
|
||
if(pCtxt != NULL)
|
||
{
|
||
Status = RtlRegisterWait(&g_hWait,
|
||
(HANDLE)pCtxt,
|
||
DigestWatchParamKey,
|
||
(HANDLE)pCtxt,
|
||
INFINITE,
|
||
WT_EXECUTEINPERSISTENTIOTHREAD|
|
||
WT_EXECUTEONLYONCE);
|
||
}
|
||
}
|
||
|
||
|
||
|