Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

922 lines
27 KiB

  1. //+--------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 2000
  6. //
  7. // File: ntdigest.c
  8. //
  9. // Contents: main entrypoints for the digest security package
  10. // SpLsaModeInitialize
  11. // SpInitialize
  12. // SpShutdown
  13. // SpGetInfo
  14. //
  15. // Helper functions:
  16. //
  17. // History: KDamour 10Mar00 Stolen from msv_sspi\ntlm.cxx
  18. //
  19. //---------------------------------------------------------------------
  20. #define NTDIGEST_GLOBAL
  21. #include "global.h"
  22. #if defined (_MSC_VER)
  23. #if _MSC_VER >= 1200
  24. #pragma warning(push)
  25. #endif
  26. #pragma warning(disable:4201) // Disable warning/error for nameless struct/union
  27. #endif
  28. #include <wow64t.h>
  29. #if defined (_MSC_VER) && ( _MSC_VER >= 800 )
  30. #if _MSC_VER >= 1200
  31. #pragma warning(pop)
  32. #else
  33. #pragma warning(default:4201) // Disable warning/error for nameless struct/union
  34. #endif
  35. #endif
  36. /* Debugging information setup */
  37. DEFINE_DEBUG2(Digest);
  38. DEBUG_KEY MyDebugKeys[] = {{DEB_ERROR, "Error"},
  39. {DEB_WARN, "Warning"},
  40. {DEB_TRACE, "Trace"},
  41. {DEB_TRACE_ASC, "TraceASC"},
  42. {DEB_TRACE_ISC, "TraceISC"},
  43. {DEB_TRACE_LSA, "TraceLSA"},
  44. {DEB_TRACE_USER, "TraceUser"},
  45. {DEB_TRACE_FUNC, "TraceFuncs"},
  46. {DEB_TRACE_MEM, "TraceMem"},
  47. {TRACE_STUFF, "Stuff"},
  48. {0, NULL}
  49. };
  50. // set to TRUE once initialized
  51. BOOL l_bDebugInitialized = FALSE;
  52. BOOL l_bDigestInitialized = FALSE;
  53. // Registry reading
  54. HKEY g_hkBase = NULL;
  55. HANDLE g_hParamEvent = NULL;
  56. HANDLE g_hWait = NULL;
  57. #define COMPUTER_NAME_SIZE (MAX_COMPUTERNAME_LENGTH + 1)
  58. #ifdef ROGUE_DC
  59. HKEY g_hDigestRogueKey = NULL;
  60. // Select same location as Kerberos
  61. #define REG_DIGEST_ROGUE_BASE L"System\\CurrentControlSet\\Services\\Kdc\\Rogue"
  62. #endif
  63. //+--------------------------------------------------------------------
  64. //
  65. // Function: SpLsaModeInitialize
  66. //
  67. // Synopsis: This function is called by the LSA when this DLL is loaded.
  68. // It returns security package function tables for all
  69. // security packages in the DLL.
  70. //
  71. // Arguments: LsaVersion - Version number of the LSA
  72. // PackageVersion - Returns version number of the package
  73. // Tables - Returns array of function tables for the package
  74. // TableCount - Returns number of entries in array of
  75. // function tables.
  76. //
  77. // Returns: PackageVersion (as above)
  78. // Tables (as above)
  79. // TableCount (as above)
  80. //
  81. // Notes:
  82. //
  83. //---------------------------------------------------------------------
  84. NTSTATUS NTAPI
  85. SpLsaModeInitialize(
  86. IN ULONG LsaVersion,
  87. OUT PULONG PackageVersion,
  88. OUT PSECPKG_FUNCTION_TABLE * Tables,
  89. OUT PULONG TableCount
  90. )
  91. {
  92. #if DBG
  93. DebugInitialize();
  94. #endif
  95. DebugLog((DEB_TRACE_FUNC, "SpLsaModeInitialize: Entering\n"));
  96. SECURITY_STATUS Status = SEC_E_OK;
  97. if (LsaVersion != SECPKG_INTERFACE_VERSION)
  98. {
  99. DebugLog((DEB_ERROR, "SpLsaModeInitialize: Invalid LSA version: %d\n", LsaVersion));
  100. Status = STATUS_INVALID_PARAMETER;
  101. goto CleanUp;
  102. }
  103. // Fill in the dispatch table for functions exported by ssp
  104. g_NtDigestFunctionTable.InitializePackage = NULL;
  105. g_NtDigestFunctionTable.LogonUser = NULL;
  106. g_NtDigestFunctionTable.CallPackage = LsaApCallPackage;
  107. g_NtDigestFunctionTable.LogonTerminated = LsaApLogonTerminated;
  108. g_NtDigestFunctionTable.CallPackageUntrusted = LsaApCallPackageUntrusted;
  109. g_NtDigestFunctionTable.LogonUserEx = NULL;
  110. g_NtDigestFunctionTable.LogonUserEx2 = LsaApLogonUserEx2;
  111. g_NtDigestFunctionTable.Initialize = SpInitialize;
  112. g_NtDigestFunctionTable.Shutdown = SpShutdown;
  113. g_NtDigestFunctionTable.GetInfo = SpGetInfo;
  114. g_NtDigestFunctionTable.AcceptCredentials = SpAcceptCredentials;
  115. g_NtDigestFunctionTable.AcquireCredentialsHandle = SpAcquireCredentialsHandle;
  116. g_NtDigestFunctionTable.FreeCredentialsHandle = SpFreeCredentialsHandle;
  117. g_NtDigestFunctionTable.SaveCredentials = SpSaveCredentials;
  118. g_NtDigestFunctionTable.GetCredentials = SpGetCredentials;
  119. g_NtDigestFunctionTable.DeleteCredentials = SpDeleteCredentials;
  120. g_NtDigestFunctionTable.InitLsaModeContext = SpInitLsaModeContext;
  121. g_NtDigestFunctionTable.AcceptLsaModeContext = SpAcceptLsaModeContext;
  122. g_NtDigestFunctionTable.DeleteContext = SpDeleteContext;
  123. g_NtDigestFunctionTable.ApplyControlToken = SpApplyControlToken;
  124. g_NtDigestFunctionTable.GetUserInfo = SpGetUserInfo;
  125. g_NtDigestFunctionTable.QueryCredentialsAttributes = SpQueryCredentialsAttributes ;
  126. g_NtDigestFunctionTable.GetExtendedInformation = SpGetExtendedInformation ;
  127. g_NtDigestFunctionTable.SetExtendedInformation = SpSetExtendedInformation ;
  128. g_NtDigestFunctionTable.CallPackagePassthrough = LsaApCallPackagePassthrough;
  129. *PackageVersion = SECPKG_INTERFACE_VERSION;
  130. *Tables = &g_NtDigestFunctionTable;
  131. *TableCount = 1;
  132. CleanUp:
  133. DebugLog((DEB_TRACE_FUNC, "SpLsaModeInitialize:Leaving\n"));
  134. return(Status);
  135. }
  136. //+--------------------------------------------------------------------
  137. //
  138. // Function: SpInitialize
  139. //
  140. // Synopsis: Initializes the Security package
  141. //
  142. // Arguments: PackageId - Contains ID for this package assigned by LSA
  143. // Parameters - Contains machine-specific information
  144. // FunctionTable - Contains table of LSA helper routines
  145. //
  146. // Returns: None
  147. //
  148. // Notes: Everything that was done in LsaApInitializePackage
  149. // should be done here. Lsa assures us that only
  150. // one thread is executing this at a time. Don't
  151. // have to worry about concurrency problems.(BUGBUG verify)
  152. //
  153. //---------------------------------------------------------------------
  154. NTSTATUS NTAPI
  155. SpInitialize(
  156. IN ULONG_PTR pPackageId,
  157. IN PSECPKG_PARAMETERS pParameters,
  158. IN PLSA_SECPKG_FUNCTION_TABLE pFunctionTable
  159. )
  160. {
  161. SECURITY_STATUS Status = SEC_E_OK;
  162. NT_PRODUCT_TYPE NtProductType = NtProductWinNt;
  163. WCHAR wszComputerName[COMPUTER_NAME_SIZE];
  164. DWORD dwComputerNameLen = COMPUTER_NAME_SIZE;
  165. DebugLog((DEB_TRACE_FUNC, "SpInitialize: Entering\n"));
  166. // Indicate that we completed initialization
  167. ASSERT(l_bDigestInitialized == FALSE); // never called more than once
  168. l_bDigestInitialized = TRUE;
  169. // Initialize global values
  170. ZeroMemory(&g_strNtDigestUTF8ServerRealm, sizeof(g_strNtDigestUTF8ServerRealm));
  171. ZeroMemory(&g_strNTDigestISO8859ServerRealm, sizeof(g_strNTDigestISO8859ServerRealm));
  172. // Define time for AcquirCredentialHandle
  173. // We really need this to be a day less than maxtime so when callers
  174. // of sspi convert to utc, they won't get time in the past.
  175. g_TimeForever.HighPart = 0x7FFFFFFF;
  176. g_TimeForever.LowPart = 0xFFFFFFFF;
  177. //
  178. // All the following are global
  179. //
  180. g_NtDigestState = NtDigestLsaMode; /* enum */
  181. g_NtDigestPackageId = pPackageId;
  182. //
  183. // Save away the Lsa functions
  184. //
  185. g_LsaFunctions = pFunctionTable;
  186. // Initialize access to Registry and read in the values
  187. NtDigestInitReadRegistry();
  188. //
  189. // Establish the packagename
  190. //
  191. RtlInitUnicodeString(
  192. &g_ustrNtDigestPackageName,
  193. WDIGEST_SP_NAME
  194. );
  195. // Set the WorkstationName
  196. if (!GetComputerNameExW(ComputerNameNetBIOS, wszComputerName, &dwComputerNameLen))
  197. {
  198. ZeroMemory(&g_ustrWorkstationName, sizeof(g_ustrWorkstationName));
  199. DebugLog((DEB_ERROR, "SpInitialize: Get ComputerName error 0x%x\n", GetLastError()));
  200. }
  201. else
  202. {
  203. Status = UnicodeStringWCharDuplicate(&g_ustrWorkstationName, wszComputerName, 0);
  204. if (!NT_SUCCESS (Status))
  205. {
  206. DebugLog((DEB_ERROR, "SpInitialize: ComputerName copy status 0x%x\n", Status));
  207. goto CleanUp;
  208. }
  209. }
  210. // Need to initialize Crypto stuff and nonce creations
  211. Status = NonceInitialize();
  212. if (!NT_SUCCESS (Status))
  213. {
  214. DebugLog((DEB_ERROR, "SpInitialize: Error from NonceInitialize status 0x%x\n", Status));
  215. goto CleanUp;
  216. }
  217. //
  218. // Determine if this machine is running Windows NT or Lanman NT.
  219. // LanMan NT runs on a domain controller.
  220. //
  221. if ( !RtlGetNtProductType( &NtProductType ) ) {
  222. // Nt Product Type undefined - WinNt assumed
  223. NtProductType = NtProductWinNt;
  224. }
  225. if (NtProductType == NtProductLanManNt)
  226. {
  227. g_fDomainController = TRUE; // Allow password checking only on DomainControllers
  228. }
  229. //
  230. // Save the Parameters info to a global struct
  231. //
  232. g_NtDigestSecPkg.MachineState = pParameters->MachineState;
  233. g_NtDigestSecPkg.SetupMode = pParameters->SetupMode;
  234. g_NtDigestSecPkg.Version = pParameters->Version;
  235. Status = UnicodeStringDuplicate(
  236. &g_NtDigestSecPkg.DnsDomainName,
  237. &(pParameters->DnsDomainName));
  238. if (!NT_SUCCESS (Status))
  239. {
  240. DebugLog((DEB_ERROR, "SpInitialize: Error from UnicodeStringDuplicate status 0x%x\n", Status));
  241. goto CleanUp;
  242. }
  243. Status = UnicodeStringDuplicate(
  244. &g_NtDigestSecPkg.DomainName,
  245. &(pParameters->DomainName));
  246. if (!NT_SUCCESS (Status))
  247. {
  248. DebugLog((DEB_ERROR, "SpInitialize: Error from UnicodeStringDuplicate status 0x%x\n", Status));
  249. goto CleanUp;
  250. }
  251. if (pParameters->DomainSid != NULL) {
  252. Status = SidDuplicate( &g_NtDigestSecPkg.DomainSid,
  253. pParameters->DomainSid );
  254. if (!NT_SUCCESS (Status))
  255. {
  256. DebugLog((DEB_ERROR, "SpInitialize: Error from SidDuplicate status 0x%x\n", Status));
  257. goto CleanUp;
  258. }
  259. }
  260. else
  261. g_NtDigestSecPkg.DomainSid = NULL;
  262. DebugLog((DEB_TRACE, "SpInitialize: DNSDomain = %wZ, Domain = %wZ\n", &(g_NtDigestSecPkg.DnsDomainName),
  263. &(g_NtDigestSecPkg.DomainName)));
  264. // For server challenges, precalculate the UTF-8 and ISO versions of the realm
  265. Status = EncodeUnicodeString(&(g_NtDigestSecPkg.DnsDomainName), CP_8859_1, &g_strNTDigestISO8859ServerRealm, NULL);
  266. if (!NT_SUCCESS(Status))
  267. {
  268. DebugLog((DEB_WARN, "SpInitialize: Error in encoding domain in ISO-8859-1\n"));
  269. ZeroMemory(&g_strNTDigestISO8859ServerRealm, sizeof(STRING));
  270. }
  271. Status = EncodeUnicodeString(&(g_NtDigestSecPkg.DnsDomainName), CP_UTF8, &g_strNtDigestUTF8ServerRealm, NULL);
  272. if (!NT_SUCCESS(Status))
  273. {
  274. DebugLog((DEB_WARN, "SpInitialize: Error in encoding domain in UTF-8\n"));
  275. ZeroMemory(&g_strNtDigestUTF8ServerRealm, sizeof(STRING));
  276. }
  277. //
  278. // Initialize the digest token source
  279. //
  280. RtlCopyMemory(
  281. g_DigestSource.SourceName,
  282. NTDIGEST_TOKEN_NAME_A,
  283. sizeof(NTDIGEST_TOKEN_NAME_A)
  284. );
  285. NtAllocateLocallyUniqueId(&g_DigestSource.SourceIdentifier);
  286. //
  287. // Init the LogonSession stuff
  288. //
  289. Status = LogSessHandlerInit();
  290. if (!NT_SUCCESS (Status))
  291. {
  292. DebugLog((DEB_ERROR, "SpInitialize: Error from LogSessHandlerInit status 0x%x\n", Status));
  293. goto CleanUp;
  294. }
  295. //
  296. // Init the Credential stuff
  297. //
  298. Status = CredHandlerInit();
  299. if (!NT_SUCCESS (Status))
  300. {
  301. DebugLog((DEB_ERROR, "SpInitialize: Error from CredHandlerInit status 0x%x\n", Status));
  302. goto CleanUp;
  303. }
  304. //
  305. // Init the Context stuff
  306. //
  307. Status = CtxtHandlerInit();
  308. if (!NT_SUCCESS (Status))
  309. {
  310. DebugLog((DEB_ERROR, "SpInitialize: Error from ContextInitialize status 0x%x\n", Status));
  311. goto CleanUp;
  312. }
  313. //
  314. // Read in the registry values for SSP configuration - in LSA space
  315. //
  316. SPLoadRegOptions();
  317. CleanUp:
  318. if (!NT_SUCCESS (Status))
  319. {
  320. SPUnloadRegOptions();
  321. SpShutdown();
  322. }
  323. DebugLog((DEB_TRACE_FUNC, "SpInitialize: Leaving\n"));
  324. return(Status);
  325. }
  326. //+--------------------------------------------------------------------
  327. //
  328. // Function: SpShutdown
  329. //
  330. // Synopsis: Exported function to shutdown the Security package.
  331. //
  332. // Effects: Forces the freeing of all credentials, contexts
  333. // and frees all global data
  334. //
  335. // Arguments: none
  336. //
  337. // Returns:
  338. //
  339. // Notes: SEC_E_OK in all cases
  340. // Most of the stuff was taken from SspCommonShutdown()
  341. // from svcdlls\ntlmssp\common\initcomn.c
  342. //
  343. //
  344. //---------------------------------------------------------------------
  345. NTSTATUS NTAPI
  346. SpShutdown(
  347. VOID
  348. )
  349. {
  350. DebugLog((DEB_TRACE_FUNC, "SpShutdown: Entering\n"));
  351. // Need to identify how to shutdown without causing faults with
  352. // incoming messages
  353. DebugLog((DEB_TRACE_FUNC, "SpShutdown: Leaving\n"));
  354. return(SEC_E_OK);
  355. }
  356. //+--------------------------------------------------------------------
  357. //
  358. // Function: SpGetInfo
  359. //
  360. // Synopsis: Returns information about the package
  361. //
  362. // Effects: returns pointers to global data
  363. //
  364. // Arguments: PackageInfo - Receives security package information
  365. //
  366. // Returns: SEC_E_OK in all cases
  367. //
  368. // Notes: Pointers to constants ok. Lsa will copy the data
  369. // before sending it to someone else. This function required
  370. // to return SUCCESS for the package to stay loaded.
  371. //
  372. //---------------------------------------------------------------------
  373. NTSTATUS NTAPI
  374. SpGetInfo(
  375. OUT PSecPkgInfo PackageInfo
  376. )
  377. {
  378. DebugLog((DEB_TRACE_FUNC, "SpGetInfo: Entering\n"));
  379. PackageInfo->fCapabilities = NTDIGEST_SP_CAPS;
  380. PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
  381. PackageInfo->wRPCID = RPC_C_AUTHN_DIGEST;
  382. PackageInfo->cbMaxToken = NTDIGEST_SP_MAX_TOKEN_SIZE;
  383. PackageInfo->Name = WDIGEST_SP_NAME;
  384. PackageInfo->Comment = NTDIGEST_SP_COMMENT;
  385. DebugLog((DEB_TRACE_FUNC, "SpGetInfo: Leaving\n"));
  386. return(SEC_E_OK);
  387. }
  388. // Misc SECPKG Functions
  389. NTSTATUS NTAPI
  390. SpGetUserInfo(
  391. IN PLUID LogonId,
  392. IN ULONG Flags,
  393. OUT PSecurityUserData * UserData
  394. )
  395. {
  396. DebugLog((DEB_TRACE_FUNC, "SpGetUserInfo: Entering/Leaving\n"));
  397. // FIXIFX Fields of UserData are username, domain, server
  398. UNREFERENCED_PARAMETER(LogonId);
  399. UNREFERENCED_PARAMETER(Flags);
  400. UNREFERENCED_PARAMETER(UserData);
  401. return(SEC_E_UNSUPPORTED_FUNCTION);
  402. }
  403. //+---------------------------------------------------------------------------
  404. //
  405. // Function: SpGetExtendedInformation
  406. //
  407. // Synopsis: Return extended information to the LSA
  408. //
  409. // Arguments: [Class] -- Information Class
  410. // [pInfo] -- Returned Information Pointer
  411. //
  412. //
  413. // Notes:
  414. //
  415. //----------------------------------------------------------------------------
  416. NTSTATUS
  417. NTAPI
  418. SpGetExtendedInformation(
  419. IN SECPKG_EXTENDED_INFORMATION_CLASS Class,
  420. OUT PSECPKG_EXTENDED_INFORMATION * ppInformation
  421. )
  422. {
  423. NTSTATUS Status = STATUS_SUCCESS;
  424. PSECPKG_EXTENDED_INFORMATION Information = NULL;
  425. ULONG Size = 0;
  426. DebugLog((DEB_TRACE_FUNC, "SpGetExtendedInformation: Entering\n"));
  427. switch ( Class )
  428. {
  429. case SecpkgWowClientDll:
  430. //
  431. // This indicates that we're smart enough to handle wow client processes
  432. //
  433. Information = (PSECPKG_EXTENDED_INFORMATION)
  434. DigestAllocateMemory( sizeof( SECPKG_EXTENDED_INFORMATION ) +
  435. (MAX_PATH * sizeof(WCHAR) ) );
  436. if ( Information == NULL )
  437. {
  438. Status = STATUS_INSUFFICIENT_RESOURCES;
  439. DebugLog((DEB_ERROR, "SpGetExtendedInformation: Allocate Memory failed\n"));
  440. goto Cleanup ;
  441. }
  442. Information->Class = SecpkgWowClientDll ;
  443. Information->Info.WowClientDll.WowClientDllPath.Buffer = (PWSTR) (Information + 1);
  444. Size = ExpandEnvironmentStrings(
  445. L"%SystemRoot%\\" WOW64_SYSTEM_DIRECTORY_U L"\\" NTDIGEST_DLL_NAME,
  446. Information->Info.WowClientDll.WowClientDllPath.Buffer,
  447. MAX_PATH );
  448. if (Size == 0)
  449. {
  450. Status = STATUS_INSUFFICIENT_RESOURCES;
  451. DebugLog((DEB_ERROR, "SpGetExtendedInformation: ExpandEnvironmentStrings failed 0x%x\n", GetLastError()));
  452. goto Cleanup ;
  453. }
  454. Information->Info.WowClientDll.WowClientDllPath.Length = (USHORT) (Size * sizeof(WCHAR));
  455. Information->Info.WowClientDll.WowClientDllPath.MaximumLength = (USHORT) ((Size + 1) * sizeof(WCHAR) );
  456. *ppInformation = Information ;
  457. Information = NULL ;
  458. break;
  459. default:
  460. Status = SEC_E_UNSUPPORTED_FUNCTION ;
  461. }
  462. Cleanup:
  463. if ( Information != NULL )
  464. {
  465. DigestFreeMemory( Information );
  466. }
  467. DebugLog((DEB_TRACE_FUNC, "SpGetExtendedInformation: Leaving Status 0x%x\n", Status));
  468. return Status ;
  469. }
  470. NTSTATUS NTAPI
  471. SpSetExtendedInformation(
  472. IN SECPKG_EXTENDED_INFORMATION_CLASS Class,
  473. IN PSECPKG_EXTENDED_INFORMATION Info
  474. )
  475. {
  476. DebugLog((DEB_TRACE_FUNC, "SpSetExtendedInformation: Entering/Leaving \n"));
  477. UNREFERENCED_PARAMETER(Class);
  478. UNREFERENCED_PARAMETER(Info);
  479. return(SEC_E_UNSUPPORTED_FUNCTION) ;
  480. }
  481. //
  482. // Registry Reading routines
  483. // This routine is called in single-threaded mode from the LSA for SpInitialize and SPInstanceInit
  484. // In user applications only SPInstanceInit calls this function
  485. //
  486. BOOL SPLoadRegOptions(void)
  487. {
  488. if (NULL != g_hParamEvent)
  489. {
  490. // Already called - no need to re-execute
  491. DebugLog((DEB_TRACE, "SPLoadRegOptions: Already initialized - Leaving \n"));
  492. return TRUE;
  493. }
  494. g_hParamEvent = CreateEvent(NULL,
  495. FALSE,
  496. FALSE,
  497. NULL);
  498. DigestWatchParamKey(g_hParamEvent, FALSE);
  499. return TRUE;
  500. }
  501. void SPUnloadRegOptions(void)
  502. {
  503. if (NULL != g_hWait)
  504. {
  505. RtlDeregisterWaitEx(g_hWait, (HANDLE)-1);
  506. g_hWait = NULL;
  507. }
  508. if(NULL != g_hkBase)
  509. {
  510. RegCloseKey(g_hkBase);
  511. g_hkBase = NULL;
  512. }
  513. if(NULL != g_hParamEvent)
  514. {
  515. CloseHandle(g_hParamEvent);
  516. g_hParamEvent = NULL;
  517. }
  518. }
  519. // Helper function to read in a DWORD - sets value if not present in registry
  520. void
  521. ReadDwordRegistrySetting(
  522. HKEY hReadKey,
  523. HKEY hWriteKey,
  524. LPCTSTR pszValueName,
  525. DWORD * pdwValue,
  526. DWORD dwDefaultValue)
  527. {
  528. DWORD dwSize = 0;
  529. DWORD dwType = 0;
  530. dwSize = sizeof(DWORD);
  531. if(RegQueryValueEx(hReadKey,
  532. pszValueName,
  533. NULL,
  534. &dwType,
  535. (PUCHAR)pdwValue,
  536. &dwSize) != STATUS_SUCCESS)
  537. {
  538. *pdwValue = dwDefaultValue;
  539. if(hWriteKey)
  540. {
  541. RegSetValueEx(hWriteKey,
  542. pszValueName,
  543. 0,
  544. REG_DWORD,
  545. (PUCHAR)pdwValue,
  546. sizeof(DWORD));
  547. }
  548. }
  549. }
  550. // Can be called at any time to change the default values
  551. // As long as a DWORD assignment can be done in a single step
  552. BOOL
  553. NtDigestReadRegistry(BOOL fFirstTime)
  554. {
  555. DWORD dwVal = 0;
  556. HKEY hWriteKey = 0;
  557. UNREFERENCED_PARAMETER(fFirstTime);
  558. // Open top-level key that has write access.
  559. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  560. REG_DIGEST_BASE,
  561. 0,
  562. KEY_READ | KEY_SET_VALUE,
  563. &hWriteKey) != STATUS_SUCCESS)
  564. {
  565. hWriteKey = 0;
  566. }
  567. // "LifeTime"
  568. /*
  569. ReadDwordRegistrySetting(
  570. g_hkBase,
  571. hWriteKey,
  572. REG_DIGEST_OPT_LIFETIME,
  573. &g_dwParameter_Lifetime,
  574. PARAMETER_LIFETIME);
  575. */
  576. // "Negotiate" Supported - BOOL value
  577. ReadDwordRegistrySetting(
  578. g_hkBase,
  579. hWriteKey,
  580. REG_DIGEST_OPT_NEGOTIATE,
  581. &dwVal,
  582. PARAMETER_NEGOTIATE);
  583. if (dwVal)
  584. g_fParameter_Negotiate = TRUE;
  585. else
  586. g_fParameter_Negotiate = FALSE;
  587. // UTF8 Supported in HTTP mode - BOOL value
  588. ReadDwordRegistrySetting(
  589. g_hkBase,
  590. hWriteKey,
  591. REG_DIGEST_OPT_UTF8HTTP,
  592. &dwVal,
  593. PARAMETER_UTF8_HTTP);
  594. if (dwVal)
  595. g_fParameter_UTF8HTTP = TRUE;
  596. else
  597. g_fParameter_UTF8HTTP = FALSE;
  598. // UTF8 supported in SASL - BOOL value
  599. ReadDwordRegistrySetting(
  600. g_hkBase,
  601. hWriteKey,
  602. REG_DIGEST_OPT_UTF8SASL,
  603. &dwVal,
  604. PARAMETER_UTF8_SASL);
  605. if (dwVal)
  606. g_fParameter_UTF8SASL = TRUE;
  607. else
  608. g_fParameter_UTF8SASL = FALSE;
  609. // Read in ServerCompat bits
  610. ReadDwordRegistrySetting(
  611. g_hkBase,
  612. 0,
  613. REG_DIGEST_OPT_SERVERCOMPAT,
  614. &g_dwParameter_ServerCompat,
  615. PARAMETER_SERVERCOMPAT);
  616. // Read in ServerCompat bits
  617. ReadDwordRegistrySetting(
  618. g_hkBase,
  619. 0,
  620. REG_DIGEST_OPT_CLIENTCOMPAT,
  621. &g_dwParameter_ClientCompat,
  622. PARAMETER_CLIENTCOMPAT);
  623. #if DBG
  624. // DebugLevel
  625. ReadDwordRegistrySetting(
  626. g_hkBase,
  627. hWriteKey,
  628. REG_DIGEST_OPT_DEBUGLEVEL,
  629. &dwVal,
  630. 0);
  631. DigestInfoLevel = dwVal; // Turn on/off selected messages
  632. #endif
  633. if(hWriteKey)
  634. {
  635. RegCloseKey(hWriteKey);
  636. hWriteKey = 0;
  637. }
  638. DebugLog((DEB_TRACE, "NtDigestReadRegistry: Lifetime %lu, Negotiate %d, UTF-8 HTTP %d, UTF-8 SASL %d, DebugLevel 0x%x\n",
  639. g_dwParameter_Lifetime,
  640. g_fParameter_Negotiate,
  641. g_fParameter_UTF8HTTP,
  642. g_fParameter_UTF8SASL,
  643. dwVal));
  644. return TRUE;
  645. }
  646. // This routine is called in single-threaded mode from the LSA for SpLsaModeInitialize and SPInstanceInit
  647. // In user applications only SPInstanceInit calls this function
  648. void
  649. DebugInitialize(void)
  650. {
  651. #if DBG
  652. if (l_bDebugInitialized == TRUE)
  653. {
  654. return;
  655. }
  656. l_bDebugInitialized = TRUE;
  657. DigestInitDebug(MyDebugKeys);
  658. DigestInfoLevel = 0x0; // Turn on OFF messages - Registry read will adjust which ones to keep on
  659. #endif
  660. return;
  661. }
  662. ////////////////////////////////////////////////////////////////////
  663. //
  664. // Name: DigestWatchParamKey
  665. //
  666. // Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
  667. // debug level, then utilizes thread pool to wait on
  668. // changes to this registry key. Enables dynamic debug
  669. // level changes, as this function will also be callback
  670. // if registry key modified.
  671. //
  672. // Arguments: pCtxt is actually a HANDLE to an event. This event
  673. // will be triggered when key is modified.
  674. //
  675. // Notes: .
  676. //
  677. VOID
  678. DigestWatchParamKey(
  679. PVOID pCtxt,
  680. BOOLEAN fWaitStatus)
  681. {
  682. NTSTATUS Status = STATUS_SUCCESS;
  683. LONG lRes = ERROR_SUCCESS;
  684. BOOL fFirstTime = FALSE;
  685. UNREFERENCED_PARAMETER(fWaitStatus);
  686. if(g_hkBase == NULL)
  687. {
  688. DebugLog((DEB_WARN,"Failed to open WDigest key access: 0x%x\n", Status));
  689. return;
  690. }
  691. if(pCtxt != NULL)
  692. {
  693. if (NULL != g_hWait)
  694. {
  695. Status = RtlDeregisterWait(g_hWait);
  696. if(!NT_SUCCESS(Status))
  697. {
  698. DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
  699. goto Reregister;
  700. }
  701. }
  702. lRes = RegNotifyChangeKeyValue(
  703. g_hkBase,
  704. TRUE,
  705. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
  706. (HANDLE)pCtxt,
  707. TRUE);
  708. if (ERROR_SUCCESS != lRes)
  709. {
  710. DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
  711. // we're tanked now. No further notifications, so get this one
  712. }
  713. }
  714. NtDigestReadRegistry(fFirstTime);
  715. Reregister:
  716. if(pCtxt != NULL)
  717. {
  718. Status = RtlRegisterWait(&g_hWait,
  719. (HANDLE)pCtxt,
  720. DigestWatchParamKey,
  721. (HANDLE)pCtxt,
  722. INFINITE,
  723. WT_EXECUTEINPERSISTENTIOTHREAD|
  724. WT_EXECUTEONLYONCE);
  725. }
  726. }
  727. // Initialize the handle to access registry and read in the current parameters
  728. BOOL
  729. NtDigestInitReadRegistry()
  730. {
  731. LONG lRes = ERROR_SUCCESS;
  732. DWORD disp = 0;
  733. if(g_hkBase == NULL)
  734. {
  735. // First time we've been called.
  736. lRes = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  737. REG_DIGEST_BASE,
  738. 0,
  739. TEXT(""),
  740. REG_OPTION_NON_VOLATILE,
  741. KEY_READ,
  742. NULL,
  743. &g_hkBase,
  744. &disp);
  745. if(lRes)
  746. {
  747. DebugLog((DEB_WARN,"NtDigestInitReadRegistry: Failed to open WDigest key: 0x%x\n", lRes));
  748. return FALSE;
  749. }
  750. NtDigestReadRegistry(TRUE);
  751. }
  752. #ifdef ROGUE_DC
  753. if(g_hDigestRogueKey == NULL)
  754. {
  755. if ( ERROR_SUCCESS != RegOpenKeyExW(
  756. HKEY_LOCAL_MACHINE,
  757. REG_DIGEST_ROGUE_BASE,
  758. 0,
  759. KEY_READ,
  760. &g_hDigestRogueKey ))
  761. {
  762. DebugLog((DEB_WARN,"Failed to open \"rogue\" wdigest key\n" ));
  763. g_hDigestRogueKey = NULL;
  764. }
  765. }
  766. #endif
  767. return TRUE;
  768. }