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.

898 lines
23 KiB

  1. /**********************************************************************/
  2. /** Microsoft Passport **/
  3. /** Copyright(c) Microsoft Corporation, 1999 - 2001 **/
  4. /**********************************************************************/
  5. /*
  6. PassportConfiguration.cpp
  7. FILE HISTORY:
  8. */
  9. // PassportConfiguration.cpp: implementation of the CPassportConfiguration class.
  10. //
  11. //////////////////////////////////////////////////////////////////////
  12. #include "stdafx.h"
  13. #include "PassportConfiguration.h"
  14. #include <time.h>
  15. #include "passportguard.hpp"
  16. extern BOOL g_bRegistering;
  17. //////////////////////////////////////////////////////////////////////
  18. // Construction/Destruction
  19. //////////////////////////////////////////////////////////////////////
  20. //===========================================================================
  21. //
  22. // CPassportConfiguration
  23. //
  24. CPassportConfiguration::CPassportConfiguration() :
  25. m_rDefault(NULL), m_n(NULL),
  26. m_rlastDefault(NULL), m_nlast(NULL), m_lastAttempt(0),
  27. m_ConfigMap(NULL), m_lastConfigMap(NULL),
  28. m_rPending(NULL), m_nPending(NULL), m_bUpdateInProgress(false),
  29. m_ConfigMapPending(NULL)
  30. {
  31. m_nUpdate = RegisterCCDUpdateNotification(_T(PRCONFIG), this);
  32. m_rUpdate = RegisterConfigChangeNotification(this);
  33. }
  34. //===========================================================================
  35. //
  36. // ~CPassportConfiguration
  37. //
  38. CPassportConfiguration::~CPassportConfiguration()
  39. {
  40. REGCONFIGMAP::iterator it;
  41. if (m_nUpdate)
  42. UnregisterCCDUpdateNotification(m_nUpdate);
  43. if (m_rUpdate)
  44. UnregisterConfigChangeNotification(m_rUpdate);
  45. //
  46. // Empty out config maps.
  47. //
  48. {
  49. PassportGuard<PassportLock> g(m_lock);
  50. if(m_ConfigMap)
  51. {
  52. while((it = m_ConfigMap->begin()) != m_ConfigMap->end())
  53. {
  54. it->second->Release();
  55. free(it->first);
  56. m_ConfigMap->erase(it);
  57. }
  58. delete m_ConfigMap;
  59. m_ConfigMap = NULL;
  60. }
  61. if(m_lastConfigMap)
  62. {
  63. while((it = m_lastConfigMap->begin()) != m_lastConfigMap->end())
  64. {
  65. it->second->Release();
  66. free(it->first);
  67. m_lastConfigMap->erase(it);
  68. }
  69. delete m_lastConfigMap;
  70. m_lastConfigMap = NULL;
  71. }
  72. if(m_ConfigMapPending)
  73. {
  74. while((it = m_ConfigMapPending->begin()) != m_ConfigMapPending->end())
  75. {
  76. it->second->Release();
  77. free(it->first);
  78. m_ConfigMapPending->erase(it);
  79. }
  80. delete m_ConfigMapPending;
  81. m_ConfigMapPending = NULL;
  82. }
  83. if (m_rDefault)
  84. {
  85. m_rDefault->Release();
  86. m_rDefault = NULL;
  87. }
  88. if (m_n)
  89. {
  90. m_n->Release();
  91. m_n = NULL;
  92. }
  93. if (m_rlastDefault)
  94. {
  95. m_rlastDefault->Release();
  96. m_rlastDefault = NULL;
  97. }
  98. if (m_nlast)
  99. {
  100. m_nlast->Release();
  101. m_nlast = NULL;
  102. }
  103. if (m_rPending)
  104. {
  105. m_rPending->Release();
  106. m_rPending = NULL;
  107. }
  108. if (m_nPending)
  109. {
  110. m_nPending->Release();
  111. m_nPending = NULL;
  112. }
  113. }
  114. }
  115. //===========================================================================
  116. //
  117. // IsIPAddress
  118. //
  119. BOOL
  120. CPassportConfiguration::IsIPAddress(
  121. LPSTR szSiteName
  122. )
  123. {
  124. for(LPSTR sz = szSiteName; *sz; sz++)
  125. if(!_istdigit(*sz) && *sz != '.' && *sz != ':')
  126. return FALSE;
  127. return TRUE;
  128. }
  129. //===========================================================================
  130. //
  131. // checkoutRegistryConfig
  132. //
  133. CRegistryConfig* CPassportConfiguration::checkoutRegistryConfig(
  134. LPSTR szHost // Can be host name or IP
  135. )
  136. {
  137. CRegistryConfig* c = NULL;
  138. REGCONFIGMAP::iterator it;
  139. PassportGuard<PassportLock> g(m_lock);
  140. if(m_ConfigMap != NULL && szHost && szHost[0])
  141. {
  142. if(IsIPAddress(szHost))
  143. {
  144. for(it = m_ConfigMap->begin(); it != m_ConfigMap->end(); it++)
  145. {
  146. if(lstrcmpA(szHost, it->second->getHostIP()) == 0)
  147. {
  148. c = it->second->AddRef();
  149. break;
  150. }
  151. }
  152. }
  153. else
  154. {
  155. it = m_ConfigMap->find(szHost);
  156. if(it != m_ConfigMap->end())
  157. c = it->second->AddRef();
  158. }
  159. }
  160. if (c == NULL)
  161. {
  162. if(!m_rDefault)
  163. {
  164. UpdateNow();
  165. c = m_rDefault ? m_rDefault->AddRef() : NULL;
  166. }
  167. else
  168. c = m_rDefault->AddRef();
  169. }
  170. return c;
  171. }
  172. //===========================================================================
  173. //
  174. // checkoutRegistryConfigBySite
  175. //
  176. CRegistryConfig* CPassportConfiguration::checkoutRegistryConfigBySite(
  177. LPSTR szSiteName
  178. )
  179. {
  180. CRegistryConfig* crc = NULL;
  181. CHAR achHostName[2048];
  182. DWORD dwHostNameBufLen;
  183. if(szSiteName && szSiteName[0])
  184. {
  185. dwHostNameBufLen = sizeof(achHostName);
  186. if(CRegistryConfig::GetHostName(szSiteName, achHostName, &dwHostNameBufLen) != ERROR_SUCCESS)
  187. goto Cleanup;
  188. crc = checkoutRegistryConfig(achHostName);
  189. }
  190. else
  191. {
  192. crc = checkoutRegistryConfig();
  193. }
  194. Cleanup:
  195. return crc;
  196. }
  197. //===========================================================================
  198. //
  199. // checkoutNexusConfig
  200. //
  201. CNexusConfig* CPassportConfiguration::checkoutNexusConfig()
  202. {
  203. if (!m_n)
  204. {
  205. PassportGuard<PassportLock> g(m_lock);
  206. if (!m_n) // In case it happened while we were waiting
  207. UpdateNow();
  208. return m_n ? m_n->AddRef() : NULL;
  209. }
  210. CNexusConfig *c = m_n->AddRef();
  211. return c;
  212. }
  213. //===========================================================================
  214. //
  215. // isValid
  216. //
  217. BOOL CPassportConfiguration::isValid()
  218. {
  219. if (m_rDefault != NULL && m_n != NULL)
  220. return m_rDefault->isValid() && m_n->isValid();
  221. else
  222. {
  223. PassportGuard<PassportLock> g(m_lock);
  224. if (m_rDefault == NULL || m_n == NULL) // In case it happened while we were waiting
  225. {
  226. BOOL retVal = UpdateNow(FALSE);
  227. return retVal;
  228. }
  229. }
  230. return (m_rDefault && m_rDefault->isValid()) && (m_n && m_n->isValid());
  231. }
  232. //===========================================================================
  233. //
  234. // TakeRegistrySnapshot
  235. //
  236. BOOL CPassportConfiguration::TakeRegistrySnapshot(
  237. CRegistryConfig** ppRegConfig,
  238. REGCONFIGMAP** ppConfigMap
  239. )
  240. {
  241. HKEY hkSites = 0;
  242. BOOL bReturn;
  243. *ppRegConfig = NULL;
  244. *ppConfigMap = NULL;
  245. // Registry
  246. CRegistryConfig* pNewRegConfig = new CRegistryConfig();
  247. if(!pNewRegConfig)
  248. {
  249. bReturn = FALSE;
  250. goto Cleanup;
  251. }
  252. pNewRegConfig->AddRef();
  253. //
  254. // Read in all other site configs. Only if we find a sites reg key with
  255. // one or more subkeys.
  256. //
  257. REGCONFIGMAP* pNewRegMap = NULL;
  258. {
  259. LONG lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  260. TEXT("Software\\Microsoft\\Passport\\Sites"),
  261. 0,
  262. KEY_READ,
  263. &hkSites);
  264. if(lResult == ERROR_SUCCESS)
  265. {
  266. DWORD dwNumSites;
  267. lResult = RegQueryInfoKey(hkSites,
  268. NULL,
  269. NULL,
  270. NULL,
  271. &dwNumSites,
  272. NULL,
  273. NULL,
  274. NULL,
  275. NULL,
  276. NULL,
  277. NULL,
  278. NULL);
  279. if(lResult == ERROR_SUCCESS && dwNumSites)
  280. {
  281. // need to wrap this because it uses STL and the STL constructors don't
  282. // check memory allocations and can AV in low memory conditions
  283. try
  284. {
  285. pNewRegMap = new REGCONFIGMAP();
  286. }
  287. catch(...)
  288. {
  289. bReturn = FALSE;
  290. goto Cleanup;
  291. }
  292. if(pNewRegMap)
  293. {
  294. DWORD dwKeyIndex = 0;
  295. CHAR achSiteName[256];
  296. DWORD dwSiteNameLen = sizeof(achSiteName);
  297. while(RegEnumKeyExA(hkSites,
  298. dwKeyIndex++,
  299. achSiteName,
  300. &dwSiteNameLen,
  301. NULL,
  302. NULL,
  303. NULL,
  304. NULL) == ERROR_SUCCESS)
  305. {
  306. CRegistryConfig* crSite = new CRegistryConfig(achSiteName);
  307. if(crSite)
  308. {
  309. crSite->AddRef();
  310. if (crSite->isValid())
  311. {
  312. REGCONFIGMAP::value_type* v =
  313. new REGCONFIGMAP::value_type(_strdup(crSite->getHostName()),
  314. crSite);
  315. if(v)
  316. {
  317. try
  318. {
  319. pNewRegMap->insert(*v);
  320. }
  321. catch(...)
  322. {
  323. delete v;
  324. crSite->Release();
  325. bReturn = FALSE;
  326. goto Cleanup;
  327. }
  328. delete v;
  329. }
  330. else
  331. crSite->Release();
  332. }
  333. else
  334. {
  335. if (g_pAlert)
  336. g_pAlert->report(PassportAlertInterface::ERROR_TYPE,
  337. PM_INVALID_CONFIGURATION,
  338. crSite->getFailureString());
  339. crSite->Release();
  340. }
  341. }
  342. dwSiteNameLen = sizeof(achSiteName);
  343. }
  344. }
  345. }
  346. else
  347. {
  348. pNewRegMap = NULL;
  349. }
  350. RegCloseKey(hkSites);
  351. hkSites = 0;
  352. }
  353. else
  354. {
  355. pNewRegMap = NULL;
  356. }
  357. }
  358. // Assign out parameters and return value.
  359. *ppRegConfig = pNewRegConfig;
  360. pNewRegConfig = NULL;
  361. *ppConfigMap = pNewRegMap;
  362. pNewRegMap = NULL;
  363. bReturn = TRUE;
  364. Cleanup:
  365. if (0 != hkSites)
  366. {
  367. RegCloseKey(hkSites);
  368. }
  369. if (NULL != pNewRegConfig)
  370. {
  371. delete pNewRegConfig;
  372. }
  373. if (NULL != pNewRegMap)
  374. {
  375. try
  376. {
  377. delete pNewRegMap;
  378. }
  379. catch(...)
  380. {
  381. }
  382. }
  383. return bReturn;
  384. }
  385. //===========================================================================
  386. //
  387. // ApplyRegistrySnapshot
  388. //
  389. BOOL CPassportConfiguration::ApplyRegistrySnapshot(
  390. CRegistryConfig* pRegConfig,
  391. REGCONFIGMAP* pConfigMap
  392. )
  393. {
  394. //
  395. // Record the registration state now in case it changes midstream. This
  396. // can happen during setup when we're called on a separate thread via
  397. // msppnxus!PpNotificationThread::run, which executes while msppmgr.dll
  398. // is still setting up the Passport registry values.
  399. //
  400. BOOL fRegistering = g_bRegistering;
  401. if (pRegConfig->isValid())
  402. {
  403. REGCONFIGMAP* temp = m_lastConfigMap;
  404. {
  405. PassportGuard<PassportLock> g(m_lock);
  406. if (m_rlastDefault)
  407. m_rlastDefault->Release();
  408. m_rlastDefault = m_rDefault;
  409. m_rDefault = pRegConfig;
  410. //
  411. // Shuffle config map pointers.
  412. //
  413. m_lastConfigMap = m_ConfigMap;
  414. m_ConfigMap = pConfigMap;
  415. }
  416. //
  417. // Delete the old site map.
  418. //
  419. if(temp)
  420. {
  421. REGCONFIGMAP::iterator it;
  422. while((it = temp->begin()) != temp->end())
  423. {
  424. free(it->first);
  425. it->second->Release();
  426. temp->erase(it);
  427. }
  428. delete temp;
  429. }
  430. if (g_pAlert)
  431. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, PM_VALID_CONFIGURATION);
  432. }
  433. else
  434. {
  435. if (g_pAlert && !fRegistering)
  436. {
  437. g_pAlert->report(PassportAlertInterface::ERROR_TYPE,
  438. PM_INVALID_CONFIGURATION,
  439. pRegConfig->getFailureString());
  440. }
  441. pRegConfig->Release();
  442. if(pConfigMap)
  443. {
  444. REGCONFIGMAP::iterator it;
  445. while((it = pConfigMap->begin()) != pConfigMap->end())
  446. {
  447. free(it->first);
  448. it->second->Release();
  449. pConfigMap->erase(it);
  450. }
  451. delete pConfigMap;
  452. }
  453. }
  454. return TRUE;
  455. }
  456. //===========================================================================
  457. //
  458. // TakeNexusSnapshot
  459. //
  460. BOOL CPassportConfiguration::TakeNexusSnapshot(
  461. CNexusConfig** ppNexusConfig,
  462. BOOL bForceFetch
  463. )
  464. {
  465. BOOL bReturn;
  466. CNexusConfig* pNexusConfig = NULL;
  467. CComPtr<IXMLDocument> pXMLDoc;
  468. *ppNexusConfig = NULL;
  469. if (GetCCD(_T(PRCONFIG),&pXMLDoc, bForceFetch))
  470. {
  471. pNexusConfig = new CNexusConfig();
  472. if(!pNexusConfig)
  473. {
  474. bReturn = FALSE;
  475. goto Cleanup;
  476. }
  477. if (!pNexusConfig->Read(pXMLDoc))
  478. {
  479. bReturn = FALSE;
  480. goto Cleanup;
  481. }
  482. pNexusConfig->AddRef();
  483. }
  484. else
  485. {
  486. if (g_pAlert)
  487. {
  488. if (g_pAlert)
  489. g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_CCD_NOT_LOADED, 0);
  490. }
  491. m_lastAttempt = time(NULL);
  492. bReturn = FALSE;
  493. goto Cleanup;
  494. }
  495. *ppNexusConfig = pNexusConfig;
  496. bReturn = TRUE;
  497. Cleanup:
  498. if(pNexusConfig && bReturn == FALSE)
  499. delete pNexusConfig;
  500. return bReturn;
  501. }
  502. //===========================================================================
  503. //
  504. // ApplyNexusSnapshot
  505. //
  506. BOOL CPassportConfiguration::ApplyNexusSnapshot(
  507. CNexusConfig* pNexusConfig
  508. )
  509. {
  510. BOOL bReturn;
  511. if (pNexusConfig->isValid())
  512. {
  513. PassportGuard<PassportLock> g(m_lock);
  514. if (m_nlast)
  515. m_nlast->Release();
  516. m_nlast = m_n;
  517. m_n = pNexusConfig;
  518. if (g_pAlert)
  519. g_pAlert->report(PassportAlertInterface::INFORMATION_TYPE, PM_CCD_LOADED);
  520. }
  521. else
  522. {
  523. // NexusConfig throws an alert already
  524. if (pNexusConfig)
  525. {
  526. pNexusConfig->Release();
  527. }
  528. bReturn = FALSE;
  529. goto Cleanup;
  530. }
  531. bReturn = TRUE;
  532. Cleanup:
  533. return bReturn;
  534. }
  535. //===========================================================================
  536. //
  537. // UpdateNow
  538. //
  539. // Update both configs
  540. BOOL CPassportConfiguration::UpdateNow(BOOL forceFetch)
  541. {
  542. BOOL bReturn;
  543. time_t now;
  544. CComPtr<IXMLDocument> is;
  545. time(&now);
  546. if(m_bUpdateInProgress)
  547. {
  548. bReturn = FALSE;
  549. goto Cleanup;
  550. }
  551. if (now - m_lastAttempt < 60 && m_n == NULL)
  552. {
  553. // Don't overload on attempts to the nexus
  554. bReturn = FALSE;
  555. goto Cleanup;
  556. }
  557. // Registry
  558. LocalConfigurationUpdated();
  559. if (m_rDefault == NULL)
  560. {
  561. m_lastAttempt = now - 30;
  562. bReturn = FALSE;
  563. goto Cleanup;
  564. }
  565. //
  566. // If we are registering msppmgr.dll then we don't want to try and fetch the CCD
  567. // since the registration occurs during setup and at that time the network isn't
  568. // available. If this does occur then msppmgr.dll hangs and setup breaks in with
  569. // registration time out.
  570. //
  571. if (!g_bRegistering)
  572. {
  573. if (GetCCD(_T(PRCONFIG),&is, forceFetch))
  574. {
  575. try
  576. {
  577. NexusConfigUpdated(is);
  578. }
  579. catch(...)
  580. {
  581. if (g_pAlert)
  582. {
  583. if (g_pAlert)
  584. g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_CCD_NOT_LOADED, 0);
  585. }
  586. bReturn = FALSE;
  587. goto Cleanup;
  588. }
  589. }
  590. else
  591. {
  592. if (g_pAlert)
  593. {
  594. if (g_pAlert)
  595. g_pAlert->report(PassportAlertInterface::ERROR_TYPE, PM_CCD_NOT_LOADED, 0);
  596. }
  597. m_lastAttempt = now;
  598. bReturn = FALSE;
  599. goto Cleanup;
  600. }
  601. }
  602. if (!m_n)
  603. {
  604. m_lastAttempt = now;
  605. bReturn = FALSE;
  606. goto Cleanup;
  607. }
  608. m_lastAttempt = 0;
  609. bReturn = TRUE;
  610. Cleanup:
  611. return bReturn;
  612. }
  613. //===========================================================================
  614. //
  615. // PrepareUpdate
  616. //
  617. BOOL CPassportConfiguration::PrepareUpdate(BOOL forceFetch)
  618. {
  619. BOOL bReturn;
  620. static PassportLock prepareLock;
  621. PassportGuard<PassportLock> g(prepareLock);
  622. // Don't allow another first phase while second phase
  623. // is pending.
  624. //if(m_bUpdateInProgress)
  625. //{
  626. // bReturn = FALSE;
  627. // goto Cleanup;
  628. //}
  629. // The PrepareUpdate is called by the Refresh method in msppext.dll where
  630. // a lock value is maintained to prevent calling first phase PrepareUpdate
  631. // while second phase CommitUpdate is pending. If for some reason the Refresh
  632. // aborts after calling PrepareUpdate and before calling CommintUpdate,
  633. // m_bUpdateInProgress will remain true preventing future Refresh. Since no first
  634. // first phase PrepareUpdate can be called while second phase CommitUpdate is pending,
  635. // m_bUpdateInProgress can be set to false safely
  636. //if(m_bUpdateInProgress)
  637. {
  638. if(m_ConfigMapPending)
  639. {
  640. REGCONFIGMAP::iterator it;
  641. while((it = m_ConfigMapPending->begin()) != m_ConfigMapPending->end())
  642. {
  643. it->second->Release();
  644. free(it->first);
  645. m_ConfigMapPending->erase(it);
  646. }
  647. delete m_ConfigMapPending;
  648. m_ConfigMapPending = NULL;
  649. }
  650. if (m_rPending)
  651. {
  652. m_rPending->Release();
  653. m_rPending = NULL;
  654. }
  655. if (m_nPending)
  656. {
  657. m_nPending->Release();
  658. m_nPending = NULL;
  659. }
  660. m_bUpdateInProgress = false;
  661. }
  662. // Get the current registry config.
  663. if (!TakeRegistrySnapshot(&m_rPending, &m_ConfigMapPending))
  664. return FALSE;
  665. // Get the latest xml
  666. if (!TakeNexusSnapshot(&m_nPending, forceFetch))
  667. return FALSE;
  668. m_bUpdateInProgress = true;
  669. bReturn = TRUE;
  670. return bReturn;
  671. }
  672. //===========================================================================
  673. //
  674. // CommitUpdate
  675. //
  676. BOOL CPassportConfiguration::CommitUpdate()
  677. {
  678. BOOL bReturn;
  679. // Update default registry and any sites
  680. if(!ApplyRegistrySnapshot(m_rPending, m_ConfigMapPending))
  681. {
  682. bReturn = FALSE;
  683. goto Cleanup;
  684. }
  685. if(!ApplyNexusSnapshot(m_nPending))
  686. {
  687. bReturn = FALSE;
  688. goto Cleanup;
  689. }
  690. m_rPending = NULL;
  691. m_ConfigMapPending = NULL;
  692. m_nPending = NULL;
  693. bReturn = TRUE;
  694. Cleanup:
  695. m_bUpdateInProgress = false;
  696. return bReturn;
  697. }
  698. //===========================================================================
  699. //
  700. // LocalConfigurationUpdated
  701. //
  702. void CPassportConfiguration::LocalConfigurationUpdated()
  703. {
  704. //
  705. // Read in default config.
  706. //
  707. CRegistryConfig* pNewRegConfig;
  708. REGCONFIGMAP* pNewConfigMap;
  709. if(!TakeRegistrySnapshot(&pNewRegConfig, &pNewConfigMap))
  710. return;
  711. //
  712. // Here we don't care about the results of reading in non-default sites. pNewConfigMap will be NULL
  713. // if anything bad happened and events will be in the event log. As long as we have a valid
  714. // default configuration we can go ahead and do the switch.
  715. //
  716. ApplyRegistrySnapshot(pNewRegConfig, pNewConfigMap);
  717. }
  718. //===========================================================================
  719. //
  720. // NexusConfigUpdated
  721. //
  722. void CPassportConfiguration::NexusConfigUpdated(IXMLDocument *is)
  723. {
  724. CNexusConfig *newc = new CNexusConfig();
  725. if (newc)
  726. {
  727. if (newc->Read(is))
  728. {
  729. newc->AddRef();
  730. ApplyNexusSnapshot(newc);
  731. }
  732. else
  733. {
  734. delete newc;
  735. }
  736. }
  737. }
  738. //===========================================================================
  739. //
  740. // getFailureString
  741. //
  742. LPWSTR CPassportConfiguration::getFailureString()
  743. {
  744. // IsValid must be called before this
  745. if (!m_rDefault)
  746. return L"Registry configuration failed.";
  747. if (!m_rDefault->isValid())
  748. return m_rDefault->getFailureString();
  749. if (!m_n)
  750. return L"Nexus configuration failed.";
  751. if (!m_n->isValid())
  752. return m_n->getFailureString();
  753. return L"OK";
  754. }
  755. //===========================================================================
  756. //
  757. // HasSites
  758. //
  759. BOOL
  760. CPassportConfiguration::HasSites()
  761. {
  762. return (m_ConfigMap && m_ConfigMap->size());
  763. }
  764. //===========================================================================
  765. //
  766. // Dump
  767. //
  768. void
  769. CPassportConfiguration::Dump(BSTR* pbstrDump)
  770. {
  771. //m_rDefault->Dump(pbstrDump);
  772. //m_ConfigMap->Dump(pbstrDump);
  773. m_n->Dump(pbstrDump);
  774. }