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.

788 lines
25 KiB

  1. //
  2. // rmigrate.cpp
  3. //
  4. // Implementation of CTscRegMigrate
  5. //
  6. // CTscRegMigrate migrates Tsc settings from the registry
  7. // to .RDP files
  8. //
  9. // Copyright(C) Microsoft Corporation 2000
  10. // Author: Nadim Abdo (nadima)
  11. //
  12. //
  13. #include "stdafx.h"
  14. #define TRC_GROUP TRC_GROUP_UI
  15. #define TRC_FILE "rmigrate.cpp"
  16. #include <atrcapi.h>
  17. #include "rmigrate.h"
  18. #include "autreg.h"
  19. #include "rdpfstore.h"
  20. #include "sh.h"
  21. #ifdef OS_WINCE
  22. #include <ceconfig.h>
  23. #endif
  24. #define TSC_SETTINGS_REG_ROOT TEXT("Software\\Microsoft\\Terminal Server Client\\")
  25. #ifdef OS_WINCE
  26. #define WBT_SETTINGS TEXT("WBT\\Settings")
  27. #endif
  28. CTscRegMigrate::CTscRegMigrate()
  29. {
  30. }
  31. CTscRegMigrate::~CTscRegMigrate()
  32. {
  33. }
  34. //
  35. // Migrates all tsc settings to files in szRootDirectory
  36. //
  37. BOOL CTscRegMigrate::MigrateAll(LPTSTR szRootDirectory)
  38. {
  39. DC_BEGIN_FN("MigrateAll");
  40. TRC_ASSERT(szRootDirectory,
  41. (TB,_T("szRootDirectory is NULL")));
  42. TCHAR szFileName[MAX_PATH*2];
  43. TCHAR szKeyName[MAX_PATH+1];
  44. BOOL fCreatedRootDir = FALSE;
  45. if(szRootDirectory)
  46. {
  47. //
  48. // Enumerate and migrate all the TS sessions under HKCU
  49. //
  50. HKEY hRootKey;
  51. LONG rc = RegOpenKeyEx(HKEY_CURRENT_USER,
  52. TSC_SETTINGS_REG_ROOT,
  53. 0,
  54. KEY_READ,
  55. &hRootKey);
  56. if(ERROR_SUCCESS == rc && hRootKey)
  57. {
  58. DWORD dwIndex = 0;
  59. for(;;)
  60. {
  61. DWORD cName = sizeof(szKeyName)/sizeof(TCHAR) - 1;
  62. FILETIME ft;
  63. rc = RegEnumKeyEx(hRootKey,
  64. dwIndex,
  65. szKeyName,
  66. &cName,
  67. NULL,
  68. NULL,
  69. NULL,
  70. &ft);
  71. if(ERROR_SUCCESS == rc)
  72. {
  73. //
  74. // Ughh..hackalicious, don't migrate
  75. // the Trace subkey. or the 'Default'
  76. // or LocalDevices
  77. // subkey as default connectoids
  78. // always use new settings
  79. //
  80. if(_tcscmp(szKeyName, TEXT("Trace")) &&
  81. _tcscmp(szKeyName, SH_DEFAULT_REG_SESSION) &&
  82. _tcsicmp(szKeyName, REG_SECURITY_FILTER_SECTION))
  83. {
  84. _tcscpy(szFileName, szRootDirectory);
  85. _tcscat(szFileName, szKeyName);
  86. _tcscat(szFileName, RDP_FILE_EXTENSION);
  87. if (!fCreatedRootDir)
  88. {
  89. //
  90. // Only create RD dir if there are keys to migrate
  91. //
  92. if(CSH::SH_CreateDirectory(szRootDirectory))
  93. {
  94. fCreatedRootDir = TRUE;
  95. }
  96. else
  97. {
  98. TRC_ERR((TB, _T("Error creating directory %s"),szRootDirectory));
  99. RegCloseKey(hRootKey);
  100. return FALSE;
  101. }
  102. }
  103. //Carry on migrating whether this migrate
  104. //fails or not
  105. CRdpFileStore rdpf;
  106. if(rdpf.OpenStore( szFileName ) )
  107. {
  108. if(!MigrateSession(szKeyName,
  109. &rdpf,
  110. TRUE))
  111. {
  112. TRC_ERR((TB,
  113. _T("Migrate failed session %s - file %s"),
  114. szKeyName, szFileName));
  115. }
  116. if(rdpf.CommitStore())
  117. {
  118. rdpf.CloseStore();
  119. }
  120. }
  121. }
  122. //next
  123. dwIndex++;
  124. }
  125. else
  126. {
  127. //done enum
  128. break;
  129. }
  130. }
  131. rc = RegCloseKey(hRootKey);
  132. if(ERROR_SUCCESS == rc)
  133. {
  134. return TRUE;
  135. }
  136. else
  137. {
  138. TRC_ERR((TB,_T("RegCloseKey failed - err:%d"),
  139. GetLastError()));
  140. }
  141. }
  142. else
  143. {
  144. TRC_ERR((TB,_T("Error opening tsc reg key")));
  145. return FALSE;
  146. }
  147. }
  148. DC_END_FN();
  149. return FALSE;
  150. }
  151. //
  152. // Migrates settings in registry to a settings store
  153. // params:
  154. // szSessionName - session to migrate
  155. // pSetStore - settings store to dump the new settings in
  156. // fDeleteUnsafeRegKeys - set to TRUE to delete old regkeys after migration
  157. //
  158. BOOL CTscRegMigrate::MigrateSession(LPTSTR szSessionName, ISettingsStore* pStore,
  159. BOOL fDeleteUnsafeRegKeys)
  160. {
  161. DC_BEGIN_FN("MigrateSession");
  162. TCHAR szRegSection[MAX_PATH];
  163. //
  164. // Sessions are migrated by pulling all the registry settings
  165. // for a session and flattening them into a settings store
  166. //
  167. // In the registry case we used to look for settings under HKCU
  168. // first, if they were not there we'd try HKLM.
  169. //
  170. // The migrate code enumerates all values in the registry under
  171. // a named session, first for HKLM then for HKCU. By writing the HKCU
  172. // settings last, they overwrite any exising HKLM settings, giving
  173. // the correct precedence.
  174. //
  175. // Certain subfolders such as HOTKEYS subfolders and ADDINS are not migrated
  176. // as those values always come from the registry.
  177. //
  178. TRC_ASSERT(szSessionName && pStore,
  179. (TB,_T("Invalid params to MigrateSession")));
  180. TRC_ASSERT(pStore->IsOpenForWrite(),
  181. (TB,_T("Settings store not open for write")));
  182. if(pStore && pStore->IsOpenForWrite() && szSessionName)
  183. {
  184. if(!_tcsicmp(szSessionName,SH_DEFAULT_REG_SESSION))
  185. {
  186. TRC_ALT((TB,_T("Never migrate 'Default' session")));
  187. return FALSE;
  188. }
  189. _tcscpy(szRegSection, TSC_SETTINGS_REG_ROOT);
  190. _tcsncat(szRegSection, szSessionName, SIZECHAR(szRegSection) -
  191. SIZECHAR(TSC_SETTINGS_REG_ROOT));
  192. //
  193. // Doesn't matter if HKLM migrate fails
  194. // In face it is pretty common because it is usually
  195. // not even present
  196. //
  197. MigrateHiveSettings(HKEY_LOCAL_MACHINE,
  198. szRegSection,
  199. pStore);
  200. if(MigrateHiveSettings(HKEY_CURRENT_USER,
  201. szRegSection,
  202. pStore))
  203. {
  204. #ifdef OS_WINCE
  205. // For a WBT configuration, read some additional registry entries
  206. // which are common for all the sessions.
  207. if (g_CEConfig == CE_CONFIG_WBT)
  208. {
  209. _tcscpy(szRegSection, TSC_SETTINGS_REG_ROOT);
  210. _tcsncat(szRegSection, WBT_SETTINGS, SIZECHAR(szRegSection) -
  211. SIZECHAR(TSC_SETTINGS_REG_ROOT));
  212. //
  213. // Doesn't matter if HKLM migrate fails
  214. // In face it is pretty common because it is usually
  215. // not even present
  216. ///
  217. if (!MigrateHiveSettings(HKEY_LOCAL_MACHINE,
  218. szRegSection,
  219. pStore))
  220. {
  221. TRC_ERR((TB,_T("Unable to read the common settings for WBT")));
  222. }
  223. }
  224. #endif
  225. #ifndef OS_WINCE
  226. if (!ConvertPasswordFormat( pStore ))
  227. {
  228. TRC_ERR((TB,_T("ConvertPasswordFormat failed")));
  229. return FALSE;
  230. }
  231. #endif
  232. //
  233. // Flag controlled as we only want to do this when migrating all settings
  234. // not necessarily when auto-migrating single settings
  235. //
  236. if (fDeleteUnsafeRegKeys) {
  237. //
  238. // After all the migration, delete unsafe entries in the registry
  239. //
  240. RemoveUnsafeRegEntries(HKEY_LOCAL_MACHINE,
  241. szRegSection);
  242. RemoveUnsafeRegEntries(HKEY_CURRENT_USER,
  243. szRegSection);
  244. }
  245. return MungeForWin2kDefaults(pStore);
  246. }
  247. else
  248. {
  249. return FALSE;
  250. }
  251. }
  252. else
  253. {
  254. return FALSE;
  255. }
  256. DC_END_FN();
  257. }
  258. //
  259. // Migrate settings from hKey\szRootName to the settings store (pSto)
  260. // It would have been cool if this function could have been completely
  261. // generic, but it has to have specific knowledge of tsc registry layout
  262. // because of how mstsc5.0 bogusly special cased so many things. E.g
  263. // user name is stored as unicode in a binary blob.
  264. //
  265. BOOL CTscRegMigrate::MigrateHiveSettings(HKEY hKey,
  266. LPCTSTR szRootName,
  267. ISettingsStore* pSto)
  268. {
  269. DC_BEGIN_FN("MigrateHiveSettings");
  270. USES_CONVERSION;
  271. HKEY rootKey;
  272. LONG rc;
  273. BOOL fRet = FALSE;
  274. rc = RegOpenKeyEx( hKey,
  275. szRootName,
  276. 0,
  277. KEY_READ | KEY_QUERY_VALUE,
  278. &rootKey);
  279. if(ERROR_SUCCESS == rc)
  280. {
  281. //
  282. // Enumerate all the values under this key
  283. //
  284. DWORD dwIndex = 0;
  285. for(;;)
  286. {
  287. TCHAR szValueName[MAX_PATH];
  288. DWORD dwValueLen = MAX_PATH;
  289. DWORD dwType;
  290. BYTE buf[MAX_PATH];
  291. DWORD dwBufLen = MAX_PATH;
  292. //
  293. // It is important to zero the buf
  294. // because we read some REG_BINARY's that
  295. // are really 0 encoded unicode strings
  296. // but tsc4 and 5 had no trailing 0's.
  297. //
  298. memset(buf, 0, sizeof(buf));
  299. rc =RegEnumValue( rootKey,
  300. dwIndex,
  301. szValueName,
  302. &dwValueLen,
  303. NULL, //reserved
  304. &dwType,
  305. (PBYTE)&buf, //data buffer
  306. &dwBufLen);
  307. if(ERROR_SUCCESS == rc)
  308. {
  309. switch(dwType)
  310. {
  311. case REG_DWORD:
  312. {
  313. // Store as int
  314. UINT value = (UINT)(*((LPDWORD)buf));
  315. fRet = pSto->WriteInt(szValueName,
  316. -1, //default ignored
  317. value,
  318. TRUE); //always write
  319. if(!fRet)
  320. {
  321. DC_QUIT;
  322. }
  323. }
  324. break;
  325. case REG_SZ:
  326. {
  327. if(FilterStringMigrate(szValueName))
  328. {
  329. fRet = pSto->WriteString(szValueName,
  330. NULL, //no default
  331. (LPTSTR)buf,
  332. TRUE); //always write
  333. if(!fRet)
  334. {
  335. DC_QUIT;
  336. }
  337. }
  338. }
  339. break;
  340. case REG_BINARY:
  341. {
  342. //
  343. // This is where things get yucky
  344. // some settings e.g UserName are stored
  345. // as 'binary' when they are really unicode strings
  346. // No choice but to look those up.
  347. //
  348. fRet = FALSE;
  349. if(MigrateAsRealBinary(szValueName))
  350. {
  351. fRet = pSto->WriteBinary(szValueName,
  352. (PBYTE)buf,
  353. dwBufLen);
  354. }
  355. else
  356. {
  357. //
  358. // The binary blob is really a unicode string
  359. //
  360. LPTSTR szString = W2T((LPWSTR)buf);
  361. if( szString)
  362. {
  363. //
  364. // If things weren't yucky enough...
  365. // strip out the " 50" suffix if it is
  366. // present
  367. //
  368. LPTSTR szSuffix = _tcsstr(szValueName,
  369. TEXT(" 50"));
  370. if(szSuffix)
  371. {
  372. *szSuffix = 0;
  373. }
  374. fRet = pSto->WriteString(szValueName,
  375. NULL, //no default
  376. szString,
  377. TRUE); //always write
  378. }
  379. }
  380. if(!fRet)
  381. {
  382. DC_QUIT;
  383. }
  384. }
  385. break;
  386. }
  387. //Keep enumerating
  388. dwIndex++;
  389. }
  390. else if(ERROR_NO_MORE_ITEMS == rc)
  391. {
  392. fRet = TRUE;
  393. break;
  394. }
  395. else
  396. {
  397. TRC_ERR((TB,_T("RegEnumValue failed - err:%d"),
  398. GetLastError()));
  399. fRet = FALSE;
  400. break;
  401. }
  402. } //for(;;)
  403. }
  404. else
  405. {
  406. TRC_ERR((TB,_T("Failed to open reg key - err:%d"),
  407. GetLastError()));
  408. return FALSE;
  409. }
  410. DC_EXIT_POINT:
  411. if(ERROR_SUCCESS != RegCloseKey(rootKey))
  412. {
  413. TRC_ERR((TB,_T("RegCloseKey failed - err:%d"),
  414. GetLastError()));
  415. }
  416. DC_END_FN();
  417. return fRet;
  418. }
  419. //
  420. // Return true if the name (szName) should be migrated as
  421. // a real binary blob.
  422. //
  423. BOOL CTscRegMigrate::MigrateAsRealBinary(LPCTSTR szName)
  424. {
  425. DC_BEGIN_FN("MigrateAsRealBinary");
  426. //
  427. // In Tsc4 and Tsc5, only the password/salt fields
  428. // were real binary blobs, all other REG_BINARY blobs
  429. // are really just unicode strings.
  430. //
  431. if(!_tcscmp(szName, UTREG_UI_PASSWORD50))
  432. {
  433. return TRUE;
  434. }
  435. else if(!_tcscmp(szName, UTREG_UI_PASSWORD))
  436. {
  437. return TRUE;
  438. }
  439. else if(!_tcscmp(szName, UTREG_UI_SALT50))
  440. {
  441. return TRUE;
  442. }
  443. #ifdef OS_WINCE
  444. else if (!_tcscmp(szName, UI_SETTING_PASSWORD51))
  445. {
  446. return TRUE;
  447. }
  448. #endif
  449. else
  450. {
  451. //
  452. // Don't migrate as binary
  453. //
  454. return FALSE;
  455. }
  456. DC_END_FN();
  457. }
  458. //
  459. // Return true if it is ok to migrate the value
  460. // in name
  461. //
  462. BOOL CTscRegMigrate::FilterStringMigrate(LPTSTR szName)
  463. {
  464. if(szName)
  465. {
  466. if(_tcsstr(szName, TEXT("MRU")))
  467. {
  468. if(!_tcscmp(szName, UTREG_UI_SERVER_MRU0))
  469. {
  470. //Translate MRU0 to fulladdress
  471. _tcscpy(szName, UTREG_UI_FULL_ADDRESS);
  472. return TRUE;
  473. }
  474. //Don't migrate any other MRU strings.
  475. //those stay in the registry
  476. return FALSE;
  477. }
  478. else
  479. {
  480. //everything else is OK
  481. return TRUE;
  482. }
  483. }
  484. else
  485. {
  486. return FALSE;
  487. }
  488. }
  489. //
  490. // Munges the settings in the settings store to be consisten
  491. // with win2k's defaults. Win2k's default values were usually
  492. // deleted on write, this means we would instead use whistler
  493. // defaults but we don't want that. Instead the behavior we
  494. // want is that a migrated connectoid has _exactly_ the same
  495. // settings it used to have for those options that had UI in win2k.
  496. //
  497. // Params -
  498. // pSto - settings store to munge for defaults
  499. // Returns -
  500. // Success flag
  501. //
  502. //
  503. #define TSC_WIN2K_DEFAULT_DESKTOPSIZE 0 //640x480
  504. #define TSC_WIN2K_DEFAULT_FULLSCREENMODE 1 //windowed
  505. #define TSC_WIN2K_DEFAULT_BITMAPCACHE 0 //off
  506. #define TSC_WIN2K_DEFAULT_COMPRESSION 1 //on
  507. BOOL CTscRegMigrate::MungeForWin2kDefaults(ISettingsStore* pSto)
  508. {
  509. DC_BEGIN_FN("MungeForWin2kDefaults");
  510. TRC_ASSERT(pSto,
  511. (TB,_T("pSto is null")));
  512. TRC_ASSERT(pSto->IsOpenForRead() && pSto->IsOpenForWrite(),
  513. (TB,_T("pSto is null")));
  514. //
  515. // Munge settings that had conman UI
  516. // to ensure that we use the user's previous settings (Even
  517. // if they are win2k defaults i.e could be value not specified).
  518. //
  519. // Resolution
  520. if(!pSto->IsValuePresent(UTREG_UI_DESKTOP_SIZEID))
  521. {
  522. //Write out win2k's default desktop size
  523. if(!pSto->WriteInt(UTREG_UI_DESKTOP_SIZEID,
  524. -1, //default ignored
  525. TSC_WIN2K_DEFAULT_DESKTOPSIZE,
  526. TRUE)) //always write
  527. {
  528. TRC_ERR((TB,_T("WriteInt UTREG_UI_DESKTOP_SIZEID failed")));
  529. return FALSE;
  530. }
  531. }
  532. // Screen mode
  533. if(!pSto->IsValuePresent(UTREG_UI_SCREEN_MODE))
  534. {
  535. //Write out win2k's default screen mode
  536. if(!pSto->WriteInt(UTREG_UI_SCREEN_MODE,
  537. -1, //default ignored
  538. TSC_WIN2K_DEFAULT_FULLSCREENMODE,
  539. TRUE)) //always write
  540. {
  541. TRC_ERR((TB,_T("WriteInt UTREG_UI_SCREEN_MODE failed")));
  542. return FALSE;
  543. }
  544. }
  545. // Bitmap caching
  546. if(!pSto->IsValuePresent(UTREG_UI_BITMAP_PERSISTENCE))
  547. {
  548. //write out win2k's default bmp persistence option
  549. if(!pSto->WriteInt(UTREG_UI_BITMAP_PERSISTENCE,
  550. -1, //default ignored
  551. TSC_WIN2K_DEFAULT_BITMAPCACHE,
  552. TRUE))
  553. {
  554. TRC_ERR((TB,_T("WriteInt TSC_WIN2K_DEFAULT_BITMAPCACHE failed")));
  555. return FALSE;
  556. }
  557. }
  558. // Compression
  559. // Compression is special..We've made a decision that it should
  560. // always be on for perf reasons (and there are no drawbacks) so
  561. // change the win2k
  562. //
  563. if(!pSto->IsValuePresent(UTREG_UI_COMPRESS))
  564. {
  565. //write out win2k's default compression option
  566. if(!pSto->WriteInt(UTREG_UI_COMPRESS,
  567. -1, //default ignored
  568. TSC_WIN2K_DEFAULT_COMPRESSION,
  569. TRUE))
  570. {
  571. TRC_ERR((TB,_T("WriteInt TSC_WIN2K_DEFAULT_BITMAPCACHE failed")));
  572. return FALSE;
  573. }
  574. }
  575. DC_END_FN();
  576. return TRUE;
  577. }
  578. #ifndef OS_WINCE
  579. //
  580. // Convert the password format (if password present)
  581. // i.e if the old style TS5 passwords are present then decrypt
  582. // to plain text and then re-encrypt and save out using CryptoAPI's
  583. //
  584. // On Platforms that don't support Crypto-API we just nuke
  585. // the existing password format as we don't support migrating it
  586. // to the RDP files since it's not a secure format (just a hash).
  587. //
  588. // Start fields in pSto - 'Password 50' + 'Salt 50'
  589. // After conversion - (win2k+) 'Password 51' - binary crypto api password
  590. // After conversion - (less than win2k) = nothing
  591. //
  592. //
  593. BOOL CTscRegMigrate::ConvertPasswordFormat(ISettingsStore* pSto)
  594. {
  595. BOOL bRet = TRUE;
  596. DC_BEGIN_FN("ConvertPasswordFormat");
  597. //Nuke TS4 format
  598. pSto->DeleteValueIfPresent( UTREG_UI_PASSWORD );
  599. if ( CSH::IsCryptoAPIPresent() &&
  600. pSto->IsValuePresent( UTREG_UI_PASSWORD50 ) &&
  601. pSto->IsValuePresent( UTREG_UI_SALT50 ) )
  602. {
  603. BOOL fHavePass = FALSE;
  604. BYTE Password[TSC_MAX_PASSWORD_LENGTH_BYTES];
  605. BYTE Salt[TSC_SALT_LENGTH];
  606. memset( Password, 0, TSC_MAX_PASSWORD_LENGTH_BYTES);
  607. if (pSto->ReadBinary(UTREG_UI_PASSWORD50,
  608. (PBYTE)Password,
  609. sizeof(Password))) //size in bytes
  610. {
  611. fHavePass = TRUE;
  612. }
  613. else
  614. {
  615. TRC_NRM((TB,
  616. _T("ReadBinary for password failed. Maybe password not present")));
  617. }
  618. //
  619. // Salt
  620. //
  621. if (!pSto->ReadBinary(UTREG_UI_SALT50,
  622. (PBYTE)Salt,
  623. sizeof(Salt)))
  624. {
  625. fHavePass = FALSE;
  626. TRC_NRM((TB,_T("ReadBinary for salt failed.")));
  627. }
  628. if (fHavePass &&
  629. EncryptDecryptLocalData50( Password,
  630. TSC_WIN2K_PASSWORD_LENGTH_BYTES,
  631. Salt, sizeof(Salt)))
  632. {
  633. //Now we have the clear text pass in Password
  634. //encrypt it with the crypto API and save that back
  635. //out to the store
  636. DATA_BLOB din;
  637. DATA_BLOB dout;
  638. din.cbData = sizeof(Password);
  639. din.pbData = (PBYTE)&Password;
  640. dout.pbData = NULL;
  641. if (CSH::DataProtect( &din, &dout))
  642. {
  643. if (!pSto->WriteBinary(UI_SETTING_PASSWORD51,
  644. dout.pbData,
  645. dout.cbData))
  646. {
  647. bRet = FALSE;
  648. }
  649. LocalFree( dout.pbData );
  650. }
  651. else
  652. {
  653. bRet = FALSE;
  654. }
  655. // Wipe from stack
  656. SecureZeroMemory( Password, TSC_MAX_PASSWORD_LENGTH_BYTES);
  657. }
  658. }
  659. // No longer need the old format so delete them
  660. pSto->DeleteValueIfPresent( UTREG_UI_PASSWORD50 );
  661. pSto->DeleteValueIfPresent( UTREG_UI_SALT50 );
  662. DC_END_FN();
  663. return bRet;
  664. }
  665. #endif
  666. BOOL
  667. CTscRegMigrate::DeleteRegValue(HKEY hKeyRoot,
  668. LPCTSTR szRootName,
  669. LPCTSTR szValueName)
  670. {
  671. HKEY hKey;
  672. LONG rc;
  673. BOOL fRet = FALSE;
  674. DC_BEGIN_FN("DeleteRegValue");
  675. rc = RegOpenKeyEx( hKeyRoot,
  676. szRootName,
  677. 0,
  678. KEY_SET_VALUE, //needed for delete access
  679. &hKey);
  680. if(ERROR_SUCCESS == rc)
  681. {
  682. rc = RegDeleteValue(hKey, szValueName);
  683. if (ERROR_SUCCESS == rc) {
  684. fRet = TRUE;
  685. }
  686. RegCloseKey(hKey);
  687. }
  688. DC_END_FN();
  689. return fRet;
  690. }
  691. //
  692. // Remove entries we don't want to keep lying around in the registry
  693. // primarily these are passwords in the old 'insecure' obfuscated formats
  694. //
  695. BOOL
  696. CTscRegMigrate::RemoveUnsafeRegEntries(HKEY hKeyRoot,
  697. LPCTSTR szRootName)
  698. {
  699. BOOL fRet = FALSE;
  700. DC_BEGIN_FN("RemoveUnsafeRegEntries");
  701. if (!DeleteRegValue(hKeyRoot, szRootName, UTREG_UI_PASSWORD50)) {
  702. TRC_ALT((TB,_T("Failed to delete: %s\\%s"), szRootName,
  703. UTREG_UI_PASSWORD50));
  704. }
  705. if (!DeleteRegValue(hKeyRoot, szRootName, UTREG_UI_PASSWORD)) {
  706. TRC_ALT((TB,_T("Failed to delete: %s\\%s"), szRootName,
  707. UTREG_UI_PASSWORD));
  708. }
  709. if (!DeleteRegValue(hKeyRoot, szRootName, UTREG_UI_SALT50)) {
  710. TRC_ALT((TB,_T("Failed to delete: %s\\%s"), szRootName,
  711. UTREG_UI_SALT50));
  712. }
  713. fRet = TRUE;
  714. DC_END_FN();
  715. return fRet;
  716. }