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.

1655 lines
37 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. HelpTab.cpp
  5. Abstract:
  6. Implementation of __HelpEntry structure and CHelpSessionTable.
  7. Author:
  8. HueiWang 06/29/2000
  9. --*/
  10. #include "stdafx.h"
  11. #include <time.h>
  12. #include <windows.h>
  13. #include <wincrypt.h>
  14. #include <stdio.h>
  15. #include <tchar.h>
  16. #include "helptab.h"
  17. #include "policy.h"
  18. #include "remotedesktoputils.h"
  19. #include "helper.h"
  20. //
  21. //
  22. // __HelpEntry strucutre implementation
  23. //
  24. //
  25. HRESULT
  26. __HelpEntry::LoadEntryValues(
  27. IN HKEY hKey
  28. )
  29. /*++
  30. Routine Description:
  31. Load help session entry from registry key.
  32. Parameters:
  33. hKey : Handle to registry key containing help entry values.
  34. Returns:
  35. S_OK or error code.
  36. --*/
  37. {
  38. DWORD dwStatus;
  39. MYASSERT( NULL != hKey );
  40. if( NULL != hKey )
  41. {
  42. dwStatus = m_EntryStatus.DBLoadValue( hKey );
  43. if( ERROR_SUCCESS != dwStatus )
  44. {
  45. goto CLEANUPANDEXIT;
  46. }
  47. if( REGVALUE_HELPSESSION_ENTRY_DELETED == m_EntryStatus )
  48. {
  49. // entry already been deleted, no reason to continue loading
  50. dwStatus = ERROR_FILE_NOT_FOUND;
  51. goto CLEANUPANDEXIT;
  52. }
  53. dwStatus = m_SessionId.DBLoadValue(hKey);
  54. if( ERROR_SUCCESS != dwStatus )
  55. {
  56. goto CLEANUPANDEXIT;
  57. }
  58. if( m_SessionId->Length() == 0 )
  59. {
  60. // Help Session ID must exist, no default value.
  61. dwStatus = ERROR_INVALID_DATA;
  62. goto CLEANUPANDEXIT;
  63. }
  64. dwStatus = m_EnableResolver.DBLoadValue(hKey);
  65. if( ERROR_SUCCESS != dwStatus )
  66. {
  67. goto CLEANUPANDEXIT;
  68. }
  69. dwStatus = m_SessResolverBlob.DBLoadValue(hKey);
  70. if( ERROR_SUCCESS != dwStatus )
  71. {
  72. goto CLEANUPANDEXIT;
  73. }
  74. dwStatus = m_UserSID.DBLoadValue(hKey);
  75. if( ERROR_SUCCESS != dwStatus )
  76. {
  77. goto CLEANUPANDEXIT;
  78. }
  79. dwStatus = m_CreationTime.DBLoadValue(hKey);
  80. if( ERROR_SUCCESS != dwStatus )
  81. {
  82. goto CLEANUPANDEXIT;
  83. }
  84. dwStatus = m_ExpirationTime.DBLoadValue(hKey);
  85. if( ERROR_SUCCESS != dwStatus )
  86. {
  87. goto CLEANUPANDEXIT;
  88. }
  89. dwStatus = m_SessionRdsSetting.DBLoadValue(hKey);
  90. if( ERROR_SUCCESS != dwStatus )
  91. {
  92. goto CLEANUPANDEXIT;
  93. }
  94. dwStatus = m_EntryStatus.DBLoadValue(hKey);
  95. if( ERROR_SUCCESS != dwStatus )
  96. {
  97. goto CLEANUPANDEXIT;
  98. }
  99. dwStatus = m_CreationTime.DBLoadValue(hKey);
  100. if( ERROR_SUCCESS != dwStatus )
  101. {
  102. goto CLEANUPANDEXIT;
  103. }
  104. dwStatus = m_IpAddress.DBLoadValue(hKey);
  105. if( ERROR_SUCCESS != dwStatus )
  106. {
  107. goto CLEANUPANDEXIT;
  108. }
  109. dwStatus = m_ICSPort.DBLoadValue(hKey);
  110. if( ERROR_SUCCESS != dwStatus )
  111. {
  112. goto CLEANUPANDEXIT;
  113. }
  114. dwStatus = m_SessionCreateBlob.DBLoadValue(hKey);
  115. }
  116. else
  117. {
  118. dwStatus = E_UNEXPECTED;
  119. }
  120. CLEANUPANDEXIT:
  121. return HRESULT_FROM_WIN32(dwStatus);
  122. }
  123. HRESULT
  124. __HelpEntry::UpdateEntryValues(
  125. IN HKEY hKey
  126. )
  127. /*++
  128. Routine Description:
  129. Update/store help entry value to registry.
  130. Parameters:
  131. hKey : Handle to registry to save help entry value.
  132. Returns:
  133. S_OK or error code.
  134. --*/
  135. {
  136. DWORD dwStatus;
  137. MYASSERT( NULL != hKey );
  138. if( NULL == hKey )
  139. {
  140. dwStatus = E_UNEXPECTED;
  141. goto CLEANUPANDEXIT;
  142. }
  143. if( REGVALUE_HELPSESSION_ENTRY_DELETED == m_EntryStatus )
  144. {
  145. // entry already deleted, error out
  146. dwStatus = ERROR_FILE_NOT_FOUND;
  147. goto CLEANUPANDEXIT;
  148. }
  149. // New entry value, entry status in registry is set
  150. // to delete so when we failed to completely writting
  151. // all value to registry, we can still assume it is
  152. // deleted.
  153. if( REGVALUE_HELPSESSION_ENTRY_NEW != m_EntryStatus )
  154. {
  155. // Mark entry dirty.
  156. m_EntryStatus = REGVALUE_HELPSESSION_ENTRY_DIRTY;
  157. dwStatus = m_EntryStatus.DBUpdateValue( hKey );
  158. if( ERROR_SUCCESS != dwStatus )
  159. {
  160. goto CLEANUPANDEXIT;
  161. }
  162. }
  163. dwStatus = m_SessionId.DBUpdateValue(hKey);
  164. if( ERROR_SUCCESS != dwStatus )
  165. {
  166. goto CLEANUPANDEXIT;
  167. }
  168. dwStatus = m_EnableResolver.DBUpdateValue(hKey);
  169. if( ERROR_SUCCESS != dwStatus )
  170. {
  171. goto CLEANUPANDEXIT;
  172. }
  173. dwStatus = m_SessResolverBlob.DBUpdateValue(hKey);
  174. if( ERROR_SUCCESS != dwStatus )
  175. {
  176. goto CLEANUPANDEXIT;
  177. }
  178. dwStatus = m_UserSID.DBUpdateValue(hKey);
  179. if( ERROR_SUCCESS != dwStatus )
  180. {
  181. goto CLEANUPANDEXIT;
  182. }
  183. dwStatus = m_CreationTime.DBUpdateValue(hKey);
  184. if( ERROR_SUCCESS != dwStatus )
  185. {
  186. goto CLEANUPANDEXIT;
  187. }
  188. dwStatus = m_ExpirationTime.DBUpdateValue(hKey);
  189. if( ERROR_SUCCESS != dwStatus )
  190. {
  191. goto CLEANUPANDEXIT;
  192. }
  193. dwStatus = m_SessionRdsSetting.DBUpdateValue(hKey);
  194. if( ERROR_SUCCESS != dwStatus )
  195. {
  196. goto CLEANUPANDEXIT;
  197. }
  198. dwStatus = m_IpAddress.DBUpdateValue(hKey);
  199. if( ERROR_SUCCESS != dwStatus )
  200. {
  201. goto CLEANUPANDEXIT;
  202. }
  203. dwStatus = m_ICSPort.DBUpdateValue(hKey);
  204. if( ERROR_SUCCESS != dwStatus )
  205. {
  206. goto CLEANUPANDEXIT;
  207. }
  208. dwStatus = m_SessionCreateBlob.DBUpdateValue(hKey);
  209. if( ERROR_SUCCESS != dwStatus )
  210. {
  211. goto CLEANUPANDEXIT;
  212. }
  213. // Mark entry normal
  214. m_EntryStatus = REGVALUE_HELPSESSION_ENTRY_NORMAL;
  215. dwStatus = m_EntryStatus.DBUpdateValue( hKey );
  216. CLEANUPANDEXIT:
  217. return HRESULT_FROM_WIN32(dwStatus);
  218. }
  219. HRESULT
  220. __HelpEntry::BackupEntry()
  221. /*++
  222. Routine Description:
  223. Backup help entry, backup is stored under
  224. <Help Entry Registry>\\Backup registry key.
  225. Parameters:
  226. None.
  227. Returns:
  228. S_OK or error code.
  229. --*/
  230. {
  231. HKEY hKey = NULL;
  232. DWORD dwStatus;
  233. MYASSERT( NULL != m_hEntryKey );
  234. if( NULL != m_hEntryKey )
  235. {
  236. //
  237. // Delete current backup
  238. (void)DeleteEntryBackup();
  239. //
  240. // Create a backup registry key
  241. dwStatus = RegCreateKeyEx(
  242. m_hEntryKey,
  243. REGKEY_HELPENTRYBACKUP,
  244. 0,
  245. NULL,
  246. REG_OPTION_NON_VOLATILE,
  247. KEY_ALL_ACCESS,
  248. NULL,
  249. &hKey,
  250. NULL
  251. );
  252. if( ERROR_SUCCESS != dwStatus )
  253. {
  254. MYASSERT(FALSE);
  255. }
  256. else
  257. {
  258. dwStatus = UpdateEntryValues( hKey );
  259. }
  260. }
  261. else
  262. {
  263. dwStatus = E_UNEXPECTED;
  264. }
  265. if( NULL != hKey )
  266. {
  267. RegCloseKey( hKey );
  268. }
  269. return HRESULT_FROM_WIN32(dwStatus);
  270. }
  271. HRESULT
  272. __HelpEntry::RestoreEntryFromBackup()
  273. /*++
  274. Routine Description:
  275. Restore help entry from backup, backup is stored under
  276. <Help Entry Registry>\\Backup registry key.
  277. Parameters:
  278. None.
  279. Returns:
  280. S_OK or error code.
  281. --*/
  282. {
  283. DWORD dwStatus;
  284. HKEY hBackupKey = NULL;
  285. MYASSERT( NULL != m_hEntryKey );
  286. if( NULL != m_hEntryKey )
  287. {
  288. //
  289. // check if backup registry exists.
  290. dwStatus = RegOpenKeyEx(
  291. m_hEntryKey,
  292. REGKEY_HELPENTRYBACKUP,
  293. 0,
  294. KEY_ALL_ACCESS,
  295. &hBackupKey
  296. );
  297. if( ERROR_SUCCESS == dwStatus )
  298. {
  299. HELPENTRY backup( m_pHelpSessionTable, hBackupKey, ENTRY_VALID_PERIOD );
  300. // load backup values
  301. dwStatus = backup.LoadEntryValues( hBackupKey );
  302. if( ERROR_SUCCESS == dwStatus )
  303. {
  304. if( (DWORD)backup.m_EntryStatus == REGVALUE_HELPSESSION_ENTRY_NORMAL )
  305. {
  306. *this = backup;
  307. }
  308. else
  309. {
  310. (void)DeleteEntryBackup();
  311. dwStatus = ERROR_FILE_NOT_FOUND;
  312. }
  313. }
  314. // HELPSESSION destructor will close registry key
  315. }
  316. if( ERROR_SUCCESS == dwStatus )
  317. {
  318. //
  319. // update all values.
  320. dwStatus = UpdateEntryValues( m_hEntryKey );
  321. if( ERROR_SUCCESS == dwStatus )
  322. {
  323. //
  324. // Already restore entry, delete backup copy
  325. (void)DeleteEntryBackup();
  326. }
  327. }
  328. }
  329. else
  330. {
  331. dwStatus = E_UNEXPECTED;
  332. }
  333. return HRESULT_FROM_WIN32( dwStatus );
  334. }
  335. HRESULT
  336. __HelpEntry::DeleteEntryBackup()
  337. /*++
  338. Routine Description:
  339. Delete help entry backup from registry.
  340. Parameters:
  341. None.
  342. Returns:
  343. always S_OK
  344. --*/
  345. {
  346. DWORD dwStatus;
  347. dwStatus = RegDelKey(
  348. m_hEntryKey,
  349. REGKEY_HELPENTRYBACKUP
  350. );
  351. return HRESULT_FROM_WIN32(dwStatus);
  352. }
  353. BOOL
  354. __HelpEntry::IsEntryExpired()
  355. {
  356. FILETIME ft;
  357. ULARGE_INTEGER ul1, ul2;
  358. GetSystemTimeAsFileTime(&ft);
  359. ul1.LowPart = ft.dwLowDateTime;
  360. ul1.HighPart = ft.dwHighDateTime;
  361. ft = (FILETIME)m_ExpirationTime;
  362. ul2.LowPart = ft.dwLowDateTime;
  363. ul2.HighPart = ft.dwHighDateTime;
  364. #if DBG
  365. if( ul1.QuadPart >= ul2.QuadPart )
  366. {
  367. DebugPrintf(
  368. _TEXT("Help Entry %s has expired ...\n"),
  369. (LPCTSTR)(CComBSTR)m_SessionId
  370. );
  371. }
  372. #endif
  373. return (ul1.QuadPart >= ul2.QuadPart);
  374. }
  375. ////////////////////////////////////////////////////////////////////////////////
  376. //
  377. // CHelpSessionTable implementation
  378. //
  379. CHelpSessionTable::CHelpSessionTable() :
  380. m_hHelpSessionTableKey(NULL), m_NumHelp(0)
  381. {
  382. HKEY hKey = NULL;
  383. DWORD dwStatus;
  384. DWORD dwSize;
  385. DWORD dwType;
  386. //
  387. // Load entry valid period setting from registry
  388. //
  389. dwStatus = RegOpenKeyEx(
  390. HKEY_LOCAL_MACHINE,
  391. RDS_MACHINEPOLICY_SUBTREE,
  392. 0,
  393. KEY_READ,
  394. &hKey
  395. );
  396. if( ERROR_SUCCESS == dwStatus )
  397. {
  398. dwSize = sizeof(DWORD);
  399. dwStatus = RegQueryValueEx(
  400. hKey,
  401. RDS_HELPENTRY_VALID_PERIOD,
  402. NULL,
  403. &dwType,
  404. (PBYTE) &m_dwEntryValidPeriod,
  405. &dwSize
  406. );
  407. if( REG_DWORD != dwType )
  408. {
  409. dwStatus = ERROR_FILE_NOT_FOUND;
  410. }
  411. RegCloseKey(hKey);
  412. }
  413. if(ERROR_SUCCESS != dwStatus )
  414. {
  415. // pick default value
  416. m_dwEntryValidPeriod = ENTRY_VALID_PERIOD;
  417. }
  418. }
  419. HRESULT
  420. CHelpSessionTable::RestoreHelpSessionTable(
  421. IN HKEY hKey,
  422. IN LPTSTR pszKeyName,
  423. IN HANDLE userData
  424. )
  425. /*++
  426. Routine Description:
  427. Restore help session table. This routine is callback from RegEnumSubKeys().
  428. Parameters:
  429. hKey : Handle to registry.
  430. pszKeyName : registry sub-key name containing one help session entry
  431. userData : User defined data.
  432. Returns:
  433. S_OK or error code.
  434. --*/
  435. {
  436. HRESULT hRes;
  437. if( NULL == userData )
  438. {
  439. hRes = E_UNEXPECTED;
  440. MYASSERT(FALSE);
  441. }
  442. else
  443. {
  444. CHelpSessionTable* pTable = (CHelpSessionTable *) userData;
  445. hRes = pTable->RestoreHelpSessionEntry( hKey, pszKeyName );
  446. if( SUCCEEDED(hRes) )
  447. {
  448. pTable->m_NumHelp++;
  449. }
  450. hRes = S_OK;
  451. }
  452. return hRes;
  453. }
  454. BOOL
  455. CHelpSessionTable::IsEntryExpired(
  456. IN PHELPENTRY pEntry
  457. )
  458. /*++
  459. Routine Description:
  460. Determine if a help entry has expired.
  461. Paramters:
  462. pEntry : Pointer to help entry.
  463. Returns:
  464. TRUE if entry has expired, FALSE otherwise.
  465. --*/
  466. {
  467. MYASSERT( NULL != pEntry );
  468. return (NULL != pEntry) ? pEntry->IsEntryExpired() : TRUE;
  469. }
  470. HRESULT
  471. CHelpSessionTable::RestoreHelpSessionEntry(
  472. IN HKEY hKey,
  473. IN LPTSTR pszKeyName
  474. )
  475. /*++
  476. Routine Description:
  477. Restore a single help session entry.
  478. Parameters:
  479. hKey : Handle to help session table.
  480. pszKeyName : Registry sub-key name containing help entry.
  481. Returns:
  482. S_OK or error code.
  483. --*/
  484. {
  485. HKEY hEntryKey = NULL;
  486. DWORD dwStatus;
  487. DWORD dwDuplicate = REG_CREATED_NEW_KEY;
  488. LONG entryStatus;
  489. BOOL bDeleteEntry = FALSE;
  490. //
  491. // Open the registry key for session entry
  492. dwStatus = RegOpenKeyEx(
  493. hKey,
  494. pszKeyName,
  495. 0,
  496. KEY_ALL_ACCESS,
  497. &hEntryKey
  498. );
  499. if( ERROR_SUCCESS == dwStatus )
  500. {
  501. HELPENTRY helpEntry( *this, hEntryKey, m_dwEntryValidPeriod );
  502. // load help entry
  503. dwStatus = helpEntry.Refresh();
  504. if( dwStatus != ERROR_SUCCESS || helpEntry.m_SessionId->Length() == 0 ||
  505. REGVALUE_HELPSESSION_ENTRY_DELETEONSTARTUP == helpEntry.m_EntryStatus )
  506. {
  507. // Session ID must not be NULL.
  508. bDeleteEntry = TRUE;
  509. }
  510. else
  511. {
  512. if( REGVALUE_HELPSESSION_ENTRY_DELETED != helpEntry.m_EntryStatus )
  513. {
  514. if( TRUE != IsEntryExpired( &helpEntry ) )
  515. {
  516. if( REGVALUE_HELPSESSION_ENTRY_DIRTY == helpEntry.m_EntryStatus )
  517. {
  518. // Entry is partially updated, try to restore from backup,
  519. // is failed restoring, treat as bad entry.
  520. if( FAILED(helpEntry.RestoreEntryFromBackup()) )
  521. {
  522. bDeleteEntry = TRUE;
  523. }
  524. }
  525. }
  526. else
  527. {
  528. LPTSTR eventString[2];
  529. BSTR pszNoviceDomain = NULL;
  530. BSTR pszNoviceName = NULL;
  531. HRESULT hr;
  532. //
  533. // Log the event indicate that ticket was deleted, non-critical
  534. // since we can still continue to run.
  535. //
  536. hr = ConvertSidToAccountName( (CComBSTR)helpEntry.m_UserSID, &pszNoviceDomain, &pszNoviceName );
  537. if( SUCCEEDED(hr) )
  538. {
  539. eventString[0] = pszNoviceDomain;
  540. eventString[1] = pszNoviceName;
  541. LogRemoteAssistanceEventString(
  542. EVENTLOG_INFORMATION_TYPE,
  543. SESSMGR_I_REMOTEASSISTANCE_DELETEDTICKET,
  544. 2,
  545. eventString
  546. );
  547. DebugPrintf(
  548. _TEXT("Help Entry has expired %s\n"),
  549. (CComBSTR)helpEntry.m_SessionId
  550. );
  551. }
  552. if( pszNoviceDomain )
  553. {
  554. SysFreeString( pszNoviceDomain );
  555. }
  556. if( pszNoviceName )
  557. {
  558. SysFreeString( pszNoviceName );
  559. }
  560. }
  561. }
  562. else
  563. {
  564. bDeleteEntry = TRUE;
  565. }
  566. }
  567. }
  568. if( TRUE == bDeleteEntry )
  569. {
  570. dwStatus = RegDelKey( hKey, pszKeyName );
  571. //
  572. // Ignore error
  573. //
  574. DebugPrintf(
  575. _TEXT("RegDelKey on entry %s returns %d\n"),
  576. pszKeyName,
  577. dwStatus
  578. );
  579. dwStatus = ERROR_FILE_NOT_FOUND;
  580. }
  581. return HRESULT_FROM_WIN32( dwStatus );
  582. }
  583. HRESULT
  584. CHelpSessionTable::LoadHelpEntry(
  585. IN HKEY hKey,
  586. IN LPTSTR pszKeyName,
  587. OUT PHELPENTRY* ppHelpSession
  588. )
  589. /*++
  590. Routine description:
  591. Load a help entry from registry.
  592. Parameters:
  593. hKey : registry handle to help session table.
  594. pszKeyName : registry sub-key name (Help session ID).
  595. ppHelpSession : Pointer to PHELPENTRY to receive loaded help
  596. entry.
  597. Returns:
  598. S_OK or error code.
  599. --*/
  600. {
  601. PHELPENTRY pSess;
  602. HRESULT hRes;
  603. HKEY hEntryKey = NULL;
  604. DWORD dwStatus;
  605. MYASSERT( NULL != hKey );
  606. if( NULL != hKey )
  607. {
  608. // open the registry containing help entry
  609. dwStatus = RegOpenKeyEx(
  610. hKey,
  611. pszKeyName,
  612. 0,
  613. KEY_ALL_ACCESS,
  614. &hEntryKey
  615. );
  616. if( ERROR_SUCCESS == dwStatus )
  617. {
  618. pSess = new HELPENTRY( *this, hEntryKey, m_dwEntryValidPeriod );
  619. if( NULL == pSess )
  620. {
  621. hRes = E_OUTOFMEMORY;
  622. }
  623. else
  624. {
  625. // load help entry, Refresh() will failed if
  626. // session ID is NULL or emptry string
  627. hRes = pSess->Refresh();
  628. if( SUCCEEDED(hRes) )
  629. {
  630. if( (DWORD)pSess->m_EntryStatus == REGVALUE_HELPSESSION_ENTRY_NORMAL )
  631. {
  632. *ppHelpSession = pSess;
  633. }
  634. else
  635. {
  636. dwStatus = ERROR_FILE_NOT_FOUND;
  637. }
  638. }
  639. if( FAILED(hRes) )
  640. {
  641. pSess->Release();
  642. }
  643. }
  644. }
  645. else
  646. {
  647. hRes = HRESULT_FROM_WIN32( dwStatus );
  648. }
  649. }
  650. else
  651. {
  652. hRes = E_UNEXPECTED;
  653. }
  654. return hRes;
  655. }
  656. HRESULT
  657. CHelpSessionTable::OpenSessionTable(
  658. IN LPCTSTR pszFileName // reserverd.
  659. )
  660. /*++
  661. Routine Description:
  662. Open help session table, routine enumerate all help entry (registry sub-key),
  663. and restore/delete help entry if necessary.
  664. Parameters:
  665. pszFileName : reserved parameter, must be NULL.
  666. Returns:
  667. S_OK or error code.
  668. --*/
  669. {
  670. DWORD dwStatus;
  671. HRESULT hr;
  672. CCriticalSectionLocker l(m_TableLock);
  673. //
  674. // Go thru all sub-key containing help entry and restore or delete
  675. // help entry if necessary.
  676. dwStatus = RegEnumSubKeys(
  677. HKEY_LOCAL_MACHINE,
  678. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
  679. RestoreHelpSessionTable,
  680. (HANDLE)this
  681. );
  682. if( ERROR_SUCCESS != dwStatus )
  683. {
  684. if( NULL != m_hHelpSessionTableKey )
  685. {
  686. // Make sure registry key is not opened.
  687. RegCloseKey(m_hHelpSessionTableKey);
  688. m_hHelpSessionTableKey = NULL;
  689. }
  690. // If table is bad, delete and re-create again
  691. dwStatus = RegDelKey(
  692. HKEY_LOCAL_MACHINE,
  693. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
  694. );
  695. if( ERROR_SUCCESS != dwStatus && ERROR_FILE_NOT_FOUND != dwStatus )
  696. {
  697. // Critical error
  698. MYASSERT(FALSE);
  699. goto CLEANUPANDEXIT;
  700. }
  701. hr = CreatePendingHelpTable();
  702. dwStatus = HRESULT_CODE(hr);
  703. if( ERROR_SUCCESS != dwStatus )
  704. {
  705. // we need registry key be ACLed.
  706. MYASSERT(FALSE);
  707. goto CLEANUPANDEXIT;
  708. }
  709. }
  710. dwStatus = RegOpenKeyEx(
  711. HKEY_LOCAL_MACHINE,
  712. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
  713. 0,
  714. KEY_ALL_ACCESS,
  715. &m_hHelpSessionTableKey
  716. );
  717. if( ERROR_SUCCESS != dwStatus )
  718. {
  719. MYASSERT(FALSE);
  720. goto CLEANUPANDEXIT;
  721. }
  722. else
  723. {
  724. m_bstrFileName = pszFileName;
  725. }
  726. CLEANUPANDEXIT:
  727. return HRESULT_FROM_WIN32(dwStatus);
  728. }
  729. HRESULT
  730. CHelpSessionTable::CloseSessionTable()
  731. /*++
  732. Routine Description:
  733. Close help session table.
  734. Parameters:
  735. None.
  736. Returns:
  737. S_OK or error code.
  738. --*/
  739. {
  740. // no help is opened.
  741. CCriticalSectionLocker l(m_TableLock);
  742. //
  743. // release all cached help entries
  744. for( HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.begin();
  745. it != m_HelpEntryCache.end();
  746. it++
  747. )
  748. {
  749. if( ((*it).second)->m_RefCount > 1 )
  750. {
  751. MYASSERT(FALSE);
  752. }
  753. ((*it).second)->Release();
  754. }
  755. m_HelpEntryCache.erase_all();
  756. MYASSERT( m_HelpEntryCache.size() == 0 );
  757. if( NULL != m_hHelpSessionTableKey )
  758. {
  759. RegCloseKey( m_hHelpSessionTableKey );
  760. m_hHelpSessionTableKey = NULL;
  761. }
  762. return S_OK;
  763. }
  764. HRESULT
  765. CHelpSessionTable::DeleteSessionTable()
  766. /*++
  767. Routine description:
  768. Delete entire help session table.
  769. Parameters:
  770. None.
  771. Returns:
  772. S_OK or error code.
  773. --*/
  774. {
  775. HRESULT hRes;
  776. DWORD dwStatus;
  777. CCriticalSectionLocker l(m_TableLock);
  778. hRes = CloseSessionTable();
  779. if( SUCCEEDED(hRes) )
  780. {
  781. // Recursively delete registry key and its sub-keys.
  782. dwStatus = RegDelKey(
  783. HKEY_LOCAL_MACHINE,
  784. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
  785. );
  786. if( ERROR_SUCCESS == dwStatus )
  787. {
  788. hRes = OpenSessionTable( m_bstrFileName );
  789. }
  790. else
  791. {
  792. hRes = HRESULT_FROM_WIN32( dwStatus );
  793. }
  794. }
  795. return hRes;
  796. }
  797. HRESULT
  798. CHelpSessionTable::MemEntryToStorageEntry(
  799. IN PHELPENTRY pEntry
  800. )
  801. /*++
  802. Routine Description:
  803. Conver an in-memory help entry to persist help entry.
  804. Parameters:
  805. pEntry : Pointer to HELPENTRY to be converted.
  806. Returns:
  807. S_OK or error code.
  808. --*/
  809. {
  810. HRESULT hRes;
  811. CCriticalSectionLocker l(m_TableLock);
  812. if( NULL != pEntry )
  813. {
  814. //
  815. // Check to see if this is in-memory entry
  816. //
  817. if( FALSE == pEntry->IsInMemoryHelpEntry() )
  818. {
  819. hRes = E_INVALIDARG;
  820. }
  821. else
  822. {
  823. DWORD dwStatus;
  824. HKEY hKey;
  825. //
  826. // Create a help entry here
  827. //
  828. dwStatus = RegCreateKeyEx(
  829. m_hHelpSessionTableKey,
  830. (LPCTSTR)(CComBSTR)pEntry->m_SessionId,
  831. 0,
  832. NULL,
  833. REG_OPTION_NON_VOLATILE,
  834. KEY_ALL_ACCESS,
  835. NULL,
  836. &hKey,
  837. NULL
  838. );
  839. if( ERROR_SUCCESS == dwStatus )
  840. {
  841. hRes = pEntry->UpdateEntryValues(hKey);
  842. if( SUCCEEDED(hRes) )
  843. {
  844. pEntry->ConvertHelpEntry( hKey );
  845. try {
  846. m_HelpEntryCache[(CComBSTR)pEntry->m_SessionId] = pEntry;
  847. }
  848. catch(CMAPException e) {
  849. hRes = HRESULT_FROM_WIN32( e.m_ErrorCode );
  850. }
  851. catch(...) {
  852. hRes = E_UNEXPECTED;
  853. throw;
  854. }
  855. }
  856. }
  857. else
  858. {
  859. hRes = HRESULT_FROM_WIN32( dwStatus );
  860. MYASSERT(FALSE);
  861. }
  862. }
  863. }
  864. else
  865. {
  866. MYASSERT(FALSE);
  867. hRes = E_UNEXPECTED;
  868. }
  869. return hRes;
  870. }
  871. HRESULT
  872. CHelpSessionTable::CreateInMemoryHelpEntry(
  873. IN const CComBSTR& bstrHelpSession,
  874. OUT PHELPENTRY* ppHelpEntry
  875. )
  876. /*++
  877. Routine Description:
  878. Create an in-memory help entry, this help entry is not
  879. persisted into registry until MemEntryToStorageEntry() is called.
  880. Paramters:
  881. bstrHelpSession : Help Session ID.
  882. ppHelpEntry : Newly created HELPENTRY.
  883. Returns:
  884. S_OK or error code.
  885. --*/
  886. {
  887. HRESULT hRes = S_OK;
  888. CCriticalSectionLocker l(m_TableLock);
  889. MYASSERT( NULL != m_hHelpSessionTableKey );
  890. if( NULL != m_hHelpSessionTableKey )
  891. {
  892. DWORD dwStatus;
  893. HKEY hKey;
  894. DWORD dwDeposition;
  895. DWORD dwEntryStatus;
  896. // Create a key here so we can tell if this is a duplicate
  897. dwStatus = RegCreateKeyEx(
  898. m_hHelpSessionTableKey,
  899. bstrHelpSession,
  900. 0,
  901. NULL,
  902. REG_OPTION_NON_VOLATILE,
  903. KEY_ALL_ACCESS,
  904. NULL,
  905. &hKey,
  906. &dwDeposition
  907. );
  908. if( ERROR_SUCCESS == dwStatus )
  909. {
  910. if( REG_OPENED_EXISTING_KEY == dwDeposition )
  911. {
  912. hRes = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS );
  913. }
  914. else
  915. {
  916. //
  917. // Mark entry status to be deleted so if we abnormally
  918. // terminated, this entry will be deleted on startup
  919. //
  920. dwEntryStatus = REGVALUE_HELPSESSION_ENTRY_DELETED;
  921. dwStatus = RegSetValueEx(
  922. hKey,
  923. COLUMNNAME_KEYSTATUS,
  924. 0,
  925. REG_DWORD,
  926. (LPBYTE)&dwEntryStatus,
  927. sizeof(dwEntryStatus)
  928. );
  929. if( ERROR_SUCCESS == dwStatus )
  930. {
  931. PHELPENTRY pSess;
  932. // Create a in-memory entry
  933. pSess = new HELPENTRY( *this, NULL, m_dwEntryValidPeriod );
  934. if( NULL != pSess )
  935. {
  936. pSess->m_SessionId = bstrHelpSession;
  937. *ppHelpEntry = pSess;
  938. //
  939. // In memory help entry should also be counted
  940. // since we still write out help session ID to
  941. // registry which on delete, will do m_NumHelp--.
  942. //
  943. m_NumHelp++;
  944. }
  945. else
  946. {
  947. hRes = E_OUTOFMEMORY;
  948. }
  949. }
  950. }
  951. RegCloseKey(hKey);
  952. }
  953. if(ERROR_SUCCESS != dwStatus )
  954. {
  955. hRes = HRESULT_FROM_WIN32( dwStatus );
  956. }
  957. }
  958. else
  959. {
  960. hRes = E_UNEXPECTED;
  961. }
  962. return hRes;
  963. }
  964. HRESULT
  965. CHelpSessionTable::OpenHelpEntry(
  966. IN const CComBSTR& bstrHelpSession,
  967. OUT PHELPENTRY* ppHelpEntry
  968. )
  969. /*++
  970. Routine Description:
  971. Open an existing help entry.
  972. Parameters:
  973. bstrHelpSession : ID of help entry to be opened.
  974. ppHelpEntry : Pointer to PHELPENTY to receive loaded
  975. help entry.
  976. Returns:
  977. S_OK or error code.
  978. --*/
  979. {
  980. CCriticalSectionLocker l(m_TableLock);
  981. HRESULT hRes = S_OK;
  982. DebugPrintf(
  983. _TEXT("OpenHelpEntry() %s\n"),
  984. bstrHelpSession
  985. );
  986. MYASSERT( bstrHelpSession.Length() > 0 );
  987. // check if entry already exists in cache
  988. HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSession );
  989. if( it != m_HelpEntryCache.end() )
  990. {
  991. *ppHelpEntry = (*it).second;
  992. //
  993. // More reference to same object.
  994. //
  995. (*ppHelpEntry)->AddRef();
  996. // timing, it is possible to have many-to-one mapping,
  997. // helpmgr delete from its internal cache but has not
  998. // release the help entry.
  999. }
  1000. else
  1001. {
  1002. hRes = LoadHelpEntry(
  1003. m_hHelpSessionTableKey,
  1004. (LPTSTR)bstrHelpSession,
  1005. ppHelpEntry
  1006. );
  1007. DebugPrintf(
  1008. _TEXT("LoadHelpEntry() on %s returns 0x%08x\n"),
  1009. bstrHelpSession,
  1010. hRes
  1011. );
  1012. if( SUCCEEDED(hRes) )
  1013. {
  1014. try {
  1015. m_HelpEntryCache[ bstrHelpSession ] = *ppHelpEntry;
  1016. }
  1017. catch( CMAPException e ) {
  1018. hRes = HRESULT_FROM_WIN32( e.m_ErrorCode );
  1019. }
  1020. catch( ... ) {
  1021. hRes = E_UNEXPECTED;
  1022. throw;
  1023. }
  1024. }
  1025. }
  1026. return hRes;
  1027. }
  1028. HRESULT
  1029. CHelpSessionTable::DeleteHelpEntry(
  1030. IN const CComBSTR& bstrHelpSession
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. Delete a help entry.
  1035. Parameters:
  1036. bstrHelpSession : ID of help session entry to be deleted.
  1037. Returns:
  1038. S_OK or error code.
  1039. --*/
  1040. {
  1041. HRESULT hRes = S_OK;
  1042. CCriticalSectionLocker l(m_TableLock);
  1043. DebugPrintf(
  1044. _TEXT("DeleteHelpEntry() %s\n"),
  1045. bstrHelpSession
  1046. );
  1047. // check if entry already exists in cache
  1048. HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSession );
  1049. if( it != m_HelpEntryCache.end() )
  1050. {
  1051. // mark entry deleted in registry
  1052. hRes = ((*it).second)->DeleteEntry();
  1053. MYASSERT( SUCCEEDED(hRes) );
  1054. // release this entry ref. count.
  1055. ((*it).second)->Release();
  1056. // remove from our cache
  1057. m_HelpEntryCache.erase( it );
  1058. }
  1059. else
  1060. {
  1061. //
  1062. // unsolicited help will not be in our cache.
  1063. //
  1064. hRes = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1065. }
  1066. {
  1067. DWORD dwStatus;
  1068. dwStatus = RegDelKey( m_hHelpSessionTableKey, bstrHelpSession );
  1069. if( ERROR_SUCCESS == dwStatus )
  1070. {
  1071. m_NumHelp--;
  1072. }
  1073. }
  1074. return hRes;
  1075. }
  1076. CHelpSessionTable::~CHelpSessionTable()
  1077. {
  1078. CloseSessionTable();
  1079. return;
  1080. }
  1081. HRESULT
  1082. CHelpSessionTable::EnumHelpEntry(
  1083. IN EnumHelpEntryCallback pFunc,
  1084. IN HANDLE userData
  1085. )
  1086. /*++
  1087. Routine Description:
  1088. Enumerate all help entries.
  1089. Parameters:
  1090. pFunc : Call back function.
  1091. userData : User defined data.
  1092. Returns:
  1093. S_OK or error code.
  1094. --*/
  1095. {
  1096. EnumHelpEntryParm parm;
  1097. HRESULT hRes = S_OK;
  1098. DWORD dwStatus;
  1099. CCriticalSectionLocker l(m_TableLock);
  1100. if( NULL == pFunc )
  1101. {
  1102. hRes = E_POINTER;
  1103. }
  1104. else
  1105. {
  1106. try {
  1107. parm.userData = userData;
  1108. parm.pCallback = pFunc;
  1109. parm.pTable = this;
  1110. dwStatus = RegEnumSubKeys(
  1111. HKEY_LOCAL_MACHINE,
  1112. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
  1113. EnumOpenHelpEntry,
  1114. (HANDLE) &parm
  1115. );
  1116. if( ERROR_SUCCESS != dwStatus )
  1117. {
  1118. hRes = HRESULT_FROM_WIN32( dwStatus );
  1119. }
  1120. }
  1121. catch(...) {
  1122. hRes = E_UNEXPECTED;
  1123. }
  1124. }
  1125. return hRes;
  1126. }
  1127. HRESULT
  1128. CHelpSessionTable::ReleaseHelpEntry(
  1129. IN CComBSTR& bstrHelpSessionId
  1130. )
  1131. /*++
  1132. Routine Description:
  1133. Release/unload a help entry from cached, this help
  1134. entry is not deleted.
  1135. Paramters:
  1136. bstrHelpSessionId : ID of help entry to be unloaded from memory.
  1137. Returns:
  1138. S_OK or error code
  1139. --*/
  1140. {
  1141. CCriticalSectionLocker l(m_TableLock);
  1142. HRESULT hRes = S_OK;
  1143. HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSessionId );
  1144. if( it != m_HelpEntryCache.end() )
  1145. {
  1146. (*it).second->Release();
  1147. m_HelpEntryCache.erase( it );
  1148. }
  1149. else
  1150. {
  1151. hRes = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  1152. }
  1153. return hRes;
  1154. }
  1155. HRESULT
  1156. CHelpSessionTable::EnumOpenHelpEntry(
  1157. IN HKEY hKey,
  1158. IN LPTSTR pszKeyName,
  1159. IN HANDLE userData
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. Call back funtion for EnumHelpEntry() and RegEnumSubKeys().
  1164. Parameters:
  1165. hKey : Registry key handle to help session table.
  1166. pszKeyName : help entry id (registry sub-key name).
  1167. userData : User defined data.
  1168. Returns:
  1169. S_OK or error code.
  1170. --*/
  1171. {
  1172. HRESULT hRes = S_OK;
  1173. PEnumHelpEntryParm pParm = (PEnumHelpEntryParm)userData;
  1174. if( NULL == pParm )
  1175. {
  1176. hRes = E_UNEXPECTED;
  1177. }
  1178. else
  1179. {
  1180. hRes = pParm->pCallback( CComBSTR(pszKeyName), pParm->userData );
  1181. }
  1182. return hRes;
  1183. }
  1184. HRESULT
  1185. CHelpSessionTable::CreatePendingHelpTable()
  1186. /*++
  1187. Routine to create pending help table registry key, if registry key already exist,
  1188. set the DACL to system context only.
  1189. --*/
  1190. {
  1191. PACL pAcl=NULL;
  1192. DWORD dwStatus = ERROR_SUCCESS;
  1193. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1194. DWORD cbAcl = 0;
  1195. PSID pSidSystem = NULL;
  1196. HKEY hKey = NULL;
  1197. pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, sizeof(SECURITY_DESCRIPTOR));
  1198. if( NULL == pSecurityDescriptor )
  1199. {
  1200. dwStatus = GetLastError();
  1201. goto CLEANUPANDEXIT;
  1202. }
  1203. //
  1204. // Initialize the security descriptor.
  1205. //
  1206. if (!InitializeSecurityDescriptor(
  1207. pSecurityDescriptor,
  1208. SECURITY_DESCRIPTOR_REVISION
  1209. ))
  1210. {
  1211. dwStatus = GetLastError();
  1212. goto CLEANUPANDEXIT;
  1213. }
  1214. dwStatus = CreateSystemSid( &pSidSystem );
  1215. if( ERROR_SUCCESS != dwStatus )
  1216. {
  1217. goto CLEANUPANDEXIT;
  1218. }
  1219. cbAcl = GetLengthSid( pSidSystem ) + sizeof(ACL) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
  1220. pAcl = (PACL) LocalAlloc( LPTR, cbAcl );
  1221. if( NULL == pAcl )
  1222. {
  1223. dwStatus = GetLastError();
  1224. goto CLEANUPANDEXIT;
  1225. }
  1226. //
  1227. // Initialize the ACL.
  1228. //
  1229. if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION))
  1230. {
  1231. dwStatus = GetLastError();
  1232. goto CLEANUPANDEXIT;
  1233. }
  1234. //
  1235. if (!AddAccessAllowedAce(pAcl,
  1236. ACL_REVISION,
  1237. GENERIC_READ | GENERIC_WRITE | GENERIC_ALL,
  1238. pSidSystem
  1239. ))
  1240. {
  1241. dwStatus = GetLastError();
  1242. goto CLEANUPANDEXIT;
  1243. }
  1244. if (!SetSecurityDescriptorDacl(pSecurityDescriptor,
  1245. TRUE, pAcl, FALSE))
  1246. {
  1247. dwStatus = GetLastError();
  1248. goto CLEANUPANDEXIT;
  1249. }
  1250. //
  1251. // Create/open the pending table registry key
  1252. //
  1253. dwStatus = RegCreateKeyEx(
  1254. HKEY_LOCAL_MACHINE,
  1255. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
  1256. 0,
  1257. NULL,
  1258. REG_OPTION_NON_VOLATILE,
  1259. KEY_ALL_ACCESS,
  1260. NULL,
  1261. &hKey,
  1262. NULL
  1263. );
  1264. if( ERROR_SUCCESS != dwStatus )
  1265. {
  1266. goto CLEANUPANDEXIT;
  1267. }
  1268. //
  1269. // Set table (registry) DACL
  1270. //
  1271. dwStatus = RegSetKeySecurity(
  1272. hKey,
  1273. DACL_SECURITY_INFORMATION,
  1274. pSecurityDescriptor
  1275. );
  1276. CLEANUPANDEXIT:
  1277. if( NULL != hKey )
  1278. {
  1279. RegCloseKey(hKey);
  1280. }
  1281. if( pAcl != NULL )
  1282. {
  1283. LocalFree(pAcl);
  1284. }
  1285. if( pSecurityDescriptor != NULL )
  1286. {
  1287. LocalFree( pSecurityDescriptor );
  1288. }
  1289. if( pSidSystem != NULL )
  1290. {
  1291. FreeSid( pSidSystem );
  1292. }
  1293. return HRESULT_FROM_WIN32(dwStatus);
  1294. }