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.

1552 lines
40 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation 1992 - 1996
  6. //
  7. // File: kerberos.cxx
  8. //
  9. // Contents: main entrypoints for the Kerberos security package
  10. //
  11. //
  12. // History: 16-April-1996 Created MikeSw
  13. // 26-Sep-1998 ChandanS
  14. // Added more debugging support etc.
  15. //
  16. //------------------------------------------------------------------------
  17. #include <kerb.hxx>
  18. #define KERBP_ALLOCATE
  19. #include <kerbp.h>
  20. #include <userapi.h>
  21. #include <safeboot.h>
  22. #include <wow64t.h>
  23. #ifdef RETAIL_LOG_SUPPORT
  24. static TCHAR THIS_FILE[]=TEXT(__FILE__);
  25. HANDLE g_hParamEvent = NULL;
  26. HKEY g_hKeyParams = NULL;
  27. #endif
  28. #if DBG
  29. extern LIST_ENTRY GlobalTicketList;
  30. #endif
  31. //
  32. // Flags for initialization progress in SpInitialize
  33. //
  34. #define KERB_INIT_EVENTS 0x00000001
  35. #define KERB_INIT_KDC_DATA 0x00000002
  36. #define KERB_INIT_OPEN_POLICY 0x00000004
  37. #define KERB_INIT_COMPUTER_NAME 0x00000008
  38. #define KERB_INIT_SCAVENGER 0x00000010
  39. #define KERB_INIT_LOGON_SESSION 0x00000020
  40. #define KERB_INIT_TICKET 0x00000040
  41. #define KERB_INIT_DOMAIN_NAME 0x00000100
  42. #define KERB_INIT_CRED_LIST 0x00000200
  43. #define KERB_INIT_CONTEXT_LIST 0x00000400
  44. #define KERB_INIT_TICKET_CACHE 0x00000800
  45. #define KERB_INIT_BINDING_CACHE 0x00001000
  46. #define KERB_INIT_SPN_CACHE 0x00002000
  47. #define KERB_INIT_S4U_CACHE 0x00004000
  48. #define KERB_INIT_MIT 0x00008000
  49. #define KERB_INIT_PKINIT 0x00010000
  50. #define KERB_INIT_SOCKETS 0x00020000
  51. #define KERB_INIT_DOMAIN_CHANGE 0x00040000
  52. #define KERB_INIT_NS_LOOKBACK_DETECTION 0x00080000
  53. #define KERB_INIT_NS_TIMER 0x00100000
  54. #ifndef WIN32_CHICAGO
  55. #ifdef RETAIL_LOG_SUPPORT
  56. DEFINE_DEBUG2(Kerb);
  57. extern DWORD KSuppInfoLevel; // needed to adjust values for common2 dir
  58. HANDLE g_hWait = NULL;
  59. DEBUG_KEY KerbDebugKeys[] = { {DEB_ERROR, "Error"},
  60. {DEB_WARN, "Warn"},
  61. {DEB_TRACE, "Trace"},
  62. {DEB_TRACE_API, "API"},
  63. {DEB_TRACE_CRED, "Cred"},
  64. {DEB_TRACE_CTXT, "Ctxt"},
  65. {DEB_TRACE_LSESS, "LSess"},
  66. {DEB_TRACE_LOGON, "Logon"},
  67. {DEB_TRACE_KDC, "KDC"},
  68. {DEB_TRACE_CTXT2, "Ctxt2"},
  69. {DEB_TRACE_TIME, "Time"},
  70. {DEB_TRACE_LOCKS, "Locks"},
  71. {DEB_TRACE_LEAKS, "Leaks"},
  72. {DEB_TRACE_SPN_CACHE, "SPN"},
  73. {DEB_S4U_ERROR, "S4uErr"},
  74. {DEB_TRACE_S4U, "S4u"},
  75. {DEB_TRACE_BND_CACHE, "Bnd"},
  76. {DEB_TRACE_LOOPBACK, "LoopBack"},
  77. {DEB_TRACE_TKT_RENEWAL, "Renew"},
  78. {DEB_TRACE_U2U, "U2U"},
  79. {DEB_TRACE_REFERRAL, "Refer"},
  80. {0, NULL},
  81. };
  82. VOID
  83. KerbInitializeDebugging(
  84. VOID
  85. )
  86. {
  87. KerbInitDebug(KerbDebugKeys);
  88. }
  89. #endif // RETAIL_LOG_SUPPORT
  90. ////////////////////////////////////////////////////////////////////
  91. //
  92. // Name: KerbGetKerbRegParams
  93. //
  94. // Synopsis: Gets the debug paramaters from the registry
  95. //
  96. // Arguments: HKEY to HKLM/System/CCS/LSA/Kerberos/Parameters
  97. //
  98. // Notes: Sets KerbInfolevel for debug spew
  99. //
  100. //
  101. void
  102. KerbGetKerbRegParams(HKEY ParamKey)
  103. {
  104. DWORD cbType, Value, cbSize;
  105. DWORD dwErr;
  106. #ifdef RETAIL_LOG_SUPPORT
  107. cbSize = sizeof(Value);
  108. Value = KerbInfoLevel;
  109. dwErr = RegQueryValueExW(
  110. ParamKey,
  111. WSZ_KERBDEBUGLEVEL,
  112. NULL,
  113. &cbType,
  114. (LPBYTE)&Value,
  115. &cbSize
  116. );
  117. if (dwErr != ERROR_SUCCESS || cbType != REG_DWORD)
  118. {
  119. if (dwErr == ERROR_FILE_NOT_FOUND)
  120. {
  121. // no registry value is present, don't want info
  122. // so reset to defaults
  123. #if DBG
  124. KSuppInfoLevel = KerbInfoLevel = DEB_ERROR;
  125. #else // fre
  126. KSuppInfoLevel = KerbInfoLevel = 0;
  127. #endif
  128. }else{
  129. D_DebugLog((DEB_WARN, "Failed to query DebugLevel: 0x%x\n", dwErr));
  130. }
  131. }
  132. KSuppInfoLevel = KerbInfoLevel = Value;
  133. cbSize = sizeof(Value);
  134. dwErr = RegQueryValueExW(
  135. ParamKey,
  136. WSZ_FILELOG,
  137. NULL,
  138. &cbType,
  139. (LPBYTE)&Value,
  140. &cbSize
  141. );
  142. if (dwErr == ERROR_SUCCESS)
  143. {
  144. KerbSetLoggingOption((BOOL) Value);
  145. }
  146. else if (dwErr == ERROR_FILE_NOT_FOUND)
  147. {
  148. KerbSetLoggingOption(FALSE);
  149. }
  150. #endif // RETAIL_LOG_SUPPORT
  151. cbSize = sizeof(Value);
  152. dwErr = RegQueryValueExW(
  153. ParamKey,
  154. KERB_PARAMETER_RETRY_PDC,
  155. NULL,
  156. &cbType,
  157. (LPBYTE)&Value,
  158. &cbSize
  159. );
  160. if (dwErr == ERROR_SUCCESS)
  161. {
  162. if ( Value != 0 )
  163. {
  164. KerbGlobalRetryPdc = TRUE;
  165. }
  166. else
  167. {
  168. KerbGlobalRetryPdc = FALSE;
  169. }
  170. }
  171. else if (dwErr == ERROR_FILE_NOT_FOUND)
  172. {
  173. KerbGlobalRetryPdc = FALSE;
  174. }
  175. //
  176. // Bug 356539: configuration key to regulate whether clients request
  177. // addresses in tickets
  178. //
  179. cbSize = sizeof(Value);
  180. dwErr = RegQueryValueExW(
  181. ParamKey,
  182. KERB_PARAMETER_CLIENT_IP_ADDRESSES,
  183. NULL,
  184. &cbType,
  185. (LPBYTE)&Value,
  186. &cbSize
  187. );
  188. if (dwErr == ERROR_SUCCESS)
  189. {
  190. if ( Value != 0 )
  191. {
  192. KerbGlobalUseClientIpAddresses = TRUE;
  193. }
  194. else
  195. {
  196. KerbGlobalUseClientIpAddresses = FALSE;
  197. }
  198. }
  199. else if (dwErr == ERROR_FILE_NOT_FOUND)
  200. {
  201. KerbGlobalUseClientIpAddresses = KERB_DEFAULT_CLIENT_IP_ADDRESSES;
  202. }
  203. //
  204. // Bug 353767: configuration key to regulate the TGT renewal interval
  205. //
  206. cbSize = sizeof(Value);
  207. dwErr = RegQueryValueExW(
  208. ParamKey,
  209. KERB_PARAMETER_TGT_RENEWAL_TIME,
  210. NULL,
  211. &cbType,
  212. (LPBYTE)&Value,
  213. &cbSize
  214. );
  215. if (dwErr == ERROR_SUCCESS)
  216. {
  217. KerbGlobalTgtRenewalTime = Value;
  218. }
  219. else if (dwErr == ERROR_FILE_NOT_FOUND)
  220. {
  221. KerbGlobalTgtRenewalTime = KERB_DEFAULT_TGT_RENEWAL_TIME;
  222. }
  223. cbSize = sizeof(Value);
  224. dwErr = RegQueryValueExW(
  225. ParamKey,
  226. KERB_PARAMETER_LOG_LEVEL,
  227. NULL,
  228. &cbType,
  229. (LPBYTE)&Value,
  230. &cbSize
  231. );
  232. if (dwErr == ERROR_SUCCESS)
  233. {
  234. KerbGlobalLoggingLevel = Value;
  235. }
  236. else if (dwErr == ERROR_FILE_NOT_FOUND)
  237. {
  238. KerbGlobalLoggingLevel = KERB_DEFAULT_LOGLEVEL;
  239. }
  240. cbSize = sizeof(Value);
  241. dwErr = RegQueryValueExW(
  242. ParamKey,
  243. KERB_PARAMETER_ALLOW_TGT_SESSION_KEY,
  244. NULL,
  245. &cbType,
  246. (LPBYTE)&Value,
  247. &cbSize
  248. );
  249. if (dwErr == ERROR_SUCCESS)
  250. {
  251. KerbGlobalAllowTgtSessionKey = ( Value != 0 );
  252. }
  253. else if (dwErr == ERROR_FILE_NOT_FOUND)
  254. {
  255. KerbGlobalAllowTgtSessionKey = KERB_DEFAULT_ALLOW_TGT_SESSION_KEY;
  256. }
  257. dwErr = RegQueryValueExW(
  258. ParamKey,
  259. KERB_PARAMETER_MAX_TICKETS,
  260. NULL,
  261. &cbType,
  262. (LPBYTE)&Value,
  263. &cbSize
  264. );
  265. if ( dwErr == ERROR_SUCCESS && cbType == REG_DWORD )
  266. {
  267. KerbGlobalMaxTickets = Value;
  268. }
  269. else if (dwErr == ERROR_FILE_NOT_FOUND)
  270. {
  271. KerbGlobalMaxTickets = KERB_TICKET_COLLECTOR_THRESHHOLD;
  272. }
  273. return;
  274. }
  275. ////////////////////////////////////////////////////////////////////
  276. //
  277. // Name: KerbWaitCleanup
  278. //
  279. // Synopsis: Cleans up wait from KerbWatchParamKey()
  280. //
  281. // Arguments: <none>
  282. //
  283. // Notes: .
  284. //
  285. void
  286. KerbWaitCleanup()
  287. {
  288. NTSTATUS Status = STATUS_SUCCESS;
  289. if (NULL != g_hWait) {
  290. Status = RtlDeregisterWait(g_hWait);
  291. if (NT_SUCCESS(Status) && NULL != g_hParamEvent ) {
  292. CloseHandle(g_hParamEvent);
  293. }
  294. }
  295. }
  296. ////////////////////////////////////////////////////////////////////
  297. //
  298. // Name: KerbWatchParamKey
  299. //
  300. // Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
  301. // debug level, then utilizes thread pool to wait on
  302. // changes to this registry key. Enables dynamic debug
  303. // level changes, as this function will also be callback
  304. // if registry key modified.
  305. //
  306. // Arguments: pCtxt is actually a HANDLE to an event. This event
  307. // will be triggered when key is modified.
  308. //
  309. // Notes: .
  310. //
  311. VOID
  312. KerbWatchKerbParamKey(PVOID pCtxt,
  313. BOOLEAN fWaitStatus)
  314. {
  315. NTSTATUS Status;
  316. LONG lRes = ERROR_SUCCESS;
  317. if (NULL == g_hKeyParams) // first time we've been called.
  318. {
  319. lRes = RegOpenKeyExW(
  320. HKEY_LOCAL_MACHINE,
  321. KERB_PARAMETER_PATH,
  322. 0,
  323. KEY_READ,
  324. &g_hKeyParams);
  325. if ( lRes == ERROR_FILE_NOT_FOUND )
  326. {
  327. HKEY KerbKey;
  328. lRes = RegOpenKeyEx(
  329. HKEY_LOCAL_MACHINE,
  330. KERB_PATH,
  331. 0,
  332. KEY_CREATE_SUB_KEY,
  333. &KerbKey
  334. );
  335. if ( lRes == ERROR_SUCCESS )
  336. {
  337. lRes = RegCreateKeyExW(
  338. KerbKey,
  339. L"Parameters",
  340. 0,
  341. NULL,
  342. 0,
  343. KEY_READ,
  344. NULL,
  345. &g_hKeyParams,
  346. NULL
  347. );
  348. RegCloseKey( KerbKey );
  349. }
  350. }
  351. if (ERROR_SUCCESS != lRes)
  352. {
  353. D_DebugLog((DEB_WARN,"Failed to open kerberos key: 0x%x\n", lRes));
  354. goto Reregister;
  355. }
  356. }
  357. if (NULL != g_hWait)
  358. {
  359. Status = RtlDeregisterWait(g_hWait);
  360. if (!NT_SUCCESS(Status))
  361. {
  362. D_DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
  363. goto Reregister;
  364. }
  365. }
  366. lRes = RegNotifyChangeKeyValue(
  367. g_hKeyParams,
  368. FALSE,
  369. REG_NOTIFY_CHANGE_LAST_SET,
  370. (HANDLE) pCtxt,
  371. TRUE);
  372. if (ERROR_SUCCESS != lRes)
  373. {
  374. D_DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
  375. // we're tanked now. No further notifications, so get this one
  376. }
  377. KerbGetKerbRegParams(g_hKeyParams);
  378. Reregister:
  379. Status = RtlRegisterWait(&g_hWait,
  380. (HANDLE) pCtxt,
  381. KerbWatchKerbParamKey,
  382. (HANDLE) pCtxt,
  383. INFINITE,
  384. WT_EXECUTEINPERSISTENTIOTHREAD|
  385. WT_EXECUTEONLYONCE);
  386. }
  387. NTSTATUS NTAPI
  388. SpCleanup(
  389. DWORD dwProgress
  390. );
  391. BOOL
  392. DllMain(
  393. HINSTANCE Module,
  394. ULONG Reason,
  395. PVOID Context
  396. )
  397. {
  398. if ( Reason == DLL_PROCESS_ATTACH )
  399. {
  400. DisableThreadLibraryCalls( Module );
  401. #ifdef RETAIL_LOG_SUPPORT
  402. KerbInitializeDebugging();
  403. #endif
  404. #if DBG
  405. if ( !NT_SUCCESS( SafeLockInit( KERB_MAX_LOCK_ENUM, TRUE ))) {
  406. return FALSE;
  407. }
  408. #endif
  409. }
  410. else if ( Reason == DLL_PROCESS_DETACH )
  411. {
  412. #if RETAIL_LOG_SUPPORT
  413. KerbUnloadDebug();
  414. #endif
  415. KerbWaitCleanup();
  416. #if DBG
  417. SafeLockCleanup();
  418. #endif
  419. }
  420. return TRUE ;
  421. }
  422. //+-------------------------------------------------------------------------
  423. //
  424. // Function: SpLsaModeInitialize
  425. //
  426. // Synopsis: This function is called by the LSA when this DLL is loaded.
  427. // It returns security package function tables for all
  428. // security packages in the DLL.
  429. //
  430. // Effects:
  431. //
  432. // Arguments: LsaVersion - Version number of the LSA
  433. // PackageVersion - Returns version number of the package
  434. // Tables - Returns array of function tables for the package
  435. // TableCount - Returns number of entries in array of
  436. // function tables.
  437. //
  438. // Requires:
  439. //
  440. // Returns:
  441. //
  442. // Notes:
  443. //
  444. //
  445. //--------------------------------------------------------------------------
  446. NTSTATUS NTAPI
  447. SpLsaModeInitialize(
  448. IN ULONG LsaVersion,
  449. OUT PULONG PackageVersion,
  450. OUT PSECPKG_FUNCTION_TABLE * Tables,
  451. OUT PULONG TableCount
  452. )
  453. {
  454. g_hParamEvent = CreateEvent(NULL,
  455. FALSE,
  456. FALSE,
  457. NULL);
  458. if (NULL == g_hParamEvent)
  459. {
  460. D_DebugLog((DEB_WARN, "CreateEvent for ParamEvent failed - 0x%x\n", GetLastError()));
  461. } else {
  462. KerbWatchKerbParamKey(g_hParamEvent, FALSE);
  463. }
  464. if (LsaVersion != SECPKG_INTERFACE_VERSION)
  465. {
  466. D_DebugLog((DEB_ERROR,"Invalid LSA version: %d. %ws, line %d\n",LsaVersion, THIS_FILE, __LINE__));
  467. return(STATUS_INVALID_PARAMETER);
  468. }
  469. KerberosFunctionTable.InitializePackage = NULL;;
  470. KerberosFunctionTable.LogonUser = NULL;
  471. KerberosFunctionTable.CallPackage = LsaApCallPackage;
  472. KerberosFunctionTable.LogonTerminated = LsaApLogonTerminated;
  473. KerberosFunctionTable.CallPackageUntrusted = LsaApCallPackageUntrusted;
  474. KerberosFunctionTable.LogonUserEx2 = LsaApLogonUserEx2;
  475. KerberosFunctionTable.Initialize = SpInitialize;
  476. KerberosFunctionTable.Shutdown = SpShutdown;
  477. KerberosFunctionTable.GetInfo = SpGetInfo;
  478. KerberosFunctionTable.AcceptCredentials = SpAcceptCredentials;
  479. KerberosFunctionTable.AcquireCredentialsHandle = SpAcquireCredentialsHandle;
  480. KerberosFunctionTable.FreeCredentialsHandle = SpFreeCredentialsHandle;
  481. KerberosFunctionTable.QueryCredentialsAttributes = SpQueryCredentialsAttributes;
  482. KerberosFunctionTable.SaveCredentials = SpSaveCredentials;
  483. KerberosFunctionTable.GetCredentials = SpGetCredentials;
  484. KerberosFunctionTable.DeleteCredentials = SpDeleteCredentials;
  485. KerberosFunctionTable.InitLsaModeContext = SpInitLsaModeContext;
  486. KerberosFunctionTable.AcceptLsaModeContext = SpAcceptLsaModeContext;
  487. KerberosFunctionTable.DeleteContext = SpDeleteContext;
  488. KerberosFunctionTable.ApplyControlToken = SpApplyControlToken;
  489. KerberosFunctionTable.GetUserInfo = SpGetUserInfo;
  490. KerberosFunctionTable.GetExtendedInformation = SpGetExtendedInformation;
  491. KerberosFunctionTable.QueryContextAttributes = SpQueryLsaModeContextAttributes;
  492. KerberosFunctionTable.CallPackagePassthrough = LsaApCallPackagePassthrough;
  493. *PackageVersion = SECPKG_INTERFACE_VERSION;
  494. *TableCount = 1;
  495. *Tables = &KerberosFunctionTable;
  496. // initialize event tracing (a/k/a WMI tracing, software tracing)
  497. KerbInitializeTrace();
  498. SafeAllocaInitialize(SAFEALLOCA_USE_DEFAULT,
  499. SAFEALLOCA_USE_DEFAULT,
  500. KerbAllocate,
  501. KerbFree);
  502. return(STATUS_SUCCESS);
  503. }
  504. #endif // WIN32_CHICAGO
  505. //+-------------------------------------------------------------------------
  506. //
  507. // Function: SpInitialize
  508. //
  509. // Synopsis: Initializes the Kerberos package
  510. //
  511. // Effects:
  512. //
  513. // Arguments: PackageId - Contains ID for this package assigned by LSA
  514. // Parameters - Contains machine-specific information
  515. // FunctionTable - Contains table of LSA helper routines
  516. //
  517. // Requires:
  518. //
  519. // Returns:
  520. //
  521. // Notes:
  522. //
  523. //
  524. //--------------------------------------------------------------------------
  525. NTSTATUS NTAPI
  526. SpInitialize(
  527. IN ULONG_PTR PackageId,
  528. IN PSECPKG_PARAMETERS Parameters,
  529. IN PLSA_SECPKG_FUNCTION_TABLE FunctionTable
  530. )
  531. {
  532. NTSTATUS Status;
  533. UNICODE_STRING TempUnicodeString;
  534. DWORD dwProgress = 0;
  535. #if DBG
  536. Status = SafeLockInit( KERB_MAX_LOCK_ENUM, TRUE );
  537. if ( !NT_SUCCESS( Status )) {
  538. return Status;
  539. }
  540. #endif
  541. #if DBG
  542. InitializeListHead( &GlobalTicketList );
  543. #endif
  544. #ifndef WIN32_CHICAGO
  545. WCHAR SafeBootEnvVar[sizeof(SAFEBOOT_MINIMAL_STR_W) + sizeof(WCHAR)];
  546. __try
  547. {
  548. SafeInitializeResource(&KerberosGlobalResource, GLOBAL_RESOURCE_LOCK_ENUM);
  549. }
  550. __except(EXCEPTION_EXECUTE_HANDLER)
  551. {
  552. return STATUS_INSUFFICIENT_RESOURCES;
  553. }
  554. #endif // WIN32_CHICAGO
  555. KerberosPackageId = PackageId;
  556. LsaFunctions = FunctionTable;
  557. #ifndef WIN32_CHICAGO
  558. KerberosState = KerberosLsaMode;
  559. #else // WIN32_CHICAGO
  560. KerberosState = KerberosUserMode;
  561. #endif // WIN32_CHICAGO
  562. RtlInitUnicodeString(
  563. &KerbPackageName,
  564. MICROSOFT_KERBEROS_NAME_W
  565. );
  566. #ifndef WIN32_CHICAGO
  567. // Check if we are in safe boot.
  568. //
  569. // Does environment variable exist
  570. //
  571. RtlZeroMemory( SafeBootEnvVar, sizeof( SafeBootEnvVar ) );
  572. KerbGlobalSafeModeBootOptionPresent = FALSE;
  573. if ( GetEnvironmentVariable(L"SAFEBOOT_OPTION", SafeBootEnvVar, sizeof(SafeBootEnvVar)/sizeof(SafeBootEnvVar[0]) ) )
  574. {
  575. if ( !wcscmp( SafeBootEnvVar, SAFEBOOT_MINIMAL_STR_W ) )
  576. {
  577. KerbGlobalSafeModeBootOptionPresent = TRUE;
  578. }
  579. }
  580. #endif // WIN32_CHICAGO
  581. Status = KerbInitializeEvents();
  582. if (!NT_SUCCESS(Status))
  583. {
  584. goto Cleanup;
  585. }
  586. dwProgress |= KERB_INIT_EVENTS;
  587. //
  588. // Init data for the kdc calling routine
  589. //
  590. #ifndef WIN32_CHICAGO
  591. Status = KerbInitKdcData();
  592. if (!NT_SUCCESS(Status))
  593. {
  594. goto Cleanup;
  595. }
  596. dwProgress |= KERB_INIT_KDC_DATA;
  597. //
  598. // init global LSA policy handle.
  599. //
  600. Status = LsaIOpenPolicyTrusted(
  601. &KerbGlobalPolicyHandle
  602. );
  603. if(!NT_SUCCESS(Status))
  604. {
  605. goto Cleanup;
  606. }
  607. dwProgress |= KERB_INIT_OPEN_POLICY;
  608. #endif // WIN32_CHICAGO
  609. //
  610. // Get our global role
  611. //
  612. if ((Parameters->MachineState & SECPKG_STATE_DOMAIN_CONTROLLER) != 0)
  613. {
  614. //
  615. // We will behave like a member workstation/server until the DS
  616. // says we are ready to act as a DC
  617. //
  618. KerbGlobalRole = KerbRoleWorkstation;
  619. }
  620. else if ((Parameters->MachineState & SECPKG_STATE_WORKSTATION) != 0)
  621. {
  622. KerbGlobalRole = KerbRoleWorkstation;
  623. }
  624. else
  625. {
  626. KerbGlobalRole = KerbRoleStandalone;
  627. }
  628. //
  629. // Fill in various useful constants
  630. //
  631. KerbSetTime(&KerbGlobalWillNeverTime, MAXTIMEQUADPART);
  632. KerbSetTime(&KerbGlobalHasNeverTime, 0);
  633. //
  634. // compute blank password hashes.
  635. //
  636. Status = RtlCalculateLmOwfPassword( "", &KerbGlobalNullLmOwfPassword );
  637. ASSERT( NT_SUCCESS(Status) );
  638. RtlInitUnicodeString(&TempUnicodeString, NULL);
  639. Status = RtlCalculateNtOwfPassword(&TempUnicodeString,
  640. &KerbGlobalNullNtOwfPassword);
  641. ASSERT( NT_SUCCESS(Status) );
  642. RtlInitUnicodeString(
  643. &KerbGlobalKdcServiceName,
  644. KDC_PRINCIPAL_NAME
  645. );
  646. //
  647. // At some point we may want to read the registry here to
  648. // find out whether we need to enforce times, currently times
  649. // are always enforced.
  650. //
  651. KerbGlobalEnforceTime = FALSE;
  652. KerbGlobalMachineNameChanged = FALSE;
  653. //
  654. // Get the machine Name
  655. //
  656. Status = KerbSetComputerName();
  657. if( !NT_SUCCESS(Status) )
  658. {
  659. D_DebugLog((DEB_ERROR,"KerbSetComputerName failed\n"));
  660. goto Cleanup;
  661. }
  662. dwProgress |= KERB_INIT_COMPUTER_NAME;
  663. //
  664. // Initialize the scavenger
  665. //
  666. Status = KerbInitializeScavenger();
  667. if ( !NT_SUCCESS( Status )) {
  668. D_DebugLog((DEB_ERROR,"KerbInitializeScavengerFailed\n"));
  669. goto Cleanup;
  670. }
  671. dwProgress |= KERB_INIT_SCAVENGER;
  672. //
  673. // Initialize the logon session list. This has to be done because
  674. // KerbSetDomainName will try to acess the logon session list
  675. //
  676. Status = KerbInitLogonSessionList();
  677. if (!NT_SUCCESS(Status))
  678. {
  679. D_DebugLog((DEB_ERROR,"Failed to initialize logon session list: 0x%x. %ws, line %d\n",
  680. Status, THIS_FILE, __LINE__ ));
  681. goto Cleanup;
  682. }
  683. dwProgress |= KERB_INIT_LOGON_SESSION;
  684. Status = KerbInitLoopbackDetection();
  685. if (!NT_SUCCESS(Status))
  686. {
  687. D_DebugLog((DEB_ERROR,"Failed to initialize network service loopback detection: 0x%x. %ws, line %d\n",
  688. Status, THIS_FILE, __LINE__ ));
  689. goto Cleanup;
  690. }
  691. dwProgress |= KERB_INIT_NS_LOOKBACK_DETECTION;
  692. Status = KerbCreateSKeyTimer();
  693. if (!NT_SUCCESS(Status))
  694. {
  695. D_DebugLog((DEB_ERROR,"Failed to initialize network service session key list timer: 0x%x. %ws, line %d\n",
  696. Status, THIS_FILE, __LINE__ ));
  697. goto Cleanup;
  698. }
  699. dwProgress |= KERB_INIT_NS_TIMER;
  700. Status = KerbInitTicketHandling();
  701. if (!NT_SUCCESS(Status))
  702. {
  703. D_DebugLog((DEB_ERROR,"Failed to initialize ticket handling: 0x%x. %ws, line %d\n",
  704. Status, THIS_FILE, __LINE__));
  705. goto Cleanup;
  706. }
  707. dwProgress |= KERB_INIT_TICKET;
  708. //
  709. // Update all global structures referencing the domain name
  710. //
  711. Status = KerbSetDomainName(
  712. &Parameters->DomainName,
  713. &Parameters->DnsDomainName,
  714. Parameters->DomainSid,
  715. Parameters->DomainGuid
  716. );
  717. if (!NT_SUCCESS(Status))
  718. {
  719. goto Cleanup;
  720. }
  721. dwProgress |= KERB_INIT_DOMAIN_NAME;
  722. //
  723. // Initialize the internal Kerberos lists
  724. //
  725. Status = KerbInitCredentialList();
  726. if (!NT_SUCCESS(Status))
  727. {
  728. D_DebugLog((DEB_ERROR,"Failed to initialize credential list: 0x%x. %ws, line %d\n",
  729. Status, THIS_FILE, __LINE__ ));
  730. goto Cleanup;
  731. }
  732. dwProgress |= KERB_INIT_CRED_LIST;
  733. Status = KerbInitContextList();
  734. if (!NT_SUCCESS(Status))
  735. {
  736. D_DebugLog((DEB_ERROR,"Failed to initialize context list: 0x%x. %ws, line %d\n",
  737. Status, THIS_FILE, __LINE__ ));
  738. goto Cleanup;
  739. }
  740. dwProgress |= KERB_INIT_CONTEXT_LIST;
  741. Status = KerbInitTicketCaching();
  742. if (!NT_SUCCESS(Status))
  743. {
  744. D_DebugLog((DEB_ERROR,"Failed to initialize ticket cache: 0x%x. %ws, line %d\n",
  745. Status, THIS_FILE, __LINE__));
  746. goto Cleanup;
  747. }
  748. dwProgress |= KERB_INIT_TICKET_CACHE;
  749. Status = KerbInitBindingCache();
  750. if (!NT_SUCCESS(Status))
  751. {
  752. D_DebugLog((DEB_ERROR,"Failed to initialize binding cache: 0x%x. %ws, line %d\n",
  753. Status, THIS_FILE, __LINE__));
  754. goto Cleanup;
  755. }
  756. dwProgress |= KERB_INIT_BINDING_CACHE;
  757. Status = KerbInitSpnCache();
  758. if (!NT_SUCCESS(Status))
  759. {
  760. D_DebugLog((DEB_ERROR,"Failed to initialize SPN cache: 0x%x. %ws, line %d\n",
  761. Status, THIS_FILE, __LINE__));
  762. goto Cleanup;
  763. }
  764. dwProgress |= KERB_INIT_SPN_CACHE;
  765. Status = KerbInitS4UCache();
  766. if (!NT_SUCCESS(Status))
  767. {
  768. D_DebugLog((DEB_ERROR,"Failed to initialize SPN cache: 0x%x. %ws, line %d\n",
  769. Status, THIS_FILE, __LINE__));
  770. goto Cleanup;
  771. }
  772. dwProgress |= KERB_INIT_S4U_CACHE;
  773. Status = KerbInitializeMitRealmList();
  774. if (!NT_SUCCESS(Status))
  775. {
  776. D_DebugLog((DEB_ERROR,"Failed to initialize MIT realm list: 0x%x. %ws, line %d\n",
  777. Status, THIS_FILE, __LINE__ ));
  778. goto Cleanup;
  779. }
  780. dwProgress |= KERB_INIT_MIT;
  781. Status = KerbInitUdpStatistics();
  782. if (!NT_SUCCESS(Status))
  783. {
  784. D_DebugLog((DEB_ERROR,"Failed to initialize UdpStats: 0x%x. %ws, line %d\n",
  785. Status, THIS_FILE, __LINE__ ));
  786. goto Cleanup;
  787. }
  788. #ifndef WIN32_CHICAGO
  789. Status = KerbInitializePkinit();
  790. if (!NT_SUCCESS(Status))
  791. {
  792. D_DebugLog((DEB_ERROR,"Failed to initialize PKINT: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  793. goto Cleanup;
  794. }
  795. dwProgress |= KERB_INIT_PKINIT;
  796. #endif // WIN32_CHICAGO
  797. Status = KerbInitializeSockets(
  798. MAKEWORD(1,1), // we want version 1.1
  799. 1, // we need at least 1 socket
  800. &KerbGlobalNoTcpUdp
  801. );
  802. if (!NT_SUCCESS(Status))
  803. {
  804. D_DebugLog((DEB_ERROR,"Failed to initialize sockets: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  805. goto Cleanup;
  806. }
  807. dwProgress |= KERB_INIT_SOCKETS;
  808. #ifndef WIN32_CHICAGO
  809. Status = KerbRegisterForDomainChange();
  810. if (!NT_SUCCESS(Status))
  811. {
  812. D_DebugLog((DEB_ERROR, "Failed to register for domain change notification: 0x%x. %ws, line %d\n",Status, THIS_FILE, __LINE__));
  813. goto Cleanup;
  814. }
  815. dwProgress |= KERB_INIT_DOMAIN_CHANGE;
  816. //
  817. // Check to see if there is a CSP registered for replacing the StringToKey calculation
  818. //
  819. CheckForOutsideStringToKey();
  820. //
  821. // See if there are any "join hints" to process
  822. //
  823. ReadInitialDcRecord(
  824. &KerbGlobalInitialDcRecord,
  825. &KerbGlobalInitialDcAddressType,
  826. &KerbGlobalInitialDcFlags
  827. );
  828. KerbGlobalRunningServer = KerbRunningServer();
  829. #endif // WIN32_CHICAGO
  830. KerbGlobalInitialized = TRUE;
  831. Cleanup:
  832. //
  833. // If we failed to initialize, shutdown
  834. //
  835. if (!NT_SUCCESS(Status))
  836. {
  837. SpCleanup(dwProgress);
  838. }
  839. return(Status);
  840. }
  841. //+-------------------------------------------------------------------------
  842. //
  843. // Function: SpCleanup
  844. //
  845. // Synopsis: Function to shutdown the Kerberos package.
  846. //
  847. // Effects: Forces the freeing of all credentials, contexts and
  848. // logon sessions and frees all global data
  849. //
  850. // Arguments: none
  851. //
  852. // Requires:
  853. //
  854. // Returns:
  855. //
  856. // Notes: STATUS_SUCCESS in all cases
  857. //
  858. //
  859. //--------------------------------------------------------------------------
  860. NTSTATUS NTAPI
  861. SpCleanup(
  862. DWORD dwProgress
  863. )
  864. {
  865. KerbGlobalInitialized = FALSE;
  866. if (dwProgress & KERB_INIT_SCAVENGER)
  867. {
  868. KerbShutdownScavenger();
  869. }
  870. #ifndef WIN32_CHICAGO
  871. if (dwProgress & KERB_INIT_DOMAIN_CHANGE)
  872. {
  873. KerbUnregisterForDomainChange();
  874. }
  875. #endif // WIN32_CHICAGO
  876. if (dwProgress & KERB_INIT_LOGON_SESSION)
  877. {
  878. KerbFreeLogonSessionList();
  879. }
  880. if (dwProgress & KERB_INIT_NS_LOOKBACK_DETECTION)
  881. {
  882. KerbFreeSKeyListAndLock();
  883. }
  884. if (dwProgress & KERB_INIT_NS_TIMER)
  885. {
  886. KerbFreeSKeyTimer();
  887. }
  888. if (dwProgress & KERB_INIT_CONTEXT_LIST)
  889. {
  890. KerbFreeContextList();
  891. }
  892. if (dwProgress & KERB_INIT_TICKET_CACHE)
  893. {
  894. KerbFreeTicketCache();
  895. }
  896. // if (dwProgress & KERB_INIT_CRED_LIST)
  897. // {
  898. // KerbFreeCredentialList();
  899. // }
  900. KerbFreeString(&KerbGlobalDomainName);
  901. KerbFreeString(&KerbGlobalDnsDomainName);
  902. KerbFreeString(&KerbGlobalMachineName);
  903. KerbFreeString((PUNICODE_STRING) &KerbGlobalKerbMachineName);
  904. KerbFreeString(&KerbGlobalMachineServiceName);
  905. KerbFreeKdcName(&KerbGlobalMitMachineServiceName);
  906. if (dwProgress & KERB_INIT_TICKET)
  907. {
  908. KerbCleanupTicketHandling();
  909. }
  910. #ifndef WIN32_CHICAGO
  911. if (KerbGlobalPolicyHandle != NULL)
  912. {
  913. ASSERT(dwProgress & KERB_INIT_OPEN_POLICY);
  914. LsarClose( &KerbGlobalPolicyHandle );
  915. KerbGlobalPolicyHandle = NULL;
  916. }
  917. if (KerbGlobalDomainSid != NULL)
  918. {
  919. KerbFree(KerbGlobalDomainSid);
  920. }
  921. #endif // WIN32_CHICAGO
  922. if (dwProgress & KERB_INIT_SOCKETS)
  923. {
  924. KerbCleanupSockets();
  925. }
  926. if (dwProgress & KERB_INIT_BINDING_CACHE)
  927. {
  928. KerbCleanupBindingCache(TRUE);
  929. }
  930. if (dwProgress & KERB_INIT_MIT)
  931. {
  932. KerbUninitializeMitRealmList();
  933. }
  934. #ifndef WIN32_CHICAGO
  935. if (dwProgress & KERB_INIT_KDC_DATA)
  936. {
  937. KerbFreeKdcData();
  938. }
  939. // RtlDeleteResource(&KerberosGlobalResource);
  940. #endif // WIN32_CHICGAO
  941. if (dwProgress & KERB_INIT_EVENTS)
  942. {
  943. KerbShutdownEvents();
  944. }
  945. return(STATUS_SUCCESS);
  946. }
  947. //+-------------------------------------------------------------------------
  948. //
  949. // Function: SpShutdown
  950. //
  951. // Synopsis: Exported function to shutdown the Kerberos package.
  952. //
  953. // Effects: Forces the freeing of all credentials, contexts and
  954. // logon sessions and frees all global data
  955. //
  956. // Arguments: none
  957. //
  958. // Requires:
  959. //
  960. // Returns:
  961. //
  962. // Notes: STATUS_SUCCESS in all cases
  963. //
  964. //
  965. //--------------------------------------------------------------------------
  966. NTSTATUS NTAPI
  967. SpShutdown(
  968. VOID
  969. )
  970. {
  971. #if 0
  972. SpCleanup(0);
  973. #endif
  974. return(STATUS_SUCCESS);
  975. }
  976. #ifndef WIN32_CHICAGO
  977. //+-------------------------------------------------------------------------
  978. //
  979. // Function: SpGetInfo
  980. //
  981. // Synopsis: Returns information about the package
  982. //
  983. // Effects: returns pointers to global data
  984. //
  985. // Arguments: PackageInfo - Receives kerberos package information
  986. //
  987. // Requires:
  988. //
  989. // Returns: STATUS_SUCCESS in all cases
  990. //
  991. // Notes:
  992. //
  993. //
  994. //--------------------------------------------------------------------------
  995. NTSTATUS NTAPI
  996. SpGetInfo(
  997. OUT PSecPkgInfo PackageInfo
  998. )
  999. {
  1000. PackageInfo->wVersion = SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION;
  1001. PackageInfo->wRPCID = RPC_C_AUTHN_GSS_KERBEROS;
  1002. PackageInfo->fCapabilities = KERBEROS_CAPABILITIES;
  1003. PackageInfo->cbMaxToken = KerbGlobalMaxTokenSize;
  1004. PackageInfo->Name = KERBEROS_PACKAGE_NAME;
  1005. PackageInfo->Comment = KERBEROS_PACKAGE_COMMENT;
  1006. return(STATUS_SUCCESS);
  1007. }
  1008. //+-------------------------------------------------------------------------
  1009. //
  1010. // Function: SpGetExtendedInformation
  1011. //
  1012. // Synopsis: returns additional information about the package
  1013. //
  1014. // Effects:
  1015. //
  1016. // Arguments:
  1017. //
  1018. // Requires:
  1019. //
  1020. // Returns:
  1021. //
  1022. // Notes:
  1023. //
  1024. //
  1025. //--------------------------------------------------------------------------
  1026. NTSTATUS
  1027. SpGetExtendedInformation(
  1028. IN SECPKG_EXTENDED_INFORMATION_CLASS Class,
  1029. OUT PSECPKG_EXTENDED_INFORMATION * ppInformation
  1030. )
  1031. {
  1032. NTSTATUS Status = STATUS_SUCCESS;
  1033. PSECPKG_EXTENDED_INFORMATION Information = NULL ;
  1034. PSECPKG_SERIALIZED_OID SerializedOid;
  1035. ULONG Size ;
  1036. switch(Class) {
  1037. case SecpkgGssInfo:
  1038. DsysAssert(gss_mech_krb5_new->length >= 2);
  1039. DsysAssert(gss_mech_krb5_new->length < 127);
  1040. //
  1041. // We need to leave space for the oid and the BER header, which is
  1042. // 0x6 and then the length of the oid.
  1043. //
  1044. Information = (PSECPKG_EXTENDED_INFORMATION)
  1045. KerbAllocate(sizeof(SECPKG_EXTENDED_INFORMATION) +
  1046. gss_mech_krb5_new->length - 2);
  1047. if (Information == NULL)
  1048. {
  1049. Status = STATUS_INSUFFICIENT_RESOURCES;
  1050. goto Cleanup;
  1051. }
  1052. Information->Class = SecpkgGssInfo;
  1053. Information->Info.GssInfo.EncodedIdLength = gss_mech_krb5_new->length + 2;
  1054. Information->Info.GssInfo.EncodedId[0] = 0x6; // BER OID type
  1055. Information->Info.GssInfo.EncodedId[1] = (UCHAR) gss_mech_krb5_new->length;
  1056. RtlCopyMemory(
  1057. &Information->Info.GssInfo.EncodedId[2],
  1058. gss_mech_krb5_new->elements,
  1059. gss_mech_krb5_new->length
  1060. );
  1061. *ppInformation = Information;
  1062. Information = NULL;
  1063. break;
  1064. case SecpkgContextThunks:
  1065. //
  1066. // Note - we don't need to add any space for the thunks as there
  1067. // is only one, and the structure has space for one. If any more
  1068. // thunks are added, we will need to add space for those.
  1069. //
  1070. Information = (PSECPKG_EXTENDED_INFORMATION)
  1071. KerbAllocate(sizeof(SECPKG_EXTENDED_INFORMATION));
  1072. if (Information == NULL)
  1073. {
  1074. Status = STATUS_INSUFFICIENT_RESOURCES;
  1075. goto Cleanup;
  1076. }
  1077. Information->Class = SecpkgContextThunks;
  1078. Information->Info.ContextThunks.InfoLevelCount = 1;
  1079. Information->Info.ContextThunks.Levels[0] = SECPKG_ATTR_NATIVE_NAMES;
  1080. *ppInformation = Information;
  1081. Information = NULL;
  1082. break;
  1083. case SecpkgWowClientDll:
  1084. //
  1085. // This indicates that we're smart enough to handle wow client processes
  1086. //
  1087. Information = (PSECPKG_EXTENDED_INFORMATION)
  1088. KerbAllocate( sizeof( SECPKG_EXTENDED_INFORMATION ) +
  1089. (MAX_PATH * sizeof(WCHAR) ) );
  1090. if ( Information == NULL )
  1091. {
  1092. Status = STATUS_INSUFFICIENT_RESOURCES ;
  1093. goto Cleanup ;
  1094. }
  1095. Information->Class = SecpkgWowClientDll ;
  1096. Information->Info.WowClientDll.WowClientDllPath.Buffer = (PWSTR) (Information + 1);
  1097. Size = ExpandEnvironmentStrings(
  1098. L"%SystemRoot%\\" WOW64_SYSTEM_DIRECTORY_U L"\\Kerberos.DLL",
  1099. Information->Info.WowClientDll.WowClientDllPath.Buffer,
  1100. MAX_PATH );
  1101. Information->Info.WowClientDll.WowClientDllPath.Length = (USHORT) (Size * sizeof(WCHAR));
  1102. Information->Info.WowClientDll.WowClientDllPath.MaximumLength = (USHORT) ((Size + 1) * sizeof(WCHAR) );
  1103. *ppInformation = Information ;
  1104. Information = NULL ;
  1105. break;
  1106. case SecpkgExtraOids:
  1107. Size = sizeof( SECPKG_EXTENDED_INFORMATION ) +
  1108. 2 * sizeof( SECPKG_SERIALIZED_OID ) ;
  1109. Information = (PSECPKG_EXTENDED_INFORMATION)
  1110. KerbAllocate( Size );
  1111. if ( Information == NULL )
  1112. {
  1113. Status = STATUS_INSUFFICIENT_RESOURCES ;
  1114. goto Cleanup ;
  1115. }
  1116. Information->Class = SecpkgExtraOids ;
  1117. Information->Info.ExtraOids.OidCount = 2 ;
  1118. SerializedOid = Information->Info.ExtraOids.Oids;
  1119. SerializedOid->OidLength = gss_mech_krb5_spnego->length + 2;
  1120. SerializedOid->OidAttributes = SECPKG_CRED_BOTH ;
  1121. SerializedOid->OidValue[ 0 ] = 0x06 ; // BER OID type
  1122. SerializedOid->OidValue[ 1 ] = (UCHAR) gss_mech_krb5_spnego->length;
  1123. RtlCopyMemory(
  1124. &SerializedOid->OidValue[2],
  1125. gss_mech_krb5_spnego->elements,
  1126. gss_mech_krb5_spnego->length
  1127. );
  1128. SerializedOid++ ;
  1129. SerializedOid->OidLength = gss_mech_krb5_u2u->length + 2;
  1130. SerializedOid->OidAttributes = SECPKG_CRED_INBOUND ;
  1131. SerializedOid->OidValue[ 0 ] = 0x06 ; // BER OID type
  1132. SerializedOid->OidValue[ 1 ] = (UCHAR) gss_mech_krb5_u2u->length;
  1133. RtlCopyMemory(
  1134. &SerializedOid->OidValue[2],
  1135. gss_mech_krb5_u2u->elements,
  1136. gss_mech_krb5_u2u->length
  1137. );
  1138. *ppInformation = Information ;
  1139. Information = NULL ;
  1140. break;
  1141. default:
  1142. return(STATUS_INVALID_INFO_CLASS);
  1143. }
  1144. Cleanup:
  1145. if (Information != NULL)
  1146. {
  1147. KerbFree(Information);
  1148. }
  1149. return(Status);
  1150. }
  1151. //+-------------------------------------------------------------------------
  1152. //
  1153. // Function: LsaApInitializePackage
  1154. //
  1155. // Synopsis: Obsolete pacakge initialize function, supported for
  1156. // compatibility only. This function has no effect.
  1157. //
  1158. // Effects: none
  1159. //
  1160. // Arguments:
  1161. //
  1162. // Requires:
  1163. //
  1164. // Returns: STATUS_SUCCESS always
  1165. //
  1166. // Notes:
  1167. //
  1168. //
  1169. //--------------------------------------------------------------------------
  1170. NTSTATUS NTAPI
  1171. LsaApInitializePackage(
  1172. IN ULONG AuthenticationPackageId,
  1173. IN PLSA_DISPATCH_TABLE LsaDispatchTable,
  1174. IN PLSA_STRING Database OPTIONAL,
  1175. IN PLSA_STRING Confidentiality OPTIONAL,
  1176. OUT PLSA_STRING *AuthenticationPackageName
  1177. )
  1178. {
  1179. return(STATUS_SUCCESS);
  1180. }
  1181. BOOLEAN
  1182. KerbIsInitialized(
  1183. VOID
  1184. )
  1185. {
  1186. return KerbGlobalInitialized;
  1187. }
  1188. NTSTATUS
  1189. KerbKdcCallBack(
  1190. VOID
  1191. )
  1192. {
  1193. PKERB_BINDING_CACHE_ENTRY CacheEntry = NULL;
  1194. NTSTATUS Status = STATUS_SUCCESS;
  1195. KerbGlobalWriteLock();
  1196. KerbGlobalRole = KerbRoleDomainController;
  1197. Status = KerbLoadKdc();
  1198. //
  1199. // Purge the binding cache of entries for this domain
  1200. //
  1201. CacheEntry = KerbLocateBindingCacheEntry(
  1202. &KerbGlobalDnsDomainName,
  1203. 0,
  1204. TRUE
  1205. );
  1206. if (CacheEntry != NULL)
  1207. {
  1208. KerbDereferenceBindingCacheEntry(CacheEntry);
  1209. }
  1210. CacheEntry = KerbLocateBindingCacheEntry(
  1211. &KerbGlobalDomainName,
  1212. 0,
  1213. TRUE
  1214. );
  1215. if (CacheEntry != NULL)
  1216. {
  1217. KerbDereferenceBindingCacheEntry(CacheEntry);
  1218. }
  1219. //
  1220. // PurgeSpnCache, because we may now have "better" state,
  1221. // e.g. right after DCPromo our SPNs may not have replicated.
  1222. // For DCs, we can not even care about the spncache.
  1223. //
  1224. KerbCleanupSpnCache();
  1225. KerbSetTimeInMinutes(&KerbGlobalSpnCacheTimeout, 0);
  1226. KerbGlobalReleaseLock();
  1227. return Status;
  1228. }
  1229. VOID
  1230. FreAssert(
  1231. IN BOOL Expression,
  1232. IN CHAR * String
  1233. )
  1234. {
  1235. static BOOL KdPresenceChecked = FALSE;
  1236. static BOOL KdPresent = FALSE;
  1237. if ( !Expression )
  1238. {
  1239. //
  1240. // Kernel debugger is either present or not,
  1241. // this can not change without a reboot
  1242. //
  1243. if ( !KdPresenceChecked )
  1244. {
  1245. SYSTEM_KERNEL_DEBUGGER_INFORMATION KdInfo ;
  1246. NTSTATUS Status ;
  1247. Status = NtQuerySystemInformation(
  1248. SystemKernelDebuggerInformation,
  1249. &KdInfo,
  1250. sizeof( KdInfo ),
  1251. NULL );
  1252. if ( NT_SUCCESS( Status ) &&
  1253. KdInfo.KernelDebuggerEnabled )
  1254. {
  1255. KdPresent = TRUE;
  1256. }
  1257. //
  1258. // Set this variable to TRUE last in order to make this routine threadsafe
  1259. //
  1260. KdPresenceChecked = TRUE;
  1261. }
  1262. if ( KdPresent || IsDebuggerPresent())
  1263. {
  1264. OutputDebugStringA( String );
  1265. OutputDebugStringA( "\n" );
  1266. DebugBreak();
  1267. }
  1268. }
  1269. }
  1270. #endif // WIN32_CHICAGO