Source code of Windows XP (NT5)
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.

781 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: spreg.c
  7. //
  8. // Contents: Schannel registry management routines.
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 11-24-97 jbanes Enabled TLS
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <sslp.h>
  18. #include "spreg.h"
  19. HKEY g_hkBase = NULL;
  20. HANDLE g_hParamEvent = NULL;
  21. HANDLE g_hWait = NULL;
  22. HKEY g_hkFipsBase = NULL;
  23. HANDLE g_hFipsParamEvent = NULL;
  24. HANDLE g_hFipsWait = NULL;
  25. BOOL g_fManualCredValidation = MANUAL_CRED_VALIDATION_SETTING;
  26. BOOL g_PctClientDisabledByDefault = PCT_CLIENT_DISABLED_SETTING;
  27. BOOL g_Ssl2ClientDisabledByDefault = SSL2_CLIENT_DISABLED_SETTING;
  28. DWORD g_dwEventLogging = DEFAULT_EVENT_LOGGING_SETTING;
  29. DWORD g_ProtEnabled = DEFAULT_ENABLED_PROTOCOLS_SETTING;
  30. BOOL g_fFipsMode = FALSE;
  31. BOOL g_fFranceLocale = FALSE;
  32. typedef struct enamap
  33. {
  34. TCHAR *pKey;
  35. DWORD Mask;
  36. } enamap;
  37. enamap g_ProtMap[] =
  38. {
  39. {SP_REG_KEY_UNIHELLO TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_UNI_CLIENT},
  40. {SP_REG_KEY_UNIHELLO TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_UNI_SERVER},
  41. {SP_REG_KEY_PCT1 TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_PCT1_CLIENT},
  42. {SP_REG_KEY_PCT1 TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_PCT1_SERVER},
  43. {SP_REG_KEY_SSL2 TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_SSL2_CLIENT},
  44. {SP_REG_KEY_SSL2 TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_SSL2_SERVER},
  45. {SP_REG_KEY_SSL3 TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_SSL3_CLIENT},
  46. {SP_REG_KEY_SSL3 TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_SSL3_SERVER},
  47. {SP_REG_KEY_TLS1 TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_TLS1_CLIENT},
  48. {SP_REG_KEY_TLS1 TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_TLS1_SERVER}
  49. };
  50. VOID
  51. SslWatchParamKey(
  52. PVOID pCtxt,
  53. BOOLEAN fWaitStatus);
  54. VOID
  55. FipsWatchParamKey(
  56. PVOID pCtxt,
  57. BOOLEAN fWaitStatus);
  58. BOOL
  59. SslReadRegOptions(
  60. BOOL fFirstTime);
  61. BOOL SPLoadRegOptions(void)
  62. {
  63. g_hParamEvent = CreateEvent(NULL,
  64. FALSE,
  65. FALSE,
  66. NULL);
  67. SslWatchParamKey(g_hParamEvent, FALSE);
  68. g_hFipsParamEvent = CreateEvent(NULL,
  69. FALSE,
  70. FALSE,
  71. NULL);
  72. FipsWatchParamKey(g_hFipsParamEvent, FALSE);
  73. return TRUE;
  74. }
  75. void SPUnloadRegOptions(void)
  76. {
  77. if (NULL != g_hWait)
  78. {
  79. RtlDeregisterWait(g_hWait);
  80. g_hWait = NULL;
  81. }
  82. if(NULL != g_hkBase)
  83. {
  84. RegCloseKey(g_hkBase);
  85. }
  86. if(NULL != g_hParamEvent)
  87. {
  88. CloseHandle(g_hParamEvent);
  89. }
  90. if (NULL != g_hFipsWait)
  91. {
  92. RtlDeregisterWait(g_hFipsWait);
  93. g_hFipsWait = NULL;
  94. }
  95. if(NULL != g_hkFipsBase)
  96. {
  97. RegCloseKey(g_hkFipsBase);
  98. }
  99. if(NULL != g_hFipsParamEvent)
  100. {
  101. CloseHandle(g_hFipsParamEvent);
  102. }
  103. }
  104. BOOL
  105. ReadRegistrySetting(
  106. HKEY hReadKey,
  107. HKEY hWriteKey,
  108. LPCTSTR pszValueName,
  109. DWORD * pdwValue,
  110. DWORD dwDefaultValue)
  111. {
  112. DWORD dwSize;
  113. DWORD dwType;
  114. DWORD dwOriginalValue = *pdwValue;
  115. dwSize = sizeof(DWORD);
  116. if(RegQueryValueEx(hReadKey,
  117. pszValueName,
  118. NULL,
  119. &dwType,
  120. (PUCHAR)pdwValue,
  121. &dwSize) != STATUS_SUCCESS)
  122. {
  123. *pdwValue = dwDefaultValue;
  124. if(hWriteKey)
  125. {
  126. RegSetValueEx(hWriteKey,
  127. pszValueName,
  128. 0,
  129. REG_DWORD,
  130. (PUCHAR)pdwValue,
  131. sizeof(DWORD));
  132. }
  133. }
  134. return (dwOriginalValue != *pdwValue);
  135. }
  136. ////////////////////////////////////////////////////////////////////
  137. //
  138. // Name: SslWatchParamKey
  139. //
  140. // Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
  141. // debug level, then utilizes thread pool to wait on
  142. // changes to this registry key. Enables dynamic debug
  143. // level changes, as this function will also be callback
  144. // if registry key modified.
  145. //
  146. // Arguments: pCtxt is actually a HANDLE to an event. This event
  147. // will be triggered when key is modified.
  148. //
  149. // Notes: .
  150. //
  151. VOID
  152. SslWatchParamKey(
  153. PVOID pCtxt,
  154. BOOLEAN fWaitStatus)
  155. {
  156. NTSTATUS Status;
  157. LONG lRes = ERROR_SUCCESS;
  158. BOOL fFirstTime = FALSE;
  159. DWORD disp;
  160. if(g_hkBase == NULL)
  161. {
  162. // First time we've been called.
  163. Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  164. SP_REG_KEY_BASE,
  165. 0,
  166. TEXT(""),
  167. REG_OPTION_NON_VOLATILE,
  168. KEY_READ,
  169. NULL,
  170. &g_hkBase,
  171. &disp);
  172. if(Status)
  173. {
  174. DebugLog((DEB_WARN,"Failed to open SCHANNEL key: 0x%x\n", Status));
  175. return;
  176. }
  177. fFirstTime = TRUE;
  178. }
  179. if(pCtxt != NULL)
  180. {
  181. if (NULL != g_hWait)
  182. {
  183. Status = RtlDeregisterWait(g_hWait);
  184. if(!NT_SUCCESS(Status))
  185. {
  186. DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
  187. goto Reregister;
  188. }
  189. }
  190. lRes = RegNotifyChangeKeyValue(
  191. g_hkBase,
  192. TRUE,
  193. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
  194. (HANDLE)pCtxt,
  195. TRUE);
  196. if (ERROR_SUCCESS != lRes)
  197. {
  198. DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
  199. // we're tanked now. No further notifications, so get this one
  200. }
  201. }
  202. SslReadRegOptions(fFirstTime);
  203. #if DBG
  204. InitDebugSupport(g_hkBase);
  205. #endif
  206. Reregister:
  207. if(pCtxt != NULL)
  208. {
  209. Status = RtlRegisterWait(&g_hWait,
  210. (HANDLE)pCtxt,
  211. SslWatchParamKey,
  212. (HANDLE)pCtxt,
  213. INFINITE,
  214. WT_EXECUTEINPERSISTENTIOTHREAD|
  215. WT_EXECUTEONLYONCE);
  216. }
  217. }
  218. ////////////////////////////////////////////////////////////////////
  219. //
  220. // Name: FipsWatchParamKey
  221. //
  222. // Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
  223. // debug level, then utilizes thread pool to wait on
  224. // changes to this registry key. Enables dynamic debug
  225. // level changes, as this function will also be callback
  226. // if registry key modified.
  227. //
  228. // Arguments: pCtxt is actually a HANDLE to an event. This event
  229. // will be triggered when key is modified.
  230. //
  231. // Notes: .
  232. //
  233. VOID
  234. FipsWatchParamKey(
  235. PVOID pCtxt,
  236. BOOLEAN fWaitStatus)
  237. {
  238. NTSTATUS Status;
  239. LONG lRes = ERROR_SUCCESS;
  240. DWORD disp;
  241. if(g_hkFipsBase == NULL)
  242. {
  243. // First time we've been called.
  244. Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  245. SP_REG_FIPS_BASE_KEY,
  246. 0,
  247. TEXT(""),
  248. REG_OPTION_NON_VOLATILE,
  249. KEY_READ,
  250. NULL,
  251. &g_hkFipsBase,
  252. &disp);
  253. if(Status)
  254. {
  255. DebugLog((DEB_WARN,"Failed to open FIPS key: 0x%x\n", Status));
  256. return;
  257. }
  258. }
  259. if(pCtxt != NULL)
  260. {
  261. if (NULL != g_hFipsWait)
  262. {
  263. Status = RtlDeregisterWait(g_hFipsWait);
  264. if(!NT_SUCCESS(Status))
  265. {
  266. DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
  267. goto Reregister;
  268. }
  269. }
  270. lRes = RegNotifyChangeKeyValue(
  271. g_hkFipsBase,
  272. TRUE,
  273. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
  274. (HANDLE)pCtxt,
  275. TRUE);
  276. if (ERROR_SUCCESS != lRes)
  277. {
  278. DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
  279. // we're tanked now. No further notifications, so get this one
  280. }
  281. }
  282. SslReadRegOptions(FALSE);
  283. Reregister:
  284. if(pCtxt != NULL)
  285. {
  286. Status = RtlRegisterWait(&g_hFipsWait,
  287. (HANDLE)pCtxt,
  288. FipsWatchParamKey,
  289. (HANDLE)pCtxt,
  290. INFINITE,
  291. WT_EXECUTEINPERSISTENTIOTHREAD|
  292. WT_EXECUTEONLYONCE);
  293. }
  294. }
  295. BOOL
  296. SslReadRegOptions(
  297. BOOL fFirstTime)
  298. {
  299. DWORD err;
  300. DWORD dwType;
  301. DWORD fVal;
  302. DWORD dwSize;
  303. DWORD dwValue;
  304. HKEY hKey;
  305. HKEY hWriteKey;
  306. DWORD disp;
  307. HKEY hSubKey;
  308. DWORD i;
  309. HKEY hkProtocols = NULL;
  310. HKEY hkCiphers = NULL;
  311. HKEY hkHashes = NULL;
  312. HKEY hkKeyExch = NULL;
  313. BOOL fFipsMode = FALSE;
  314. BOOL fSettingsChanged = FALSE;
  315. DWORD dwOriginalValue;
  316. DebugLog((DEB_TRACE,"Load configuration parameters from registry.\n"));
  317. // "FipsAlgorithmPolicy"
  318. ReadRegistrySetting(
  319. g_hkFipsBase,
  320. 0,
  321. SP_REG_FIPS_POLICY,
  322. &dwValue,
  323. 0);
  324. if(dwValue == 1)
  325. {
  326. fFipsMode = TRUE;
  327. }
  328. if(fFipsMode != g_fFipsMode)
  329. {
  330. g_fFipsMode = fFipsMode;
  331. fSettingsChanged = TRUE;
  332. }
  333. //
  334. // Read top-level configuration options.
  335. //
  336. // Open top-level key that has write access.
  337. if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  338. SP_REG_KEY_BASE,
  339. 0,
  340. KEY_READ | KEY_SET_VALUE,
  341. &hWriteKey) != STATUS_SUCCESS)
  342. {
  343. hWriteKey = 0;
  344. }
  345. // "EventLogging"
  346. if(ReadRegistrySetting(
  347. g_hkBase,
  348. hWriteKey,
  349. SP_REG_VAL_EVENTLOG,
  350. &g_dwEventLogging,
  351. DEFAULT_EVENT_LOGGING_SETTING))
  352. {
  353. fSettingsChanged = TRUE;
  354. }
  355. // "ManualCredValidation"
  356. if(ReadRegistrySetting(
  357. g_hkBase,
  358. 0,
  359. SP_REG_VAL_MANUAL_CRED_VALIDATION,
  360. &g_fManualCredValidation,
  361. MANUAL_CRED_VALIDATION_SETTING))
  362. {
  363. fSettingsChanged = TRUE;
  364. }
  365. // "ClientCacheTime"
  366. if(ReadRegistrySetting(
  367. g_hkBase,
  368. 0,
  369. SP_REG_VAL_CLIENT_CACHE_TIME,
  370. &SchannelCache.dwClientLifespan,
  371. SP_CACHE_CLIENT_LIFESPAN))
  372. {
  373. fSettingsChanged = TRUE;
  374. }
  375. // "ServerCacheTime"
  376. if(ReadRegistrySetting(
  377. g_hkBase,
  378. 0,
  379. SP_REG_VAL_SERVER_CACHE_TIME,
  380. &SchannelCache.dwServerLifespan,
  381. SP_CACHE_SERVER_LIFESPAN))
  382. {
  383. fSettingsChanged = TRUE;
  384. }
  385. // "MaximumCacheSize"
  386. if(ReadRegistrySetting(
  387. g_hkBase,
  388. 0,
  389. SP_REG_VAL_MAXUMUM_CACHE_SIZE,
  390. &SchannelCache.dwMaximumEntries,
  391. SP_MAXIMUM_CACHE_ELEMENTS))
  392. {
  393. fSettingsChanged = TRUE;
  394. }
  395. if(fFirstTime)
  396. {
  397. SchannelCache.dwCacheSize = SchannelCache.dwMaximumEntries;
  398. }
  399. // "MultipleProcessClientCache"
  400. if(ReadRegistrySetting(
  401. g_hkBase,
  402. 0,
  403. SP_REG_VAL_MULTI_PROC_CLIENT_CACHE,
  404. &g_fMultipleProcessClientCache,
  405. FALSE))
  406. {
  407. fSettingsChanged = TRUE;
  408. }
  409. if(hWriteKey)
  410. {
  411. RegCloseKey(hWriteKey);
  412. hWriteKey = 0;
  413. }
  414. //
  415. // Enable/Disable Protocols
  416. //
  417. if(fFipsMode)
  418. {
  419. // Disable everything except TLS.
  420. g_ProtEnabled = SP_PROT_TLS1;
  421. }
  422. else
  423. {
  424. DWORD dwProtEnabled = DEFAULT_ENABLED_PROTOCOLS_SETTING;
  425. err = RegCreateKeyEx( g_hkBase,
  426. SP_REG_KEY_PROTOCOL,
  427. 0,
  428. TEXT(""),
  429. REG_OPTION_NON_VOLATILE,
  430. KEY_READ,
  431. NULL,
  432. &hkProtocols,
  433. &disp);
  434. if(err == ERROR_SUCCESS)
  435. {
  436. for(i=0; i < (sizeof(g_ProtMap)/sizeof(enamap)); i++)
  437. {
  438. if(g_ProtMap[i].Mask & SP_PROT_PCT1)
  439. {
  440. if(g_fFranceLocale)
  441. {
  442. // Don't allow PCT to be enabled in France.
  443. continue;
  444. }
  445. }
  446. err = RegCreateKeyEx( hkProtocols,
  447. g_ProtMap[i].pKey,
  448. 0,
  449. TEXT(""),
  450. REG_OPTION_NON_VOLATILE,
  451. KEY_READ,
  452. NULL,
  453. &hKey,
  454. &disp);
  455. if(!err)
  456. {
  457. dwSize = sizeof(DWORD);
  458. err = RegQueryValueEx(hKey, SP_REG_VAL_ENABLED, NULL, &dwType, (PUCHAR)&fVal, &dwSize);
  459. if(!err)
  460. {
  461. if(fVal)
  462. {
  463. dwProtEnabled |= g_ProtMap[i].Mask;
  464. }
  465. else
  466. {
  467. dwProtEnabled &= ~g_ProtMap[i].Mask;
  468. }
  469. }
  470. if(g_ProtMap[i].Mask & SP_PROT_PCT1_CLIENT)
  471. {
  472. // "DisabledByDefault"
  473. ReadRegistrySetting(
  474. hKey,
  475. 0,
  476. SP_REG_VAL_DISABLED_BY_DEFAULT,
  477. &g_PctClientDisabledByDefault,
  478. PCT_CLIENT_DISABLED_SETTING);
  479. }
  480. if(g_ProtMap[i].Mask & SP_PROT_SSL2_CLIENT)
  481. {
  482. // "DisabledByDefault"
  483. ReadRegistrySetting(
  484. hKey,
  485. 0,
  486. SP_REG_VAL_DISABLED_BY_DEFAULT,
  487. &g_Ssl2ClientDisabledByDefault,
  488. SSL2_CLIENT_DISABLED_SETTING);
  489. }
  490. RegCloseKey(hKey);
  491. }
  492. }
  493. RegCloseKey(hkProtocols);
  494. }
  495. if(g_ProtEnabled != dwProtEnabled)
  496. {
  497. g_ProtEnabled = dwProtEnabled;
  498. fSettingsChanged = TRUE;
  499. }
  500. }
  501. //
  502. // Enable/Disable Ciphers
  503. //
  504. if(fFipsMode)
  505. {
  506. // Disable everything except 3DES.
  507. for(i=0; i < g_cAvailableCiphers; i++)
  508. {
  509. if(g_AvailableCiphers[i].aiCipher != CALG_3DES)
  510. {
  511. g_AvailableCiphers[i].fProtocol = 0;
  512. }
  513. }
  514. }
  515. else
  516. {
  517. err = RegCreateKeyEx( g_hkBase,
  518. SP_REG_KEY_CIPHERS,
  519. 0,
  520. TEXT(""),
  521. REG_OPTION_NON_VOLATILE,
  522. KEY_READ,
  523. NULL,
  524. &hkCiphers,
  525. &disp);
  526. if(err == ERROR_SUCCESS)
  527. {
  528. for(i=0; i < g_cAvailableCiphers; i++)
  529. {
  530. dwOriginalValue = g_AvailableCiphers[i].fProtocol;
  531. g_AvailableCiphers[i].fProtocol = g_AvailableCiphers[i].fDefault;
  532. fVal = g_AvailableCiphers[i].fDefault;
  533. err = RegCreateKeyExA( hkCiphers,
  534. g_AvailableCiphers[i].szName,
  535. 0,
  536. "",
  537. REG_OPTION_NON_VOLATILE,
  538. KEY_READ,
  539. NULL,
  540. &hKey,
  541. &disp);
  542. if(!err)
  543. {
  544. dwSize = sizeof(DWORD);
  545. err = RegQueryValueEx(hKey, SP_REG_VAL_ENABLED, NULL, &dwType, (PUCHAR)&fVal, &dwSize);
  546. if(err)
  547. {
  548. fVal = g_AvailableCiphers[i].fDefault;
  549. }
  550. RegCloseKey(hKey);
  551. }
  552. g_AvailableCiphers[i].fProtocol &= fVal;
  553. if(g_AvailableCiphers[i].fProtocol != dwOriginalValue)
  554. {
  555. fSettingsChanged = TRUE;
  556. }
  557. }
  558. RegCloseKey(hkCiphers);
  559. }
  560. }
  561. //
  562. // Enable/Disable Hashes
  563. //
  564. err = RegCreateKeyEx( g_hkBase,
  565. SP_REG_KEY_HASHES,
  566. 0,
  567. TEXT(""),
  568. REG_OPTION_NON_VOLATILE,
  569. KEY_READ,
  570. NULL,
  571. &hkHashes,
  572. &disp);
  573. if(err == ERROR_SUCCESS)
  574. {
  575. for(i = 0; i < g_cAvailableHashes; i++)
  576. {
  577. dwOriginalValue = g_AvailableHashes[i].fProtocol;
  578. g_AvailableHashes[i].fProtocol = g_AvailableHashes[i].fDefault;
  579. fVal = g_AvailableHashes[i].fDefault;
  580. err = RegCreateKeyExA( hkHashes,
  581. g_AvailableHashes[i].szName,
  582. 0,
  583. "",
  584. REG_OPTION_NON_VOLATILE,
  585. KEY_READ,
  586. NULL,
  587. &hKey,
  588. &disp);
  589. if(!err)
  590. {
  591. dwSize = sizeof(DWORD);
  592. err = RegQueryValueEx(hKey, SP_REG_VAL_ENABLED, NULL, &dwType, (PUCHAR)&fVal, &dwSize);
  593. if(err)
  594. {
  595. fVal = g_AvailableHashes[i].fDefault;
  596. }
  597. RegCloseKey(hKey);
  598. }
  599. g_AvailableHashes[i].fProtocol &= fVal;
  600. if(dwOriginalValue != g_AvailableHashes[i].fProtocol)
  601. {
  602. fSettingsChanged = TRUE;
  603. }
  604. }
  605. RegCloseKey(hkHashes);
  606. }
  607. //
  608. // Enable/Disable Key Exchange algs.
  609. //
  610. if(fFipsMode)
  611. {
  612. // Disable everything except RSA.
  613. for(i=0; i < g_cAvailableExch; i++)
  614. {
  615. if(g_AvailableExch[i].aiExch != CALG_RSA_KEYX &&
  616. g_AvailableExch[i].aiExch != CALG_RSA_SIGN)
  617. {
  618. g_AvailableExch[i].fProtocol = 0;
  619. }
  620. }
  621. }
  622. else
  623. {
  624. err = RegCreateKeyEx( g_hkBase,
  625. SP_REG_KEY_KEYEXCH,
  626. 0,
  627. TEXT(""),
  628. REG_OPTION_NON_VOLATILE,
  629. KEY_READ,
  630. NULL,
  631. &hkKeyExch,
  632. &disp);
  633. if(err == ERROR_SUCCESS)
  634. {
  635. for(i = 0; i < g_cAvailableExch; i++)
  636. {
  637. dwOriginalValue = g_AvailableExch[i].fProtocol;
  638. g_AvailableExch[i].fProtocol = g_AvailableExch[i].fDefault;
  639. fVal = g_AvailableExch[i].fDefault;
  640. err = RegCreateKeyExA( hkKeyExch,
  641. g_AvailableExch[i].szName,
  642. 0,
  643. "",
  644. REG_OPTION_NON_VOLATILE,
  645. KEY_READ,
  646. NULL,
  647. &hKey,
  648. &disp);
  649. if(!err)
  650. {
  651. dwSize = sizeof(DWORD);
  652. err = RegQueryValueEx(hKey, SP_REG_VAL_ENABLED, NULL, &dwType, (PUCHAR)&fVal, &dwSize);
  653. if(err)
  654. {
  655. fVal = g_AvailableExch[i].fDefault;
  656. }
  657. g_AvailableExch[i].fProtocol &= fVal;
  658. RegCloseKey(hKey);
  659. }
  660. if(dwOriginalValue != g_AvailableExch[i].fProtocol)
  661. {
  662. fSettingsChanged = TRUE;
  663. }
  664. }
  665. RegCloseKey(hkKeyExch);
  666. }
  667. }
  668. //
  669. // Purge the session cache.
  670. //
  671. if(g_fCacheInitialized && fSettingsChanged)
  672. {
  673. SPCachePurgeEntries(NULL,
  674. 0,
  675. NULL,
  676. SSL_PURGE_CLIENT_ALL_ENTRIES |
  677. SSL_PURGE_SERVER_ALL_ENTRIES);
  678. }
  679. return TRUE;
  680. }