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.

2742 lines
80 KiB

  1. /***************************************************************************
  2. *
  3. * MODULE: REGDIFF
  4. *
  5. * This module implements a charmode utility for snapshoting, diffing,
  6. * merging, and unmerging the registry.
  7. *
  8. * If your wondering why this isn't simpler than it is, its because the
  9. * registry is not consistant across all nodes thus special hacks were
  10. * done to make it work. I have endeavored to keep it clean though and
  11. * there are many functions out of here you can just grab and use for
  12. * the most part.
  13. *
  14. * Happy diffing.
  15. *
  16. * Created 8/20/93 sanfords
  17. ***************************************************************************/
  18. #define UNICODE
  19. #define _UNICODE
  20. #ifndef RC_INVOKED
  21. #include <nt.h>
  22. #include <ntrtl.h>
  23. #include <nturtl.h>
  24. #endif
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <tchar.h>
  29. #include <windows.h>
  30. /*
  31. * By using macros for all IO its easy to just cut it out.
  32. */
  33. #define DPRINTF(x) if (fDebug) { _tprintf(TEXT("DBG:")); _tprintf##x; }
  34. #define VPRINTF(x) if (fVerbose) _tprintf##x
  35. #define DVPRINTF(x) if (fVerbose | fDebug) _tprintf##x
  36. #define EPRINTF(x) _tprintf(TEXT("ERR:")); _tprintf##x; if (fBreak) DebugBreak()
  37. #define WPRINTF(x) _tprintf(TEXT("WARNING:-----\n")); _tprintf##x
  38. #define MEMFAILED EPRINTF((pszMemFailed));
  39. /*
  40. * Constants for the LogRegAccess() worker function.
  41. */
  42. #define LRA_OPEN 0
  43. #define LRA_CREATE 1
  44. /*
  45. * Structure used to associate any open key with its parent key and
  46. * subkey name allowing us to optain the full key name of any open
  47. * key at any time. Useful for decent output w/o high overhead.
  48. */
  49. typedef struct tagKEYLOG {
  50. struct tagKEYLOG *next;
  51. HKEY hKey;
  52. HKEY hKeyParent;
  53. LPTSTR psz;
  54. } KEYLOG, *PKEYLOG;
  55. /*
  56. * Linked list of all open key logs.
  57. */
  58. PKEYLOG pKeyLogList = NULL;
  59. /*
  60. * Flags - mostly set by command line parameters.
  61. */
  62. BOOL fEraseInputFileWhenDone = FALSE;
  63. BOOL fInclusionListSpecified = FALSE;
  64. BOOL fExclusionListSpecified = FALSE;
  65. BOOL fSnap = FALSE;
  66. BOOL fDiff = FALSE;
  67. BOOL fMerge = FALSE;
  68. BOOL fUnmerge = FALSE;
  69. BOOL fRemoveDiffInfo = FALSE;
  70. BOOL fWriteDiffInfo = FALSE;
  71. BOOL fLoadDiffInfo = FALSE;
  72. BOOL fVerbose = FALSE;
  73. BOOL fDebug = FALSE;
  74. BOOL fBreak = FALSE;
  75. BOOL fSafe = FALSE;
  76. LPSTR pszSnapFileIn = NULL;
  77. LPSTR pszSnapFileOut = NULL;
  78. LPSTR pszDiffFileIn = NULL;
  79. LPSTR pszDiffFileOut = NULL;
  80. LPSTR pszTempFile = "regdiff1";
  81. LPSTR pszTempFileLog = "regdiff1.log";
  82. LPSTR pszTempFile2 = "regdiff2";
  83. LPSTR pszTempFile2Log = "regdiff2.log";
  84. LPSTR pszDummyFile = "_regdiff";
  85. LPSTR pszDummyFileLog = "_regdiff.log";
  86. LPTSTR pszMemFailed = TEXT("Memory Failure.\n");
  87. LPTSTR pszTemp1 = NULL;
  88. LPTSTR pszTemp2 = NULL;
  89. LPTSTR pszTemp3 = NULL;
  90. LPTSTR pszCurUserSID = NULL;
  91. LPTSTR pszHKEY_LOCAL_MACHINE = TEXT("HKEY_LOCAL_MACHINE");
  92. LPTSTR pszHKEY_USERS = TEXT("HKEY_USERS");
  93. LPTSTR pszHKEY_CURRENT_USER = TEXT("HKEY_CURRENT_USER");
  94. LPTSTR pszHKEY_CURRENT_USER_Real = NULL; // made from user's SID
  95. LPTSTR pszHKEY_CLASSES_ROOT = TEXT("HKEY_CLASSES_ROOT");
  96. LPTSTR pszHKEY_CLASSES_ROOT_Real = TEXT("HKEY_LOCAL_MACHINE\\SOFTWARE\\Classes");
  97. LPTSTR pszRealClassesRoot = TEXT("SOFTWARE\\Classes");
  98. LPTSTR pszDiffRoot = TEXT("regdiff");
  99. LPTSTR pszAddKey = TEXT("Add");
  100. LPTSTR pszDelKey = TEXT("Del");
  101. LPTSTR pszSnapshotSubkeyName = TEXT("Regdiff_SnapshotKey");
  102. /*
  103. * default Exception list
  104. */
  105. LPTSTR apszExceptKeys[] = {
  106. TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\Clone"),
  107. TEXT("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\CacheLastUpdate"),
  108. TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet"),
  109. TEXT("HKEY_LOCAL_MACHINE\\SYSTEM\\ControlSet???"),
  110. };
  111. DWORD cExceptKeys = sizeof(apszExceptKeys)/sizeof(LPTSTR);
  112. LPTSTR *ppszExceptKeys = apszExceptKeys; // pointer to current exception list.
  113. /*
  114. * default Inclusion list
  115. */
  116. LPTSTR apszIncludeKeys[] = {
  117. TEXT("HKEY_LOCAL_MACHINE\\SYSTEM"),
  118. TEXT("HKEY_LOCAL_MACHINE\\SOFTWARE"),
  119. TEXT("HKEY_CURRENT_USER"),
  120. };
  121. DWORD cIncludeKeys = sizeof(apszIncludeKeys)/sizeof(LPTSTR);
  122. LPTSTR *ppszIncludeKeys = apszIncludeKeys; // pointer to current inclusion list.
  123. /*
  124. * array of flags used to make sure that our loaded snapfile contained
  125. * at least all the keys in the inclusion list.
  126. */
  127. BOOL afIncludeKeyMarks[sizeof(apszIncludeKeys)/sizeof(LPTSTR)] = {
  128. FALSE,
  129. FALSE,
  130. FALSE,
  131. };
  132. BOOL *pfIncludeKeyMarks = afIncludeKeyMarks;
  133. /*
  134. * Necessary prototypes.
  135. */
  136. BOOL AddNodeInfo(HKEY hKeyInfo, HKEY hKeyTarget);
  137. VOID PrintUsage(VOID)
  138. {
  139. DWORD i;
  140. _tprintf(
  141. TEXT("regdiff usage:\n")
  142. TEXT("\n")
  143. TEXT("-s <snapfile>\n")
  144. TEXT(" save current registry contents to snapfile.\n")
  145. TEXT("-d <snapfile>\n")
  146. TEXT(" create diff info from current registry state and <snapfile>.\n")
  147. TEXT("-l <difffile>\n")
  148. TEXT(" load diff info into registry from <difffile>.\n")
  149. TEXT("-w <difffile>\n")
  150. TEXT(" write diff info to <difffile> from registry when done.\n")
  151. TEXT("-e erase input file(s) after done.\n")
  152. TEXT("-m merge diff info into current registry.\n")
  153. TEXT("-u unmerge diff info from current registry.\n")
  154. TEXT("-r remove diff info from registry when done.\n")
  155. TEXT("-x <exceptionsfile>\n")
  156. TEXT(" use <exceptionsfile> to bypass diff, merge or unmerge on certain keys.\n")
  157. TEXT("-i <inclusionsfile>\n")
  158. TEXT(" use <inclusionsfile> to snap or diff only certain keys.\n")
  159. TEXT("-v verbose output on.\n")
  160. TEXT("-@ Debug mode.\n")
  161. TEXT("-b break on errors.\n")
  162. TEXT("-n neuter - don't really do merges/unmerges. (for safe testing)\n")
  163. TEXT("\n")
  164. TEXT("<snapfile> and <difffile> should not have extensions on FAT partitions.\n")
  165. TEXT("diff info is kept in HKEY_LOCAL_MACHINE\\regdiff\n")
  166. );
  167. _tprintf(TEXT("\nThe default inclusions list is:\n"));
  168. for (i = 0; i < cIncludeKeys; i++) {
  169. _tprintf(TEXT(" %ws\n"), ppszIncludeKeys[i]);
  170. }
  171. _tprintf(TEXT("\nThe default exceptions list is:\n"));
  172. for (i = 0; i < cExceptKeys; i++) {
  173. _tprintf(TEXT(" %ws\n"), ppszExceptKeys[i]);
  174. }
  175. }
  176. /*
  177. * The following functions allow us to log all registry key openings and
  178. * closeings so we can know at any time the full path of any open key.
  179. *
  180. * This simplifies such things as exception and inclusion lookups.
  181. */
  182. LPTSTR LookupPathFromKey(
  183. HKEY hKey,
  184. PHKEY phKeyParent)
  185. {
  186. PKEYLOG pkl;
  187. *phKeyParent = NULL;
  188. if (hKey == HKEY_LOCAL_MACHINE) {
  189. return(pszHKEY_LOCAL_MACHINE);
  190. } else if (hKey == HKEY_USERS) {
  191. return(pszHKEY_USERS);
  192. } else if (hKey == HKEY_CURRENT_USER) {
  193. return(pszHKEY_CURRENT_USER_Real);
  194. } else if (hKey == HKEY_CLASSES_ROOT) {
  195. return(pszHKEY_CLASSES_ROOT_Real);
  196. } else {
  197. pkl = pKeyLogList;
  198. while (pkl != NULL) {
  199. if (pkl->hKey == hKey) {
  200. *phKeyParent = pkl->hKeyParent;
  201. return(pkl->psz);
  202. }
  203. pkl = pkl->next;
  204. }
  205. return(NULL);
  206. }
  207. }
  208. /*
  209. * This removes pseudo-key root names from paths and changes them to
  210. * real-root names.
  211. *
  212. * Return string must be freed by caller if pfFree is set.
  213. */
  214. LPTSTR NormalizePathName(
  215. LPTSTR pszPath,
  216. BOOL *pfFree)
  217. {
  218. LPTSTR pszOffender, pszFixed;
  219. if (pfFree != NULL) {
  220. *pfFree = FALSE;
  221. }
  222. pszOffender = _tcsstr(pszPath, pszHKEY_CURRENT_USER);
  223. if (pszOffender != NULL) {
  224. pszFixed = malloc((
  225. _tcslen(pszPath) +
  226. _tcslen(pszHKEY_CURRENT_USER_Real) -
  227. _tcslen(pszHKEY_CURRENT_USER) +
  228. 1) * sizeof(TCHAR));
  229. if (pszFixed == NULL) {
  230. MEMFAILED;
  231. return(NULL);
  232. }
  233. _tcscpy(pszFixed, pszHKEY_CURRENT_USER_Real);
  234. _tcscat(pszFixed, pszOffender + _tcslen(pszHKEY_CURRENT_USER));
  235. if (pfFree != NULL) {
  236. *pfFree = TRUE;
  237. }
  238. return(pszFixed);
  239. }
  240. pszOffender = _tcsstr(pszPath, pszHKEY_CLASSES_ROOT);
  241. if (pszOffender != NULL) {
  242. pszFixed = malloc((
  243. _tcslen(pszPath) +
  244. _tcslen(pszHKEY_CLASSES_ROOT_Real) -
  245. _tcslen(pszHKEY_CLASSES_ROOT) +
  246. 1) * sizeof(TCHAR));
  247. if (pszFixed == NULL) {
  248. MEMFAILED;
  249. return(NULL);
  250. }
  251. _tcscpy(pszFixed, pszHKEY_CLASSES_ROOT_Real);
  252. _tcscat(pszFixed, pszOffender + _tcslen(pszHKEY_CLASSES_ROOT));
  253. if (pfFree != NULL) {
  254. *pfFree = TRUE;
  255. }
  256. return(pszFixed);
  257. }
  258. return(pszPath); // already normalized
  259. }
  260. /*
  261. * return value must be freed by caller.
  262. *
  263. * NULL is returned on error.
  264. */
  265. LPTSTR GetFullPathFromKey(
  266. HKEY hKey,
  267. LPCTSTR pszSubkey)
  268. {
  269. LPTSTR pszPart, pszNewSubkey;
  270. HKEY hKeyParent;
  271. pszPart = LookupPathFromKey(hKey, &hKeyParent);
  272. if (pszPart != NULL) {
  273. pszNewSubkey = malloc((_tcslen(pszPart) + 1 +
  274. (pszSubkey == NULL ? 0 : (_tcslen(pszSubkey) + 1))) *
  275. sizeof(TCHAR));
  276. if (pszNewSubkey == NULL) {
  277. MEMFAILED;
  278. return(NULL);
  279. }
  280. _tcscpy(pszNewSubkey, pszPart);
  281. if (pszSubkey != NULL) {
  282. _tcscat(pszNewSubkey, TEXT("\\"));
  283. _tcscat(pszNewSubkey, pszSubkey);
  284. }
  285. if (hKeyParent != NULL) {
  286. pszPart = GetFullPathFromKey(hKeyParent, pszNewSubkey);
  287. free(pszNewSubkey);
  288. } else {
  289. pszPart = pszNewSubkey;
  290. }
  291. }
  292. return(pszPart);
  293. }
  294. /*
  295. * Same as GetFullPathFromKey but the pointer given is reused.
  296. */
  297. LPTSTR ReuseFullPathFromKey(
  298. HKEY hKey,
  299. LPCTSTR pszSubkey,
  300. LPTSTR *ppsz)
  301. {
  302. if (*ppsz != NULL) {
  303. free(*ppsz);
  304. }
  305. *ppsz = GetFullPathFromKey(hKey, pszSubkey);
  306. return(*ppsz);
  307. }
  308. LONG LogRegAccessKey(
  309. DWORD AccessType,
  310. HKEY hKey,
  311. LPCTSTR pszSubkeyName,
  312. HKEY *phSubkey)
  313. {
  314. PKEYLOG pkl;
  315. LONG status;
  316. DWORD dwDisp;
  317. DPRINTF((TEXT("LogRegAccessKey(%s, %s, %s)\n"),
  318. (AccessType == LRA_OPEN ? TEXT("Open") : TEXT("Create")),
  319. ReuseFullPathFromKey(hKey, NULL, &pszTemp1),
  320. pszSubkeyName));
  321. switch (AccessType) {
  322. case LRA_OPEN:
  323. status = RegOpenKeyEx(hKey, pszSubkeyName, 0, KEY_ALL_ACCESS, phSubkey);
  324. if (status != ERROR_SUCCESS) {
  325. DPRINTF((TEXT("Failed to open key %s with ALL_ACCESS.\n"),
  326. ReuseFullPathFromKey(hKey, pszSubkeyName, &pszTemp1)));
  327. /*
  328. * Loaded keys can't be written to - so try opening readonly.
  329. */
  330. status = RegOpenKeyEx(hKey, pszSubkeyName, 0, KEY_READ, phSubkey);
  331. }
  332. break;
  333. case LRA_CREATE:
  334. status = RegCreateKeyEx(hKey, pszSubkeyName, 0, TEXT(""),
  335. REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, phSubkey, \
  336. &dwDisp);
  337. if (status != ERROR_SUCCESS) {
  338. /*
  339. * Loaded keys can't be written to - so try opening readonly.
  340. */
  341. DPRINTF((TEXT("Failed to create key %s with ALL_ACCESS.\n"),
  342. ReuseFullPathFromKey(hKey, pszSubkeyName, &pszTemp1)));
  343. status = RegCreateKeyEx(hKey, pszSubkeyName, 0, TEXT(""),
  344. REG_OPTION_NON_VOLATILE, KEY_READ, NULL, phSubkey, \
  345. &dwDisp);
  346. }
  347. break;
  348. }
  349. if (status == ERROR_SUCCESS) {
  350. pkl = malloc(sizeof(KEYLOG));
  351. if (pkl != NULL) {
  352. pkl->psz = malloc((_tcslen(pszSubkeyName) + 1) * sizeof(TCHAR));
  353. if (pkl->psz != NULL) {
  354. pkl->next = pKeyLogList;
  355. pkl->hKey = *phSubkey;
  356. pkl->hKeyParent = hKey;
  357. _tcscpy(pkl->psz, pszSubkeyName);
  358. pKeyLogList = pkl;
  359. } else {
  360. status = ERROR_NOT_ENOUGH_MEMORY;
  361. free(pkl);
  362. }
  363. } else {
  364. status = ERROR_NOT_ENOUGH_MEMORY;
  365. }
  366. }
  367. return(status);
  368. }
  369. LONG LogRegOpenKey(
  370. HKEY hKey,
  371. LPCTSTR pszSubkeyName,
  372. HKEY *phSubkey)
  373. {
  374. return(LogRegAccessKey(LRA_OPEN, hKey, pszSubkeyName, phSubkey));
  375. }
  376. LONG LogRegCreateKey(
  377. HKEY hKey,
  378. LPCTSTR pszSubkeyName,
  379. HKEY *phSubkey)
  380. {
  381. return(LogRegAccessKey(LRA_CREATE, hKey, pszSubkeyName, phSubkey));
  382. }
  383. LONG LogRegCloseKey(
  384. HKEY hKey)
  385. {
  386. PKEYLOG pkl, pklPrev;
  387. DPRINTF((TEXT("LogRegCloseKey(%s)\n"),
  388. ReuseFullPathFromKey(hKey, NULL, &pszTemp1)));
  389. pkl = pKeyLogList;
  390. pklPrev = NULL;
  391. while (pkl != NULL) {
  392. if (hKey == pkl->hKey) {
  393. if (pklPrev != NULL) {
  394. pklPrev->next = pkl->next;
  395. } else {
  396. pKeyLogList = pkl->next;
  397. }
  398. free(pkl->psz);
  399. free(pkl);
  400. break;
  401. }
  402. pklPrev = pkl;
  403. pkl = pkl->next;
  404. }
  405. if (pkl == NULL) {
  406. EPRINTF((TEXT("Key %s being closed was not found in KeyLog.\n"),
  407. ReuseFullPathFromKey(hKey, NULL, &pszTemp1)));
  408. }
  409. return(RegCloseKey(hKey));
  410. }
  411. /*
  412. * Simpler privilege enabling mechanism.
  413. */
  414. BOOL EnablePrivilege(
  415. LPCTSTR lpszPrivilege)
  416. {
  417. TOKEN_PRIVILEGES tp;
  418. HANDLE hToken = NULL;
  419. if (!OpenProcessToken(GetCurrentProcess(),
  420. TOKEN_READ | TOKEN_WRITE, &hToken)) {
  421. EPRINTF((TEXT("Could not open process token.\n")));
  422. return(FALSE);
  423. }
  424. if (hToken == NULL) {
  425. EPRINTF((TEXT("Could not open process token.\n")));
  426. return(FALSE);
  427. }
  428. if (!LookupPrivilegeValue(NULL, lpszPrivilege, &tp.Privileges[0].Luid)) {
  429. EPRINTF((TEXT("Could not lookup privilege value %s.\n"), lpszPrivilege));
  430. return(FALSE);
  431. }
  432. tp.PrivilegeCount = 1;
  433. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  434. if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) {
  435. EPRINTF((TEXT("Could not adjust privilege %s.\n"), lpszPrivilege));
  436. return(FALSE);
  437. }
  438. return(TRUE);
  439. }
  440. /*
  441. * a little more sane version of the real API that can handle NULLs.
  442. */
  443. LONG MyRegQueryInfoKey(
  444. HKEY hKey,
  445. LPDWORD lpcSubkeys,
  446. LPDWORD lpcchMaxSubkey,
  447. LPDWORD lpcValues,
  448. LPDWORD lpcchMaxValueName,
  449. LPDWORD lpcbMaxValueData,
  450. LPFILETIME lpft)
  451. {
  452. DWORD cchClass, cSubkeys, cchMaxSubkey, cchMaxClass, cValues;
  453. DWORD cchMaxValueName, cbMaxValueData, cbSID;
  454. FILETIME LastWriteTime;
  455. TCHAR szClass[100];
  456. LONG status;
  457. cchClass = 100;
  458. status = RegQueryInfoKey(hKey,
  459. szClass,
  460. &cchClass,
  461. NULL,
  462. (lpcSubkeys == NULL) ? &cSubkeys : lpcSubkeys,
  463. (lpcchMaxSubkey == NULL) ? &cchMaxSubkey : lpcchMaxSubkey,
  464. &cchMaxClass,
  465. (lpcValues == NULL) ? &cValues : lpcValues,
  466. (lpcchMaxValueName == NULL) ? &cchMaxValueName : lpcchMaxValueName,
  467. (lpcbMaxValueData == NULL) ? &cbMaxValueData : lpcbMaxValueData,
  468. &cbSID,
  469. (lpft == NULL) ? &LastWriteTime : lpft);
  470. if (status == ERROR_MORE_DATA) {
  471. status = ERROR_SUCCESS;
  472. }
  473. return(status);
  474. }
  475. /*
  476. * Frees strings allocated with GetCurUserSidString().
  477. */
  478. VOID DeleteSidString(
  479. LPTSTR SidString)
  480. {
  481. #ifdef UNICODE
  482. UNICODE_STRING String;
  483. RtlInitUnicodeString(&String, SidString);
  484. RtlFreeUnicodeString(&String);
  485. #else
  486. ANSI_STRING String;
  487. RtlInitAnsiString(&String, SidString);
  488. RtlFreeAnsiString(&String);
  489. #endif
  490. }
  491. /*
  492. * Gets the current user's SID in text form.
  493. * The return string should be freed using DeleteSidString().
  494. */
  495. LPTSTR GetCurUserSidString(VOID)
  496. {
  497. HANDLE hToken;
  498. TOKEN_USER tu;
  499. DWORD cbRequired;
  500. PTOKEN_USER ptu = NULL, ptuUse;
  501. UNICODE_STRING UnicodeString;
  502. #ifndef UNICODE
  503. STRING String;
  504. #endif
  505. NTSTATUS NtStatus;
  506. if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken)) {
  507. EPRINTF((TEXT("Could not open process token.\n")));
  508. return(NULL);
  509. }
  510. if (hToken == NULL) {
  511. EPRINTF((TEXT("Could not open process token.\n")));
  512. return(NULL);
  513. }
  514. if (!GetTokenInformation(hToken, TokenUser, &tu, sizeof(tu), &cbRequired)) {
  515. if (cbRequired > sizeof(tu)) {
  516. ptu = malloc(cbRequired);
  517. if (ptu == NULL) {
  518. return(NULL);
  519. }
  520. if (!GetTokenInformation(hToken, TokenUser, ptu, cbRequired, &cbRequired)) {
  521. free(ptu);
  522. EPRINTF((TEXT("Could not get token information.\n")));
  523. return(NULL);
  524. }
  525. ptuUse = ptu;
  526. }
  527. } else {
  528. ptuUse = &tu;
  529. }
  530. NtStatus = RtlConvertSidToUnicodeString(&UnicodeString, ptuUse->User.Sid, TRUE);
  531. if (!NT_SUCCESS(NtStatus)) {
  532. EPRINTF((TEXT("Could not get current user SID string. NtError=%d\n"), NtStatus));
  533. return(NULL);
  534. }
  535. #ifdef UNICODE
  536. return(UnicodeString.Buffer);
  537. #else
  538. //
  539. // Convert the string to ansi
  540. //
  541. NtStatus = RtlUnicodeStringToAnsiString(&String, &UnicodeString, TRUE);
  542. RtlFreeUnicodeString(&UnicodeString);
  543. if (!NT_SUCCESS(NtStatus)) {
  544. EPRINTF((TEXT("Could not convert user SID string to ANSI. NtError=%d\n"), NtStatus));
  545. return(NULL);
  546. }
  547. return(String.Buffer);
  548. #endif
  549. }
  550. /*
  551. * This function stores/appends the contents of the hKey subkey specified to
  552. * hfOut. pszKeyName is for error output use.
  553. *
  554. * Returns fSuccess - TRUE if ALL info was successfully saved.
  555. */
  556. BOOL StoreSubKey(
  557. HKEY hKey,
  558. LPTSTR pszSubkeyName,
  559. FILE *hfOut)
  560. {
  561. DWORD status, cb;
  562. HKEY hSubkey;
  563. FILE *hfIn;
  564. VOID *pBuf;
  565. DVPRINTF((TEXT(" Snapping %s...\n"),
  566. ReuseFullPathFromKey(hKey, pszSubkeyName, &pszTemp1)));
  567. DeleteFileA(pszTempFile); // RegSaveKey() won't work if this exists.
  568. status = LogRegOpenKey(hKey, pszSubkeyName, &hSubkey);
  569. if (status != ERROR_SUCCESS) {
  570. EPRINTF((TEXT("Could not open key %s. Error=%d.\n"),
  571. ReuseFullPathFromKey(hKey, pszSubkeyName, &pszTemp1), status));
  572. return(FALSE);
  573. }
  574. /*
  575. * store key in temp file.
  576. */
  577. status = RegSaveKeyA(hSubkey, pszTempFile, NULL);
  578. if (status != ERROR_SUCCESS) {
  579. EPRINTF((TEXT("Could not save %s. Error=%d.\n"),
  580. ReuseFullPathFromKey(hKey, pszSubkeyName, &pszTemp1), status));
  581. Exit1:
  582. LogRegCloseKey(hSubkey);
  583. return(FALSE);
  584. }
  585. /*
  586. * open key data file
  587. */
  588. hfIn = fopen(pszTempFile, "rb+");
  589. if (hfIn == NULL) {
  590. EPRINTF((TEXT("File read error.\n")));
  591. goto Exit1;
  592. }
  593. /*
  594. * write sizeof Subkey name.
  595. */
  596. cb = (_tcslen(pszSubkeyName) + 1) * sizeof(TCHAR);
  597. if (fwrite(&cb, 1, sizeof(DWORD), hfOut) != sizeof(DWORD) || ferror(hfOut)) {
  598. EPRINTF((TEXT("Write failure. [sizeof(%s).]\n"), pszSubkeyName));
  599. Exit2:
  600. fclose(hfIn);
  601. DeleteFileA(pszTempFile);
  602. goto Exit1;
  603. }
  604. /*
  605. * write Subkey name.
  606. */
  607. if (fwrite(pszSubkeyName, 1, cb, hfOut) != cb || ferror(hfOut)) {
  608. EPRINTF((TEXT("Write failure. [%s]\n"), pszSubkeyName));
  609. goto Exit2;
  610. }
  611. /*
  612. * write root key handle (MUST BE AN HKEY_ CONSTANT!)
  613. */
  614. if (fwrite(&hKey, 1, sizeof(HKEY), hfOut) != sizeof(HKEY) || ferror(hfOut)) {
  615. EPRINTF((TEXT("Write failure. [Handle of %s.]\n"),
  616. ReuseFullPathFromKey(hKey, NULL, &pszTemp1)));
  617. goto Exit2;
  618. }
  619. /*
  620. * get key data file size
  621. */
  622. if (fseek(hfIn, 0, SEEK_END)) {
  623. EPRINTF((TEXT("Seek failure.\n")));
  624. goto Exit2;
  625. }
  626. cb = ftell(hfIn);
  627. /*
  628. * write sizeof key data
  629. */
  630. if (fwrite(&cb, 1, sizeof(DWORD), hfOut) != sizeof(DWORD) || ferror(hfOut)) {
  631. EPRINTF((TEXT("Write failure. [sizeof key data]\n")));
  632. goto Exit2;
  633. }
  634. /*
  635. * alocate key data buffer
  636. */
  637. pBuf = malloc(cb);
  638. if (pBuf == NULL) {
  639. EPRINTF((TEXT("memory error. [key data buffer.]\n")));
  640. goto Exit2;
  641. }
  642. /*
  643. * read key data into buffer
  644. */
  645. if (fseek(hfIn, 0, SEEK_SET)) {
  646. EPRINTF((TEXT("Seek failure.\n")));
  647. goto Exit2;
  648. }
  649. if (fread(pBuf, 1, cb, hfIn) != cb || ferror(hfIn)) {
  650. EPRINTF((TEXT("Read failure. [key data.]\n")));
  651. goto Exit2;
  652. }
  653. /*
  654. * write key data
  655. */
  656. if (fwrite(pBuf, 1, cb, hfOut) != cb || ferror(hfOut)) {
  657. EPRINTF((TEXT("Write failure. [key data.]\n")));
  658. goto Exit2;
  659. }
  660. free(pBuf);
  661. fclose(hfIn);
  662. LogRegCloseKey(hSubkey);
  663. /*
  664. * remove temp file
  665. */
  666. DeleteFileA(pszTempFile);
  667. return(TRUE);
  668. }
  669. /*
  670. * Creates a canonical key name from hKeyRoot and prefixes it with pszPrefix.
  671. *
  672. * ppszNode must be freed by caller.
  673. * returns fSuccess.
  674. */
  675. BOOL GetKeyNameWithPrefix(
  676. LPTSTR *ppszNode, // results needs to be freed
  677. HKEY hKeyRoot,
  678. LPTSTR pszPrefix)
  679. {
  680. LPTSTR pszPrefix1;
  681. pszPrefix1 = ReuseFullPathFromKey(hKeyRoot, NULL, &pszTemp1);
  682. *ppszNode = malloc(
  683. (_tcslen(pszPrefix1) +
  684. _tcslen(pszPrefix) +
  685. 3) * sizeof(TCHAR));
  686. if (*ppszNode == NULL) {
  687. MEMFAILED;
  688. return(FALSE);
  689. }
  690. _tcscpy(*ppszNode, pszPrefix);
  691. _tcscat(*ppszNode, TEXT("\\"));
  692. _tcscat(*ppszNode, pszPrefix1);
  693. return(TRUE);
  694. }
  695. /*
  696. * Breaks up a canonical key name into its root, and subkey names and
  697. * also returns the root HKEY key value as well.
  698. *
  699. * pfFreeSubkeyString is set to TRUE if the ppszSubkey returned
  700. * was allocated.
  701. *
  702. * returns fSuccess.
  703. */
  704. BOOL KeyPartsFromNodeName(
  705. LPTSTR pszNode,
  706. LPTSTR *ppszRootkey,
  707. LPTSTR *ppszSubkey, // FREE this if pfFreeSubkeyString is set on return.
  708. HKEY *phKeyRoot,
  709. BOOL *pfFreeSubkeyString)
  710. {
  711. *pfFreeSubkeyString = FALSE;
  712. if (_tcsstr(pszNode, pszHKEY_LOCAL_MACHINE) == pszNode) {
  713. *ppszRootkey = pszHKEY_LOCAL_MACHINE;
  714. *phKeyRoot = HKEY_LOCAL_MACHINE;
  715. *ppszSubkey = &pszNode[_tcslen(pszHKEY_LOCAL_MACHINE) + 1];
  716. } else if (_tcsstr(pszNode, pszHKEY_USERS) == pszNode) {
  717. *ppszRootkey = pszHKEY_USERS;
  718. *phKeyRoot = HKEY_USERS;
  719. *ppszSubkey = &pszNode[_tcslen(pszHKEY_USERS) + 1];
  720. } else if (_tcsstr(pszNode, pszHKEY_CURRENT_USER) == pszNode) {
  721. *ppszRootkey = pszHKEY_USERS;
  722. *phKeyRoot = HKEY_USERS;
  723. *ppszSubkey = malloc((_tcslen(pszCurUserSID) +
  724. _tcslen(pszNode)) * sizeof(TCHAR));
  725. if (*ppszSubkey == NULL) {
  726. MEMFAILED;
  727. return(FALSE);
  728. }
  729. _tcscpy(*ppszSubkey, pszCurUserSID);
  730. _tcscat(*ppszSubkey, &pszNode[_tcslen(pszHKEY_CURRENT_USER)]);
  731. *pfFreeSubkeyString = TRUE;
  732. } else if (_tcsstr(pszNode, pszHKEY_CLASSES_ROOT) == pszNode) {
  733. *ppszRootkey = pszHKEY_LOCAL_MACHINE;
  734. *phKeyRoot = HKEY_LOCAL_MACHINE;
  735. *ppszSubkey = malloc((_tcslen(pszRealClassesRoot) +
  736. _tcslen(pszNode)) * sizeof(TCHAR));
  737. if (*ppszSubkey == NULL) {
  738. MEMFAILED;
  739. return(FALSE);
  740. }
  741. _tcscpy(*ppszSubkey, pszRealClassesRoot);
  742. _tcscat(*ppszSubkey, &pszNode[_tcslen(pszHKEY_CLASSES_ROOT)]);
  743. *pfFreeSubkeyString = TRUE;
  744. } else {
  745. return(FALSE);
  746. }
  747. return(TRUE);
  748. }
  749. /*
  750. * Snapshots the local hives and puts the into into pszOutFile.
  751. */
  752. BOOL SnapHives(
  753. LPSTR pszOutFile)
  754. {
  755. FILE *hfOut;
  756. LPTSTR pszRootkey, pszSubkey;
  757. HKEY hKeyRoot;
  758. BOOL fFree;
  759. DWORD i;
  760. DPRINTF((TEXT("SnapHives(%hs)\n"), pszOutFile));
  761. hfOut = fopen(pszOutFile, "wb");
  762. if (hfOut == NULL) {
  763. EPRINTF((TEXT("Couldn't create %hs.\n"), pszOutFile));
  764. return(FALSE);
  765. }
  766. for (i = 0; i < cIncludeKeys; i++) {
  767. if (!KeyPartsFromNodeName(ppszIncludeKeys[i], &pszRootkey,
  768. &pszSubkey, &hKeyRoot, &fFree)) {
  769. EPRINTF((TEXT("Invalid Inclusion list entry: %s.\n"),
  770. ppszIncludeKeys[i]));
  771. fclose(hfOut);
  772. return(FALSE);
  773. }
  774. if (!StoreSubKey(hKeyRoot, pszSubkey, hfOut)) {
  775. EPRINTF((TEXT("Snapshot failed.\n")));
  776. if (fFree) {
  777. free(pszSubkey);
  778. }
  779. fclose(hfOut);
  780. return(FALSE);
  781. }
  782. if (fFree) {
  783. free(pszSubkey);
  784. }
  785. }
  786. fclose(hfOut);
  787. VPRINTF((TEXT("Snapshot to %hs completed ok.\n"), pszOutFile));
  788. return(TRUE);
  789. }
  790. /*
  791. * Special string searching code that sees if pszSearch is a proper
  792. * substring of pszData where '?'s in pszSearch match any character in
  793. * pszData. pszData must not be '\' when pszSearch is '?'.
  794. *
  795. * returns fMatched.
  796. */
  797. BOOL substrrexp(
  798. LPCTSTR pszSearch,
  799. LPCTSTR pszData)
  800. {
  801. // DPRINTF(("substrrexp(%s,%s) = ", pszData, pszSearch));
  802. while (*pszData != TEXT('\0') && *pszSearch != TEXT('\0')) {
  803. if (*pszSearch != TEXT('?')) {
  804. if (*pszData != *pszSearch) {
  805. break;
  806. }
  807. } else {
  808. if (*pszData == TEXT('\\')) {
  809. break; // prevents \ from matching a ?
  810. }
  811. }
  812. pszData++;
  813. pszSearch++;
  814. }
  815. // DPRINTF(("%d\n", *pszSearch == TEXT('\0')));
  816. return(*pszSearch == TEXT('\0'));
  817. }
  818. /*
  819. * Searches all the node names in the node list given and sets the
  820. * corresponding afMarkFound[] element to TRUE if hKey\pszSubkey is
  821. * referenced within that node name. Returns TRUE if ANY node names
  822. * reference the subkey name.
  823. *
  824. * afMarkFound may be NULL.
  825. * pszSubkey may be NULL.
  826. */
  827. BOOL IsKeyWithinNodeList(
  828. HKEY hKey,
  829. LPTSTR pszSubkey, // optional
  830. LPTSTR *apszNodes,
  831. DWORD cNodes,
  832. BOOL *afMarkFound) // optional
  833. {
  834. DWORD i;
  835. BOOL fRet;
  836. LPTSTR pszFullName;
  837. fRet = FALSE;
  838. pszFullName = GetFullPathFromKey(hKey, pszSubkey);
  839. if (pszFullName != NULL) {
  840. for (i = 0; i < cNodes; i++) {
  841. if (substrrexp(apszNodes[i], pszFullName) &&
  842. (pszFullName[_tcslen(apszNodes[i])] == TEXT('\\') ||
  843. pszFullName[_tcslen(apszNodes[i])] == TEXT('\0'))) {
  844. fRet = TRUE;
  845. if (afMarkFound != NULL) {
  846. afMarkFound[i] = TRUE;
  847. }
  848. }
  849. if (fRet && afMarkFound == NULL) {
  850. break; // no need to cycle if not marking found nodes.
  851. }
  852. }
  853. free(pszFullName);
  854. }
  855. return(fRet);
  856. }
  857. BOOL CopyKeySubkey(
  858. HKEY hKeyFrom,
  859. LPTSTR pszSubkeyFrom,
  860. HKEY hKeyTo,
  861. LPTSTR pszSubkeyTo)
  862. {
  863. LONG status;
  864. HKEY hSubkeyFrom, hSubkeyTo;
  865. BOOL fRet;
  866. DPRINTF((TEXT("CopyKeySubkey(%s, %s)\n"),
  867. ReuseFullPathFromKey(hKeyFrom, pszSubkeyFrom, &pszTemp1),
  868. ReuseFullPathFromKey(hKeyTo, pszSubkeyTo, &pszTemp2)));
  869. /*
  870. * This key could be in our exclusion list - check first.
  871. */
  872. if (IsKeyWithinNodeList(hKeyFrom, pszSubkeyFrom, ppszExceptKeys, cExceptKeys, NULL)) {
  873. if (fDebug) {
  874. DPRINTF((TEXT("Key %s was EXCLUDED.\n"),
  875. ReuseFullPathFromKey(hKeyFrom, pszSubkeyFrom, &pszTemp1)));
  876. }
  877. return(TRUE); // just fake it - its excluded.
  878. }
  879. if (IsKeyWithinNodeList(hKeyTo, pszSubkeyTo, ppszExceptKeys, cExceptKeys, NULL)) {
  880. if (fDebug) {
  881. DPRINTF((TEXT("Key %s was EXCLUDED.\n"),
  882. ReuseFullPathFromKey(hKeyTo, pszSubkeyTo, &pszTemp1)));
  883. }
  884. return(TRUE); // just fake it - its excluded.
  885. }
  886. if (!fSafe) {
  887. status = LogRegOpenKey(hKeyFrom, pszSubkeyFrom, &hSubkeyFrom);
  888. if (status != ERROR_SUCCESS) {
  889. EPRINTF((TEXT("Could not open key %s. Error=%d.\n"),
  890. ReuseFullPathFromKey(hKeyFrom, pszSubkeyFrom, &pszTemp1), status));
  891. return(FALSE);
  892. }
  893. status = LogRegCreateKey(hKeyTo, pszSubkeyTo, &hSubkeyTo);
  894. if (status != ERROR_SUCCESS) {
  895. EPRINTF((TEXT("Could not create key %s. Error=%d.\n"),
  896. ReuseFullPathFromKey(hKeyTo, pszSubkeyTo, &pszTemp1), status));
  897. return(FALSE);
  898. }
  899. fRet = AddNodeInfo(hSubkeyFrom, hSubkeyTo);
  900. LogRegCloseKey(hSubkeyTo);
  901. LogRegCloseKey(hSubkeyFrom);
  902. } else if (fDebug || fVerbose) {
  903. LPTSTR pszInfo = GetFullPathFromKey(hKeyFrom, pszSubkeyFrom);
  904. LPTSTR pszTarget = GetFullPathFromKey(hKeyTo, pszSubkeyTo);
  905. VPRINTF((TEXT("Would have copied %s to %s.\n"),
  906. ReuseFullPathFromKey(hKeyFrom, pszSubkeyFrom, &pszTemp1),
  907. ReuseFullPathFromKey(hKeyTo, pszSubkeyTo, &pszTemp2)));
  908. free(pszInfo);
  909. free(pszTarget);
  910. fRet = TRUE;
  911. }
  912. return(fRet);
  913. }
  914. /*
  915. * Combines the pszName entries into one string and passes control on to
  916. * CopyKeySubkey().
  917. */
  918. BOOL CopyKeySubkeyEx(
  919. HKEY hKeyFrom,
  920. LPTSTR pszSubkeyName,
  921. HKEY hKeyTo,
  922. LPTSTR pszNameTo1,
  923. LPTSTR pszNameTo2)
  924. {
  925. LPTSTR psz;
  926. psz = malloc((_tcslen(pszNameTo1) + _tcslen(pszNameTo2) +
  927. _tcslen(pszSubkeyName) + 3) * sizeof(TCHAR));
  928. if (psz == NULL) {
  929. MEMFAILED;
  930. return(FALSE);
  931. }
  932. _tcscpy(psz, pszNameTo1);
  933. _tcscat(psz, TEXT("\\"));
  934. _tcscat(psz, pszNameTo2);
  935. _tcscat(psz, TEXT("\\"));
  936. _tcscat(psz, pszSubkeyName);
  937. if (!CopyKeySubkey(hKeyFrom, pszSubkeyName, hKeyTo, psz)) {
  938. free(psz);
  939. return(FALSE);
  940. }
  941. free(psz);
  942. return(TRUE);
  943. }
  944. BOOL CopyKeyValue(
  945. HKEY hKeyFrom,
  946. HKEY hKeyTo,
  947. LPTSTR pszValue)
  948. {
  949. LONG status;
  950. PVOID pBuf;
  951. DWORD dwType, cbData;
  952. DPRINTF((TEXT("CopyKeyValue(%s, %s, %s)\n"),
  953. ReuseFullPathFromKey(hKeyFrom, NULL, &pszTemp1),
  954. ReuseFullPathFromKey(hKeyTo, NULL, &pszTemp2),
  955. pszValue));
  956. /*
  957. * This key could be in our exclusion list - check first.
  958. */
  959. if (IsKeyWithinNodeList(hKeyFrom, pszValue, ppszExceptKeys, cExceptKeys, NULL)) {
  960. if (fDebug) {
  961. DPRINTF((TEXT("Source Value \"%s\" was EXCLUDED.\n"), pszValue));
  962. }
  963. return(TRUE); // just fake it - its excluded.
  964. }
  965. if (IsKeyWithinNodeList(hKeyTo, pszValue, ppszExceptKeys, cExceptKeys, NULL)) {
  966. if (fDebug) {
  967. DPRINTF((TEXT("Target Value \"%s\" was EXCLUDED.\n"), pszValue));
  968. }
  969. return(TRUE); // just fake it - its excluded.
  970. }
  971. status = RegQueryValueEx(hKeyFrom, pszValue, NULL, &dwType, NULL, &cbData);
  972. if (status != ERROR_SUCCESS) {
  973. EPRINTF((TEXT("Could not query value %s size from %s. Error=%d.\n"),
  974. pszValue, ReuseFullPathFromKey(hKeyFrom, NULL, &pszTemp1),
  975. status));
  976. return(FALSE);
  977. }
  978. pBuf = malloc(cbData);
  979. if (pBuf == NULL) {
  980. MEMFAILED;
  981. return(FALSE);
  982. }
  983. status = RegQueryValueEx(hKeyFrom, pszValue, NULL, &dwType, pBuf, &cbData);
  984. if (status != ERROR_SUCCESS) {
  985. EPRINTF((TEXT("Could not query value %s from %s. Error=%d.\n"),
  986. pszValue, ReuseFullPathFromKey(hKeyFrom, NULL, &pszTemp1),
  987. status));
  988. free(pBuf);
  989. return(FALSE);
  990. }
  991. status = RegSetValueEx(hKeyTo, pszValue, 0, dwType, (BYTE *)pBuf, cbData);
  992. free(pBuf);
  993. if (status == ERROR_SUCCESS) {
  994. return(TRUE);
  995. } else {
  996. EPRINTF((TEXT("Could not set value %s. Error=%d.\n"),
  997. ReuseFullPathFromKey(hKeyTo, pszValue, &pszTemp1), status));
  998. return(FALSE);
  999. }
  1000. }
  1001. /*
  1002. * Combines the pszName entries into one string and passes control on to
  1003. * CopyKeyValue().
  1004. */
  1005. BOOL CopyKeyValueEx(
  1006. HKEY hKeyFrom,
  1007. LPTSTR pszValueName,
  1008. HKEY hKeyTo,
  1009. LPTSTR pszNameTo1,
  1010. LPTSTR pszNameTo2)
  1011. {
  1012. LPTSTR psz;
  1013. HKEY hKeyToFull;
  1014. LONG status;
  1015. psz = malloc((_tcslen(pszNameTo1) + _tcslen(pszNameTo2) + 2) * sizeof(TCHAR));
  1016. if (psz == NULL) {
  1017. MEMFAILED;
  1018. return(FALSE);
  1019. }
  1020. _tcscpy(psz, pszNameTo1);
  1021. _tcscat(psz, TEXT("\\"));
  1022. _tcscat(psz, pszNameTo2);
  1023. status = LogRegCreateKey(hKeyTo, psz, &hKeyToFull);
  1024. if (status != ERROR_SUCCESS) {
  1025. free(psz);
  1026. return(FALSE);
  1027. }
  1028. free(psz);
  1029. if (!CopyKeyValue(hKeyFrom, hKeyToFull, pszValueName)) {
  1030. EPRINTF((TEXT("Key value %s could not be copied from %s to %s.\n"),
  1031. pszValueName,
  1032. ReuseFullPathFromKey(hKeyFrom, (LPCTSTR)NULL, &pszTemp1),
  1033. ReuseFullPathFromKey(hKeyToFull, (LPCTSTR)NULL, &pszTemp2)));
  1034. LogRegCloseKey(hKeyToFull);
  1035. return(FALSE);
  1036. }
  1037. LogRegCloseKey(hKeyToFull);
  1038. return(TRUE);
  1039. }
  1040. BOOL AreValuesEqual(
  1041. HKEY hSubkey1,
  1042. LPTSTR pszValueName1,
  1043. HKEY hSubkey2,
  1044. LPTSTR pszValueName2)
  1045. {
  1046. LONG status;
  1047. BOOL fRet = FALSE;
  1048. DWORD dwType1, cbData1;
  1049. DWORD dwType2, cbData2;
  1050. PVOID pBuf1, pBuf2;
  1051. DPRINTF((TEXT("AreValuesEqual(%s, %s)\n"),
  1052. ReuseFullPathFromKey(hSubkey1, pszValueName1, &pszTemp1),
  1053. ReuseFullPathFromKey(hSubkey2, pszValueName2, &pszTemp2)));
  1054. status = RegQueryValueEx(hSubkey1, pszValueName1, NULL, &dwType1, NULL, &cbData1);
  1055. if (status != ERROR_SUCCESS) {
  1056. EPRINTF((TEXT("Could not get value size of %s. Error=%d.\n"), pszValueName1, status));
  1057. return(FALSE);
  1058. }
  1059. status = RegQueryValueEx(hSubkey2, pszValueName2, NULL, &dwType2, NULL, &cbData2);
  1060. if (status != ERROR_SUCCESS) {
  1061. EPRINTF((TEXT("Could not get value size of %s. Error=%d.\n"), pszValueName2, status));
  1062. return(FALSE);
  1063. }
  1064. if (dwType1 != dwType2 || cbData1 != cbData2) {
  1065. return(FALSE);
  1066. }
  1067. pBuf1 = malloc(cbData1);
  1068. if (pBuf1 == NULL) {
  1069. MEMFAILED;
  1070. return(FALSE);
  1071. }
  1072. status = RegQueryValueEx(hSubkey1, pszValueName1, NULL, &dwType1, pBuf1, &cbData1);
  1073. if (status != ERROR_SUCCESS) {
  1074. EPRINTF((TEXT("Could not get value %s. Error=%d.\n"), pszValueName1, status));
  1075. goto Exit1;
  1076. }
  1077. pBuf2 = malloc(cbData2);
  1078. if (pBuf2 == NULL) {
  1079. MEMFAILED;
  1080. goto Exit1;
  1081. }
  1082. status = RegQueryValueEx(hSubkey2, pszValueName2, NULL, &dwType2, pBuf2, &cbData2);
  1083. if (status != ERROR_SUCCESS) {
  1084. EPRINTF((TEXT("Could not get value %s. Error=%d.\n"), pszValueName2, status));
  1085. goto Exit2;
  1086. }
  1087. fRet = memcmp(pBuf1, pBuf2, cbData1) == 0;
  1088. Exit2:
  1089. free(pBuf2);
  1090. Exit1:
  1091. free(pBuf1);
  1092. return(fRet);
  1093. }
  1094. int __cdecl mycmp(
  1095. LPCTSTR *ppsz1,
  1096. LPCTSTR *ppsz2)
  1097. {
  1098. return(_tcscmp(*ppsz1, *ppsz2));
  1099. }
  1100. VOID FreeSortedValues(
  1101. LPTSTR *ppsz,
  1102. DWORD cValues)
  1103. {
  1104. DWORD i;
  1105. if (cValues) {
  1106. for (i = 0; i < cValues; i++) {
  1107. free(ppsz[i]);
  1108. }
  1109. free(ppsz);
  1110. }
  1111. }
  1112. LPTSTR * EnumAndSortValues(
  1113. HKEY hKey,
  1114. DWORD cValues,
  1115. DWORD cchMaxValueName)
  1116. {
  1117. LONG status;
  1118. LPTSTR *ppsz;
  1119. DWORD cch, dwType, cb;
  1120. DWORD i;
  1121. DPRINTF((TEXT("EnumAndSortValues(%s, %d, %d)\n"),
  1122. ReuseFullPathFromKey(hKey, (LPCTSTR)NULL, &pszTemp1),
  1123. cValues,
  1124. cchMaxValueName));
  1125. cchMaxValueName++;
  1126. ppsz = malloc(cValues * sizeof(LPTSTR));
  1127. if (ppsz == NULL) {
  1128. MEMFAILED;
  1129. return(NULL);
  1130. }
  1131. for (i = 0; i < cValues; i++) {
  1132. ppsz[i] = malloc(cchMaxValueName * sizeof(TCHAR));
  1133. if (ppsz[i] == NULL) {
  1134. MEMFAILED;
  1135. FreeSortedValues(ppsz, i);
  1136. return(NULL);
  1137. }
  1138. cch = cchMaxValueName;
  1139. cb = 0;
  1140. status = RegEnumValue(hKey, i, ppsz[i], &cch, NULL, &dwType, NULL, &cb);
  1141. if (status != ERROR_SUCCESS) {
  1142. if (status != ERROR_NO_MORE_ITEMS) {
  1143. EPRINTF((TEXT("Could not enumerate value %d of %s. Error=%d.\n"),
  1144. i, ReuseFullPathFromKey(hKey, (LPCTSTR)NULL, &pszTemp1), status));
  1145. }
  1146. FreeSortedValues(ppsz, i + 1);
  1147. return(NULL);
  1148. }
  1149. }
  1150. qsort(ppsz, cValues, sizeof(LPTSTR), mycmp);
  1151. if (fDebug && fVerbose) {
  1152. DPRINTF((TEXT("--Value List--\n")));
  1153. for (i = 0; i < cValues; i++) {
  1154. DPRINTF((TEXT(" %s\n"), ppsz[i]));
  1155. }
  1156. }
  1157. return(ppsz);
  1158. }
  1159. VOID FreeSortedSubkeys(
  1160. LPTSTR *ppsz,
  1161. DWORD cSubkeys)
  1162. {
  1163. DWORD i;
  1164. if (cSubkeys) {
  1165. for (i = 0; i < cSubkeys; i++) {
  1166. free(ppsz[i]);
  1167. }
  1168. free(ppsz);
  1169. }
  1170. }
  1171. LPTSTR * EnumAndSortSubkeys(
  1172. HKEY hKey,
  1173. DWORD cSubkeys,
  1174. DWORD cchMaxSubkeyName)
  1175. {
  1176. LONG status;
  1177. LPTSTR *ppsz;
  1178. DWORD cch;
  1179. FILETIME ft;
  1180. DWORD i;
  1181. DPRINTF((TEXT("EnumAndSortSubkeys(%s, %d, %d)\n"),
  1182. ReuseFullPathFromKey(hKey, (LPCTSTR)NULL, &pszTemp1),
  1183. cSubkeys,
  1184. cchMaxSubkeyName));
  1185. cchMaxSubkeyName++; // poor APIs take different than what they give.
  1186. ppsz = malloc(cSubkeys * sizeof(LPTSTR));
  1187. if (ppsz == NULL) {
  1188. MEMFAILED;
  1189. return(NULL);
  1190. }
  1191. for (i = 0; i < cSubkeys; i++) {
  1192. ppsz[i] = malloc(cchMaxSubkeyName * sizeof(TCHAR));
  1193. if (ppsz[i] == NULL) {
  1194. MEMFAILED;
  1195. FreeSortedSubkeys(ppsz, i);
  1196. return(NULL);
  1197. }
  1198. cch = cchMaxSubkeyName;
  1199. status = RegEnumKeyEx(hKey, i, ppsz[i], &cch, NULL, NULL, NULL, &ft);
  1200. if (status != ERROR_SUCCESS) {
  1201. if (status != ERROR_NO_MORE_ITEMS) {
  1202. EPRINTF((TEXT("Could not enumerate key %d of %s. Error=%d.\n"),
  1203. i, ReuseFullPathFromKey(hKey, (LPCTSTR)NULL, &pszTemp1), status));
  1204. }
  1205. FreeSortedSubkeys(ppsz, i + 1);
  1206. return(NULL);
  1207. }
  1208. }
  1209. qsort(ppsz, cSubkeys, sizeof(LPTSTR), mycmp);
  1210. if (fDebug && fVerbose) {
  1211. DPRINTF((TEXT("--Subkey List--\n")));
  1212. for (i = 0; i < cSubkeys; i++) {
  1213. DPRINTF((TEXT(" %s\n"), ppsz[i]));
  1214. }
  1215. }
  1216. return(ppsz);
  1217. }
  1218. /*
  1219. * Recursively compares two nodes in the registry and places the added and
  1220. * deleted differences into subnodes of the Diffkey given.
  1221. *
  1222. * Additions go into hRootDiffKey\pszAddKey\<pszSubkeyName1>
  1223. * Deletions go into hRootDiffKey\pszDelKey\<pszSubkeyName1>
  1224. */
  1225. BOOL DiffNodes(
  1226. HKEY hKeyRoot,
  1227. LPTSTR pszSubkeyName1, // Key BEFORE changes (modified name)
  1228. LPTSTR pszSubkeyName2, // Key AFTER changes (original name)
  1229. HKEY hRootDiffKey)
  1230. {
  1231. DWORD status;
  1232. DWORD cSubkeys1, cchMaxSubkey1, cValues1, cchMaxValueName1, cbMaxValueData1;
  1233. DWORD cSubkeys2, cchMaxSubkey2, cValues2, cchMaxValueName2, cbMaxValueData2;
  1234. FILETIME FileTime1, FileTime2;
  1235. HKEY hSubkey1, hSubkey2;
  1236. LPTSTR pszNewSubkeyName1, pszNewSubkeyName2;
  1237. LPTSTR *apszValueName1, *apszValueName2, *apszSubkeyName1, *apszSubkeyName2;
  1238. BOOL fRet;
  1239. DWORD i1, i2;
  1240. int comp;
  1241. LPTSTR pszFullDelKey, pszFullAddKey;
  1242. DPRINTF((TEXT("DiffNodes(%s and %s to %s.)\n"),
  1243. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName1, &pszTemp1),
  1244. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName2, &pszTemp2),
  1245. ReuseFullPathFromKey(hRootDiffKey, (LPCTSTR)NULL, &pszTemp3)));
  1246. if (!GetKeyNameWithPrefix(&pszFullDelKey, hKeyRoot, pszDelKey)) {
  1247. return(FALSE);
  1248. }
  1249. if (!GetKeyNameWithPrefix(&pszFullAddKey, hKeyRoot, pszAddKey)) {
  1250. Exit0:
  1251. free(pszFullDelKey);
  1252. return(FALSE);
  1253. }
  1254. /*
  1255. * Skip it if its in the exception list
  1256. */
  1257. for (i1 = 0; i1 < cExceptKeys; i1++) {
  1258. if (!_tcscmp(pszSubkeyName1, ppszExceptKeys[i1])) {
  1259. DPRINTF((TEXT("Diff on node %s EXCEPTED.\n"),
  1260. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName1, &pszTemp1)));
  1261. return(TRUE);
  1262. }
  1263. }
  1264. /*
  1265. * Open subkeys
  1266. */
  1267. status = LogRegOpenKey(hKeyRoot, pszSubkeyName1, &hSubkey1);
  1268. if (status != ERROR_SUCCESS) {
  1269. EPRINTF((TEXT("Could not open key %s. Error=%d\n"),
  1270. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName1, &pszTemp1),
  1271. status));
  1272. return(FALSE);
  1273. }
  1274. status = LogRegOpenKey(hKeyRoot, pszSubkeyName2, &hSubkey2);
  1275. if (status != ERROR_SUCCESS) {
  1276. EPRINTF((TEXT("Could not open key %s. Error=%d\n"),
  1277. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName2, &pszTemp1),
  1278. status));
  1279. EPRINTF((TEXT("Try adding this key to the exception list.\n")));
  1280. return(FALSE);
  1281. }
  1282. /*
  1283. * Enumerate subkeys
  1284. */
  1285. status = MyRegQueryInfoKey(hSubkey1, &cSubkeys1, &cchMaxSubkey1, &cValues1,
  1286. &cchMaxValueName1, &cbMaxValueData1, &FileTime1);
  1287. if (status != ERROR_SUCCESS) {
  1288. if (status != ERROR_NO_MORE_ITEMS) {
  1289. EPRINTF((TEXT("Could not enumerate key %s. Error=%d.\n"),
  1290. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName1, &pszTemp1),
  1291. status));
  1292. }
  1293. return(FALSE);
  1294. }
  1295. cchMaxSubkey1++;
  1296. cchMaxValueName1++;
  1297. cbMaxValueData1++;
  1298. status = MyRegQueryInfoKey(hSubkey2, &cSubkeys2, &cchMaxSubkey2, &cValues2,
  1299. &cchMaxValueName2, &cbMaxValueData2, &FileTime2);
  1300. if (status != ERROR_SUCCESS) {
  1301. if (status != ERROR_NO_MORE_ITEMS) {
  1302. EPRINTF((TEXT("Could not enumerate key %s. Error=%d.\n"),
  1303. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName2, &pszTemp1),
  1304. status));
  1305. }
  1306. return(FALSE);
  1307. }
  1308. cchMaxSubkey2++;
  1309. cchMaxValueName2++;
  1310. cbMaxValueData2++;
  1311. /*
  1312. * Compare subkey values
  1313. */
  1314. if (CompareFileTime(&FileTime1, &FileTime2)) {
  1315. /*
  1316. * Timestamps differ so values may be different.
  1317. *
  1318. * Enumerate values on nodes, sort, and compare.
  1319. */
  1320. if (cValues1) {
  1321. apszValueName1 = EnumAndSortValues(hSubkey1, cValues1, cchMaxValueName1);
  1322. if (apszValueName1 == NULL) {
  1323. Exit1:
  1324. LogRegCloseKey(hSubkey1);
  1325. LogRegCloseKey(hSubkey2);
  1326. free(pszFullAddKey);
  1327. goto Exit0;
  1328. }
  1329. }
  1330. if (cValues2) {
  1331. apszValueName2 = EnumAndSortValues(hSubkey2, cValues2, cchMaxValueName2);
  1332. if (apszValueName2 == NULL) {
  1333. Exit2:
  1334. FreeSortedValues(apszValueName1, cValues1);
  1335. goto Exit1;
  1336. }
  1337. }
  1338. i1 = i2 = 0;
  1339. while (i1 < cValues1 && i2 < cValues2) {
  1340. comp = _tcscmp(apszValueName1[i1], apszValueName2[i2]);
  1341. if (comp < 0) {
  1342. /*
  1343. * Value1 is NOT in Key2. Add Value1 to Del Node.
  1344. */
  1345. if (!CopyKeyValueEx(hSubkey1, apszValueName1[i1], hRootDiffKey,
  1346. pszFullDelKey, pszSubkeyName2)) {
  1347. Exit3:
  1348. FreeSortedValues(apszValueName2, cValues2);
  1349. goto Exit2;
  1350. }
  1351. i1++;
  1352. } else if (comp > 0) {
  1353. /*
  1354. * Value2 is NOT in Key1, Add Value2 to Add Node.
  1355. */
  1356. if (!CopyKeyValueEx(hSubkey2, apszValueName2[i2], hRootDiffKey,
  1357. pszFullAddKey, pszSubkeyName2)) {
  1358. goto Exit3;
  1359. }
  1360. i2++;
  1361. } else {
  1362. /*
  1363. * Compare data of Value1 and Value2
  1364. */
  1365. if (!AreValuesEqual(hSubkey1, apszValueName1[i1],
  1366. hSubkey2, apszValueName2[i2])) {
  1367. /*
  1368. * Value has changed. Add to both Add and Del nodes.
  1369. */
  1370. if (!CopyKeyValueEx(hSubkey1, apszValueName1[i1], hRootDiffKey,
  1371. pszFullDelKey, pszSubkeyName2)) {
  1372. goto Exit3;
  1373. }
  1374. if (!CopyKeyValueEx(hSubkey2, apszValueName2[i2], hRootDiffKey,
  1375. pszFullAddKey, pszSubkeyName2)) {
  1376. goto Exit3;
  1377. }
  1378. }
  1379. i1++;
  1380. i2++;
  1381. }
  1382. }
  1383. while (i1 < cValues1) {
  1384. if (!CopyKeyValueEx(hSubkey1, apszValueName1[i1], hRootDiffKey,
  1385. pszFullDelKey, pszSubkeyName2)) {
  1386. goto Exit3;
  1387. }
  1388. i1++;
  1389. }
  1390. while (i2 < cValues2) {
  1391. if (!CopyKeyValueEx(hSubkey2, apszValueName2[i2], hRootDiffKey,
  1392. pszFullAddKey, pszSubkeyName2)) {
  1393. goto Exit3;
  1394. }
  1395. i2++;
  1396. }
  1397. FreeSortedValues(apszValueName1, cValues1);
  1398. FreeSortedValues(apszValueName2, cValues2);
  1399. }
  1400. /*
  1401. * Enumerate subkeys and compare.
  1402. */
  1403. if (cSubkeys1) {
  1404. apszSubkeyName1 = EnumAndSortSubkeys(hSubkey1, cSubkeys1, cchMaxSubkey1);
  1405. if (apszSubkeyName1 == NULL) {
  1406. goto Exit1;
  1407. }
  1408. }
  1409. if (cSubkeys2) {
  1410. apszSubkeyName2 = EnumAndSortSubkeys(hSubkey2, cSubkeys2, cchMaxSubkey2);
  1411. if (apszSubkeyName2 == NULL) {
  1412. Exit4:
  1413. FreeSortedSubkeys(apszSubkeyName1, cSubkeys1);
  1414. goto Exit1;
  1415. }
  1416. }
  1417. i1 = i2 = 0;
  1418. while (i1 < cSubkeys1 && i2 < cSubkeys2) {
  1419. comp = _tcscmp(apszSubkeyName1[i1], apszSubkeyName2[i2]);
  1420. if (comp < 0) {
  1421. /*
  1422. * Subkey1 is NOT in Key2. Add Subkey1 to Del Node.
  1423. */
  1424. if (!CopyKeySubkeyEx(hSubkey1, apszSubkeyName1[i1], hRootDiffKey,
  1425. pszFullDelKey, pszSubkeyName2)) {
  1426. Exit5:
  1427. FreeSortedSubkeys(apszSubkeyName2, cSubkeys2);
  1428. goto Exit4;
  1429. }
  1430. i1++;
  1431. } else if (comp > 0) {
  1432. /*
  1433. * Subkey2 is NOT in Key1, Add Subkey2 to Add Node.
  1434. */
  1435. if (!CopyKeySubkeyEx(hSubkey2, apszSubkeyName2[i2], hRootDiffKey,
  1436. pszFullAddKey, pszSubkeyName2)) {
  1437. goto Exit5;
  1438. }
  1439. i2++;
  1440. } else {
  1441. /*
  1442. * Compare subkeys of Subkey1 and Subkey2
  1443. */
  1444. pszNewSubkeyName1 = malloc((_tcslen(pszSubkeyName1) +
  1445. _tcslen(apszSubkeyName1[i1]) + 2) * sizeof(TCHAR));
  1446. if (pszNewSubkeyName1 == NULL) {
  1447. MEMFAILED;
  1448. goto Exit5;
  1449. }
  1450. _tcscpy(pszNewSubkeyName1, pszSubkeyName1);
  1451. _tcscat(pszNewSubkeyName1, TEXT("\\"));
  1452. _tcscat(pszNewSubkeyName1, apszSubkeyName1[i1]);
  1453. pszNewSubkeyName2 = malloc((_tcslen(pszSubkeyName2) +
  1454. _tcslen(apszSubkeyName2[i2]) + 2) * sizeof(TCHAR));
  1455. if (pszNewSubkeyName2 == NULL) {
  1456. MEMFAILED;
  1457. free(pszNewSubkeyName1);
  1458. goto Exit5;
  1459. }
  1460. _tcscpy(pszNewSubkeyName2, pszSubkeyName2);
  1461. _tcscat(pszNewSubkeyName2, TEXT("\\"));
  1462. _tcscat(pszNewSubkeyName2, apszSubkeyName2[i2]);
  1463. fRet = DiffNodes(hKeyRoot, pszNewSubkeyName1, pszNewSubkeyName2,
  1464. hRootDiffKey);
  1465. free(pszNewSubkeyName1);
  1466. free(pszNewSubkeyName2);
  1467. if (fRet == FALSE) {
  1468. goto Exit5;
  1469. }
  1470. i1++;
  1471. i2++;
  1472. }
  1473. }
  1474. while (i1 < cSubkeys1) {
  1475. if (!CopyKeySubkeyEx(hSubkey1, apszSubkeyName1[i1], hRootDiffKey,
  1476. pszFullDelKey, pszSubkeyName2)) {
  1477. goto Exit5;
  1478. }
  1479. i1++;
  1480. }
  1481. while (i2 < cSubkeys2) {
  1482. if (!CopyKeySubkeyEx(hSubkey2, apszSubkeyName2[i2], hRootDiffKey,
  1483. pszFullAddKey, pszSubkeyName2)) {
  1484. goto Exit5;
  1485. }
  1486. i2++;
  1487. }
  1488. FreeSortedSubkeys(apszSubkeyName1, cSubkeys1);
  1489. FreeSortedSubkeys(apszSubkeyName2, cSubkeys2);
  1490. LogRegCloseKey(hSubkey1);
  1491. LogRegCloseKey(hSubkey2);
  1492. free(pszFullAddKey);
  1493. free(pszFullDelKey);
  1494. return(TRUE);
  1495. }
  1496. /*
  1497. * Removes a key and all its subkeys from the registry. Returns fSuccess.
  1498. */
  1499. BOOL DeleteKeyNode(
  1500. HKEY hKey,
  1501. LPCTSTR lpszSubkey)
  1502. {
  1503. LONG status;
  1504. HKEY hSubkey;
  1505. DWORD cSubkeys;
  1506. DWORD cchMaxSubkey;
  1507. DWORD i;
  1508. LPTSTR *apszSubkeyNames;
  1509. if (fDebug) {
  1510. DPRINTF((TEXT("DeleteKeyNode(%s)\n"),
  1511. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1)));
  1512. }
  1513. /*
  1514. * First, just try to delete it. We might just be lucky!
  1515. */
  1516. status = RegDeleteKey(hKey, lpszSubkey);
  1517. if (status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND) {
  1518. return(TRUE);
  1519. }
  1520. /*
  1521. * Ok ok, so we weren't lucky.
  1522. */
  1523. status = LogRegOpenKey(hKey, lpszSubkey, &hSubkey);
  1524. if (status != ERROR_SUCCESS) {
  1525. EPRINTF((TEXT("Could not open key %s for deletion. Error=%d\n"),
  1526. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1), status));
  1527. return(FALSE);
  1528. }
  1529. status = MyRegQueryInfoKey(hSubkey, &cSubkeys, &cchMaxSubkey, NULL, NULL,
  1530. NULL, NULL);
  1531. if (status != ERROR_SUCCESS) {
  1532. EPRINTF((TEXT("Could not get info on key %s for deletion. Error=%d\n"),
  1533. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1), status));
  1534. Exit1:
  1535. LogRegCloseKey(hSubkey);
  1536. return(FALSE);
  1537. }
  1538. cchMaxSubkey++;
  1539. apszSubkeyNames = EnumAndSortSubkeys(hSubkey, cSubkeys, cchMaxSubkey);
  1540. if (apszSubkeyNames == NULL) {
  1541. EPRINTF((TEXT("Could not enumerate key %s for deletion.\n"),
  1542. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1)));
  1543. goto Exit1;
  1544. }
  1545. for (i = 0; i < cSubkeys; i++) {
  1546. DeleteKeyNode(hSubkey, apszSubkeyNames[i]);
  1547. }
  1548. FreeSortedSubkeys(apszSubkeyNames, cSubkeys);
  1549. LogRegCloseKey(hSubkey);
  1550. /*
  1551. * Ok, the key no longer has subkeys so we should be able to delete it now.
  1552. */
  1553. status = RegDeleteKey(hKey, lpszSubkey);
  1554. if (status != ERROR_SUCCESS) {
  1555. EPRINTF((TEXT("Could not delete key %s. Error=%d.\n"),
  1556. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1), status));
  1557. return(FALSE);
  1558. }
  1559. return(TRUE);
  1560. }
  1561. LONG MyRegLoadKey(
  1562. HKEY hKey,
  1563. LPCTSTR pszSubkey,
  1564. LPCSTR pszFile)
  1565. {
  1566. LONG status;
  1567. #ifdef UNICODE
  1568. LPWSTR pszWBuf;
  1569. pszWBuf = malloc((strlen(pszTempFile) + 1) * sizeof(WCHAR));
  1570. if (pszWBuf != NULL) {
  1571. _stprintf(pszWBuf, TEXT("%hs"), pszFile);
  1572. status = RegLoadKey(hKey, pszSubkey, pszWBuf);
  1573. free(pszWBuf);
  1574. } else {
  1575. status = ERROR_NOT_ENOUGH_MEMORY;
  1576. }
  1577. #else
  1578. status = RegLoadKey(hKey, pszSubkey, pszFile);
  1579. #endif // UNICODE
  1580. return(status);
  1581. }
  1582. BOOL DiffHive(
  1583. LPSTR pszSnapFileIn)
  1584. {
  1585. FILE *hfIn, *hfOut;
  1586. LPTSTR pszSubkeyName;
  1587. LPVOID pBuf;
  1588. DWORD cb, i;
  1589. LONG status;
  1590. HKEY hKeyRoot, hKeyDiffRoot;
  1591. DPRINTF((TEXT("DiffHive(%hs)\n"),
  1592. pszSnapFileIn));
  1593. /*
  1594. * remove any diff info laying around in the registry.
  1595. */
  1596. RegUnLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot);
  1597. DeleteKeyNode(HKEY_LOCAL_MACHINE, pszDiffRoot);
  1598. /*
  1599. * Load an empty file to create the regdiff key off of the
  1600. * HKEY_LOCAL_MACHINE root key.
  1601. * (a hack that should not be necessary!)
  1602. */
  1603. DeleteFileA(pszDummyFile);
  1604. status = MyRegLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot, pszDummyFile);
  1605. if (status != ERROR_SUCCESS) {
  1606. EPRINTF((TEXT("Unable to load %s\\%s from %hs.\n"),
  1607. pszHKEY_LOCAL_MACHINE, pszDiffRoot, pszDummyFile));
  1608. return(FALSE);
  1609. }
  1610. /*
  1611. * Open snapshot file
  1612. */
  1613. hfIn = fopen(pszSnapFileIn, "rb");
  1614. if (hfIn == NULL) {
  1615. EPRINTF((TEXT("Could not open %hs.\n"), pszSnapFileIn));
  1616. return(FALSE);
  1617. }
  1618. /*
  1619. * for each section...
  1620. */
  1621. DeleteFileA(pszTempFile); // RegSaveKey will fail if this exists.
  1622. while(fread(&cb, 1, sizeof(DWORD), hfIn) == sizeof(DWORD) && !ferror(hfIn)) {
  1623. /*
  1624. * alocate a buffer for full key name.
  1625. */
  1626. pszSubkeyName = malloc(cb);
  1627. if (pszSubkeyName == NULL) {
  1628. MEMFAILED;
  1629. Exit4:
  1630. fclose(hfIn);
  1631. return(FALSE);
  1632. }
  1633. /*
  1634. * read full key name
  1635. */
  1636. if (fread(pszSubkeyName, 1, cb, hfIn) != cb || ferror(hfIn)) {
  1637. EPRINTF((TEXT("Read failure. [key name.]\n")));
  1638. Exit6:
  1639. free(pszSubkeyName);
  1640. goto Exit4;
  1641. }
  1642. /*
  1643. * read root key handle
  1644. */
  1645. if (fread(&hKeyRoot, 1, sizeof(HKEY), hfIn) != sizeof(HKEY) || ferror(hfIn)) {
  1646. EPRINTF((TEXT("Read failure. [Root key handle.]\n")));
  1647. goto Exit6;
  1648. }
  1649. /*
  1650. * Find out if pszSubkeyName is covered by our include key list.
  1651. * If so, do a diff on it.
  1652. */
  1653. if (IsKeyWithinNodeList(hKeyRoot, pszSubkeyName, ppszIncludeKeys,
  1654. cIncludeKeys, afIncludeKeyMarks)) {
  1655. /*
  1656. * read sizeof key data
  1657. */
  1658. if (fread(&cb, 1, sizeof(DWORD), hfIn) != sizeof(DWORD) || ferror(hfIn)) {
  1659. EPRINTF((TEXT("Read failure. [key data length.]\n")));
  1660. goto Exit6;
  1661. }
  1662. /*
  1663. * Allocate key data buffer
  1664. */
  1665. pBuf = malloc(cb);
  1666. if (pBuf == NULL) {
  1667. MEMFAILED;
  1668. goto Exit6;
  1669. }
  1670. /*
  1671. * Read key data
  1672. */
  1673. if (fread(pBuf, 1, cb, hfIn) != cb || ferror(hfIn)) {
  1674. EPRINTF((TEXT("Read failure. [key data.]\n")));
  1675. Exit7:
  1676. free(pBuf);
  1677. goto Exit6;
  1678. }
  1679. /*
  1680. * Create temp file.
  1681. */
  1682. hfOut = fopen(pszTempFile, "wb");
  1683. if (hfOut == NULL) {
  1684. EPRINTF((TEXT("File open error. [temp file %hs.]\n"),
  1685. pszTempFile));
  1686. goto Exit7;
  1687. }
  1688. /*
  1689. * Write data to temp file
  1690. */
  1691. if (fwrite(pBuf, 1, cb, hfOut) != cb || ferror(hfOut)) {
  1692. EPRINTF((TEXT("Write failure. [temp file data.]\n")));
  1693. Exit8:
  1694. fclose(hfOut);
  1695. goto Exit7;
  1696. }
  1697. /*
  1698. * close temp file
  1699. */
  1700. fclose(hfOut);
  1701. /*
  1702. * load temp file into registry.
  1703. */
  1704. VPRINTF((TEXT(" Loading key %s.\n"),
  1705. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName, &pszTemp1)));
  1706. status = MyRegLoadKey(hKeyRoot, pszSnapshotSubkeyName, pszTempFile);
  1707. if (status != ERROR_SUCCESS) {
  1708. EPRINTF((TEXT("Could not load key %s from %hs. Error=%d.\n"),
  1709. ReuseFullPathFromKey(hKeyRoot, pszSnapshotSubkeyName, &pszTemp1),
  1710. pszTempFile, status));
  1711. goto Exit8;
  1712. }
  1713. status = LogRegCreateKey(HKEY_LOCAL_MACHINE, pszDiffRoot, &hKeyDiffRoot);
  1714. if (status != ERROR_SUCCESS) {
  1715. EPRINTF((TEXT("Could not create %s. Error=%d\n"),
  1716. ReuseFullPathFromKey(HKEY_LOCAL_MACHINE, pszDiffRoot, &pszTemp1),
  1717. status));
  1718. Exit9:
  1719. status = RegUnLoadKey(hKeyRoot, pszSnapshotSubkeyName);
  1720. if (status != ERROR_SUCCESS) {
  1721. EPRINTF((TEXT(" Unloading key %s, Error=%d.\n"),
  1722. ReuseFullPathFromKey(hKeyRoot, pszSnapshotSubkeyName, &pszTemp1),
  1723. status));
  1724. }
  1725. goto Exit8;
  1726. }
  1727. /*
  1728. * Compare nodes and put differences into add and delete keys
  1729. */
  1730. VPRINTF((TEXT(" Diffing node %s.\n"),
  1731. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName, &pszTemp1)));
  1732. if (!DiffNodes(hKeyRoot, pszSnapshotSubkeyName, pszSubkeyName,
  1733. hKeyDiffRoot)) {
  1734. EPRINTF((TEXT("Diff on node %s failed.\n"),
  1735. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName, &pszTemp1)));
  1736. LogRegCloseKey(hKeyDiffRoot);
  1737. //Exit10:
  1738. goto Exit9;
  1739. }
  1740. LogRegCloseKey(hKeyDiffRoot);
  1741. /*
  1742. * unload temporary key node
  1743. */
  1744. VPRINTF((TEXT(" Unloading %s.\n"),
  1745. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName, &pszTemp1)));
  1746. status = RegUnLoadKey(hKeyRoot, pszSnapshotSubkeyName);
  1747. if (status != ERROR_SUCCESS) {
  1748. DPRINTF((TEXT("Unloading key %s, Error=%d.\n"),
  1749. ReuseFullPathFromKey(hKeyRoot, pszSnapshotSubkeyName, &pszTemp1),
  1750. status));
  1751. }
  1752. /*
  1753. * free buffers
  1754. */
  1755. free(pBuf);
  1756. } else {
  1757. /*
  1758. * skip past this snapshot node in the file.
  1759. */
  1760. fseek(hfIn, sizeof(HKEY), SEEK_CUR);
  1761. /*
  1762. * read sizeof key data
  1763. */
  1764. if (fread(&cb, 1, sizeof(DWORD), hfIn) != sizeof(DWORD) || ferror(hfIn)) {
  1765. EPRINTF((TEXT("Read failure. [key data length.]\n")));
  1766. goto Exit6;
  1767. }
  1768. fseek(hfIn, cb, SEEK_CUR);
  1769. }
  1770. free(pszSubkeyName);
  1771. /*
  1772. * delete temp file
  1773. */
  1774. DeleteFileA(pszTempFile);
  1775. }
  1776. /*
  1777. * Close add and delete keys.
  1778. */
  1779. fclose(hfIn);
  1780. /*
  1781. * Make sure all nodes in the include keys list were diffed.
  1782. */
  1783. for (i = 0; i < cIncludeKeys; i++) {
  1784. if (afIncludeKeyMarks[i] == FALSE) {
  1785. WPRINTF((TEXT("Node %s was not included in %hs.\nDiff may be incomplete."),
  1786. ppszIncludeKeys[i], pszSnapFileIn));
  1787. }
  1788. }
  1789. return(TRUE);
  1790. }
  1791. /*
  1792. * Adds values and subkeys found on hKeyInfo to hKeyTarget.
  1793. *
  1794. * Returns fSuccess.
  1795. */
  1796. BOOL AddNodeInfo(
  1797. HKEY hKeyInfo,
  1798. HKEY hKeyTarget)
  1799. {
  1800. DWORD cSubkeys = (DWORD)-1;
  1801. DWORD cchMaxSubkeyName, cValues, cchMaxValueName;
  1802. LPTSTR pszValueName, pszSubkeyName;
  1803. LONG status;
  1804. DWORD i, cch, dwType, cb;
  1805. if (fDebug) {
  1806. DPRINTF((TEXT("AddNodeInfo(%s, %s)\n"),
  1807. ReuseFullPathFromKey(hKeyInfo, (LPCTSTR)NULL, &pszTemp1),
  1808. ReuseFullPathFromKey(hKeyTarget, (LPCTSTR)NULL, &pszTemp2)));
  1809. }
  1810. if (IsKeyWithinNodeList(hKeyTarget, NULL, ppszExceptKeys, cExceptKeys, NULL)) {
  1811. if (fDebug) {
  1812. DPRINTF((TEXT("Key %s was EXCLUDED.\n"),
  1813. ReuseFullPathFromKey(hKeyTarget, (LPCTSTR)NULL, &pszTemp1)));
  1814. }
  1815. return(TRUE); // just fake it - its excluded.
  1816. }
  1817. status = MyRegQueryInfoKey(hKeyInfo, &cSubkeys, &cchMaxSubkeyName,
  1818. &cValues, &cchMaxValueName, NULL, NULL);
  1819. if (status == ERROR_SUCCESS) {
  1820. cchMaxSubkeyName++;
  1821. cchMaxValueName++;
  1822. pszValueName = malloc(cchMaxValueName * sizeof(TCHAR));
  1823. if (pszValueName == NULL) {
  1824. MEMFAILED;
  1825. return(FALSE);
  1826. }
  1827. /*
  1828. * Enumerate all the values and copy them to the target.
  1829. */
  1830. for (i = 0; i < cValues; i++) {
  1831. cch = cchMaxValueName;
  1832. cb = 0;
  1833. status = RegEnumValue(hKeyInfo, i, pszValueName, &cch, NULL, &dwType, NULL, &cb);
  1834. if (status == ERROR_SUCCESS) {
  1835. if (!fSafe) {
  1836. status = CopyKeyValue(hKeyInfo, hKeyTarget, pszValueName);
  1837. } else {
  1838. if (fDebug || fVerbose) {
  1839. WPRINTF((TEXT("Would have copied value \"%s\" to \"%s\".\n"),
  1840. ReuseFullPathFromKey(hKeyInfo, pszValueName, &pszTemp1),
  1841. ReuseFullPathFromKey(hKeyTarget, (LPCTSTR)NULL, &pszTemp2)));
  1842. }
  1843. status = TRUE;
  1844. }
  1845. if (!status) {
  1846. EPRINTF((TEXT("Unable to copy value %s from %s to %s.\n"),
  1847. pszValueName,
  1848. ReuseFullPathFromKey(hKeyInfo, (LPCTSTR)NULL, &pszTemp1),
  1849. ReuseFullPathFromKey(hKeyTarget, (LPCTSTR)NULL, &pszTemp2)));
  1850. }
  1851. } else {
  1852. EPRINTF((TEXT("Could not enumerate value %d of %s.\n"),
  1853. i + 1, ReuseFullPathFromKey(hKeyInfo, (LPCTSTR)NULL, &pszTemp1)));
  1854. }
  1855. }
  1856. free(pszValueName);
  1857. pszSubkeyName = malloc(cchMaxSubkeyName * sizeof(TCHAR));
  1858. if (pszSubkeyName == NULL) {
  1859. MEMFAILED;
  1860. return(0);
  1861. }
  1862. for (i = 0; i < cSubkeys; i++) {
  1863. status = RegEnumKey(hKeyInfo, i, pszSubkeyName, cchMaxSubkeyName);
  1864. if (status == ERROR_SUCCESS) {
  1865. status = CopyKeySubkey(hKeyInfo, pszSubkeyName, hKeyTarget, pszSubkeyName);
  1866. if (!status) {
  1867. EPRINTF((TEXT("Unable to copy subkey %s.\n"), pszSubkeyName));
  1868. }
  1869. } else {
  1870. EPRINTF((TEXT("Could not enumerate value %d of %d.\n"), i + 1, cSubkeys));
  1871. }
  1872. }
  1873. free(pszSubkeyName);
  1874. }
  1875. return(TRUE);
  1876. }
  1877. /*
  1878. * Deletes values and leaf keys found on hKeyInfo from hKeyTarget.
  1879. *
  1880. * Returns:
  1881. * 0 error
  1882. * 1 leaf node
  1883. * 2 nonleaf node
  1884. */
  1885. int DelNodeInfo(
  1886. HKEY hKeyInfo,
  1887. HKEY hKeyTarget)
  1888. {
  1889. DWORD cSubkeys, i, cch, dwType, cb;
  1890. DWORD cchMaxSubkeyName, cValues, cchMaxValueName;
  1891. LPTSTR pszValueName, pszSubkeyName;
  1892. LONG status;
  1893. int iLeafNode;
  1894. iLeafNode = 0;
  1895. if (fDebug) {
  1896. LPTSTR psz1, psz2;
  1897. psz1 = GetFullPathFromKey(hKeyInfo, NULL);
  1898. psz2 = GetFullPathFromKey(hKeyTarget, NULL);
  1899. DPRINTF((TEXT("DelNodeInfo(%s, %s)\n"), psz1, psz2));
  1900. free(psz1);
  1901. free(psz2);
  1902. }
  1903. if (IsKeyWithinNodeList(hKeyTarget, NULL, ppszExceptKeys, cExceptKeys, NULL)) {
  1904. if (fDebug) {
  1905. LPTSTR psz = GetFullPathFromKey(hKeyTarget, NULL);
  1906. DPRINTF((TEXT("Key %s was EXCLUDED.\n"), psz));
  1907. free(psz);
  1908. }
  1909. return(TRUE); // just fake it - its excluded.
  1910. }
  1911. status = MyRegQueryInfoKey(hKeyInfo, &cSubkeys, &cchMaxSubkeyName,
  1912. &cValues, &cchMaxValueName, NULL, NULL);
  1913. if (status == ERROR_SUCCESS) {
  1914. cchMaxSubkeyName++;
  1915. cchMaxValueName++;
  1916. pszValueName = malloc(cchMaxValueName * sizeof(TCHAR));
  1917. if (pszValueName == NULL) {
  1918. MEMFAILED;
  1919. return(0);
  1920. }
  1921. /*
  1922. * Enumerate all the values and delete them from the target.
  1923. */
  1924. for (i = 0; i < cValues; i++) {
  1925. cch = cchMaxValueName;
  1926. cb = 0;
  1927. status = RegEnumValue(hKeyInfo, i, pszValueName, &cch, NULL, &dwType, NULL, &cb);
  1928. if (status == ERROR_SUCCESS) {
  1929. if (!fSafe) {
  1930. status = RegDeleteValue(hKeyTarget, pszValueName);
  1931. } else {
  1932. if (fDebug || fVerbose) {
  1933. LPTSTR psz = GetFullPathFromKey(hKeyTarget, NULL);
  1934. VPRINTF((TEXT("Would have deleted value \"%s\" from \"%s\".\n"),
  1935. pszValueName, psz));
  1936. free(psz);
  1937. }
  1938. status = ERROR_SUCCESS;
  1939. }
  1940. if (status != ERROR_SUCCESS) {
  1941. EPRINTF((TEXT("Unable to delete value %s.\n"), pszValueName));
  1942. }
  1943. } else {
  1944. EPRINTF((TEXT("Could not enumerate value %d of %d.\n"), i + 1, cValues));
  1945. }
  1946. }
  1947. free(pszValueName);
  1948. pszSubkeyName = malloc(cchMaxSubkeyName * sizeof(TCHAR));
  1949. if (pszSubkeyName == NULL) {
  1950. MEMFAILED;
  1951. return(0);
  1952. }
  1953. /*
  1954. * Enumerate all the subkeys and recurse.
  1955. */
  1956. for (i = 0; i < cSubkeys; i++) {
  1957. status = RegEnumKey(hKeyInfo, i, pszSubkeyName, cchMaxSubkeyName);
  1958. if (status == ERROR_SUCCESS) {
  1959. HKEY hSubkeyInfo, hSubkeyTarget;
  1960. status = LogRegOpenKey(hKeyInfo, pszSubkeyName, &hSubkeyInfo);
  1961. if (status == ERROR_SUCCESS) {
  1962. status = LogRegOpenKey(hKeyTarget, pszSubkeyName, &hSubkeyTarget);
  1963. if (status == ERROR_SUCCESS) {
  1964. iLeafNode = DelNodeInfo(hSubkeyInfo, hSubkeyTarget);
  1965. LogRegCloseKey(hSubkeyTarget);
  1966. } else if (status == ERROR_FILE_NOT_FOUND) {
  1967. iLeafNode = 2; // target is gone already.
  1968. } else {
  1969. iLeafNode = 0; // target not accessible.
  1970. EPRINTF((TEXT("%s could not be deleted.\n"), pszSubkeyName));
  1971. }
  1972. LogRegCloseKey(hSubkeyInfo);
  1973. } else {
  1974. iLeafNode = 0; // somethings wrong with our info.
  1975. }
  1976. if (iLeafNode == 1) {
  1977. /*
  1978. * If the key is a leaf, delete it.
  1979. */
  1980. if (!fSafe) {
  1981. status = RegDeleteKey(hKeyTarget, pszSubkeyName); // leaf
  1982. if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
  1983. LPTSTR psz = GetFullPathFromKey(hKeyTarget, NULL);
  1984. EPRINTF((TEXT("Could not delete key \"%s\" from \"%s\".\n"),
  1985. pszSubkeyName, psz));
  1986. free(psz);
  1987. }
  1988. } else if (fDebug || fVerbose) {
  1989. LPTSTR psz = GetFullPathFromKey(hKeyTarget, NULL);
  1990. VPRINTF((TEXT("Would have deleted key \"%s\" from \"%s\"\n"),
  1991. pszSubkeyName, psz));
  1992. free(psz);
  1993. }
  1994. } else if (iLeafNode == 0) {
  1995. /*
  1996. * propigate errors upline.
  1997. */
  1998. free(pszSubkeyName);
  1999. return(0);
  2000. }
  2001. }
  2002. }
  2003. free(pszSubkeyName);
  2004. /*
  2005. * Now reenumerate the TARGET key to find out if its now a leaf.
  2006. */
  2007. MyRegQueryInfoKey(hKeyTarget, &cSubkeys, NULL, &cValues,
  2008. NULL, NULL, NULL);
  2009. if (cSubkeys == 0 && cValues == 0) {
  2010. iLeafNode = 1;
  2011. } else {
  2012. iLeafNode = 2;
  2013. }
  2014. }
  2015. return(iLeafNode);
  2016. }
  2017. /*
  2018. * The DiffRoot contains subkeys of the form:
  2019. * diffroot\add\canonicalkeyname
  2020. * diffroot\del\canonicalkeyname
  2021. *
  2022. * The pszAddKey and pszDelKey allow this function to work in reverse.
  2023. *
  2024. * returns fSuccess.
  2025. */
  2026. BOOL MergeHive(
  2027. LPTSTR pszAddName,
  2028. LPTSTR pszDelName)
  2029. {
  2030. LONG status;
  2031. HKEY hKeyDiffRoot, hKeyRoot, hKey;
  2032. DPRINTF((TEXT("MergeHive(%s, %s)\n"),
  2033. pszAddName, pszDelName));
  2034. status = LogRegOpenKey(HKEY_LOCAL_MACHINE, pszDiffRoot, &hKeyDiffRoot);
  2035. if (status != ERROR_SUCCESS) {
  2036. if (status != ERROR_FILE_NOT_FOUND) {
  2037. EPRINTF((TEXT("Could not open key KEY_LOCAL_MACHINE\\%s. Error=%d.\n"),
  2038. pszDiffRoot, status));
  2039. } else {
  2040. VPRINTF((TEXT("No diff information found.\n")));
  2041. }
  2042. return(FALSE);
  2043. }
  2044. status = LogRegOpenKey(hKeyDiffRoot, pszDelName, &hKeyRoot);
  2045. if (status == ERROR_SUCCESS) {
  2046. status = LogRegOpenKey(hKeyRoot, pszHKEY_LOCAL_MACHINE, &hKey);
  2047. if (status == ERROR_SUCCESS) {
  2048. DelNodeInfo(hKey, HKEY_LOCAL_MACHINE);
  2049. LogRegCloseKey(hKey);
  2050. }
  2051. status = LogRegOpenKey(hKeyRoot, pszHKEY_USERS, &hKey);
  2052. if (status == ERROR_SUCCESS) {
  2053. DelNodeInfo(hKey, HKEY_USERS);
  2054. LogRegCloseKey(hKey);
  2055. }
  2056. LogRegCloseKey(hKeyRoot);
  2057. }
  2058. status = LogRegOpenKey(hKeyDiffRoot, pszAddName, &hKeyRoot);
  2059. if (status == ERROR_SUCCESS) {
  2060. status = LogRegOpenKey(hKeyRoot, pszHKEY_LOCAL_MACHINE, &hKey);
  2061. if (status == ERROR_SUCCESS) {
  2062. AddNodeInfo(hKey, HKEY_LOCAL_MACHINE);
  2063. LogRegCloseKey(hKey);
  2064. }
  2065. status = LogRegOpenKey(hKeyRoot, pszHKEY_USERS, &hKey);
  2066. if (status == ERROR_SUCCESS) {
  2067. AddNodeInfo(hKey, HKEY_USERS);
  2068. LogRegCloseKey(hKey);
  2069. }
  2070. LogRegCloseKey(hKeyRoot);
  2071. }
  2072. LogRegCloseKey(hKeyDiffRoot);
  2073. return(TRUE);
  2074. }
  2075. BOOL ReadNodeListFile(
  2076. LPSTR pszFile,
  2077. LPTSTR **papszNodeList,
  2078. DWORD *pcNodes,
  2079. BOOL **pafNodeMarks)
  2080. {
  2081. FILE *hfIn;
  2082. TCHAR szBuf[MAX_PATH];
  2083. LPTSTR pszEOL, pszRootkey, pszSubkey;
  2084. HKEY hKeyRoot;
  2085. BOOL fFree;
  2086. DPRINTF((TEXT("ReadNodeListFile(%hs)\n"), pszFile));
  2087. *pcNodes = 0;
  2088. if (pafNodeMarks != NULL) {
  2089. *pafNodeMarks = NULL;
  2090. }
  2091. *papszNodeList = NULL;
  2092. hfIn = fopen(pszFile, "r");
  2093. if (hfIn == NULL) {
  2094. EPRINTF((TEXT("Could not read %hs.\n"), pszFile));
  2095. return(FALSE);
  2096. }
  2097. while (!feof(hfIn)) {
  2098. if (fgets((char *)szBuf, MAX_PATH * sizeof(TCHAR), hfIn) == NULL) {
  2099. break;
  2100. }
  2101. #ifdef UNICODE
  2102. {
  2103. WCHAR szwBuf[MAX_PATH];
  2104. _stprintf(szwBuf, TEXT("%hs"), (LPTSTR)szBuf);
  2105. _tcscpy(szBuf, szwBuf);
  2106. }
  2107. #endif
  2108. pszEOL = _tcsrchr(szBuf, TEXT('\n'));
  2109. if (pszEOL == NULL) {
  2110. EPRINTF((TEXT("Line too long in %hs.\n"), pszFile));
  2111. return(FALSE);
  2112. }
  2113. *pszEOL = TEXT('\0');
  2114. if (!KeyPartsFromNodeName(szBuf, &pszRootkey, &pszSubkey, &hKeyRoot, &fFree)) {
  2115. EPRINTF((TEXT("Invalid path %s in %hs.\n"), szBuf, pszFile));
  2116. if (fFree) {
  2117. free(pszSubkey);
  2118. }
  2119. return(FALSE);
  2120. }
  2121. if (*pcNodes == 0) {
  2122. *papszNodeList = malloc(sizeof(LPTSTR));
  2123. if (*papszNodeList == NULL) {
  2124. MEMFAILED;
  2125. return(FALSE);
  2126. }
  2127. } else {
  2128. *papszNodeList = realloc(*papszNodeList, sizeof(LPTSTR) * ((*pcNodes) + 1));
  2129. if (*papszNodeList == NULL) {
  2130. MEMFAILED;
  2131. return(FALSE);
  2132. }
  2133. }
  2134. (*papszNodeList)[*pcNodes] = malloc((_tcslen(pszRootkey) +
  2135. _tcslen(pszSubkey) + 2) * sizeof(TCHAR));
  2136. if ((*papszNodeList)[*pcNodes] == NULL) {
  2137. MEMFAILED;
  2138. return(FALSE);
  2139. }
  2140. _tcscpy((*papszNodeList)[*pcNodes], pszRootkey);
  2141. _tcscat((*papszNodeList)[*pcNodes], TEXT("\\"));
  2142. _tcscat((*papszNodeList)[*pcNodes], pszSubkey);
  2143. DPRINTF((TEXT("Read in %s\n"), (*papszNodeList)[*pcNodes]));
  2144. (*pcNodes)++;
  2145. if (fFree) {
  2146. free(pszSubkey);
  2147. }
  2148. }
  2149. fclose(hfIn);
  2150. if (pafNodeMarks != NULL) {
  2151. *pafNodeMarks = malloc(sizeof(BOOL) * (*pcNodes));
  2152. if (*pafNodeMarks == NULL) {
  2153. MEMFAILED;
  2154. return(FALSE);
  2155. }
  2156. /*
  2157. * Set all NodeMarks to FALSE.
  2158. */
  2159. memset(*pafNodeMarks, 0, sizeof(BOOL) * (*pcNodes));
  2160. }
  2161. return((*pcNodes) != 0);
  2162. }
  2163. __cdecl CDECL main (argc, argv)
  2164. int argc;
  2165. char *argv[];
  2166. {
  2167. DWORD i;
  2168. if (argc == 1) {
  2169. PrintUsage();
  2170. return(1);
  2171. }
  2172. /*
  2173. * find out what the nodename is for the current user (current SID text form)
  2174. * so we can snapshot the current user the same way we do other root nodes.
  2175. */
  2176. pszCurUserSID = GetCurUserSidString();
  2177. if (pszCurUserSID == NULL) {
  2178. EPRINTF((TEXT("Could not get current user SID.\n")));
  2179. return(1);
  2180. }
  2181. DPRINTF((TEXT("Current user Sid:%s\n"), pszCurUserSID));
  2182. /*
  2183. * Set up pszHKEY_CURRENT_USER_Real
  2184. */
  2185. pszHKEY_CURRENT_USER_Real = malloc((_tcslen(pszHKEY_USERS) + 1 +
  2186. _tcslen(pszCurUserSID) + 1) * sizeof(TCHAR));
  2187. if (pszHKEY_CURRENT_USER_Real == NULL) {
  2188. MEMFAILED;
  2189. return(1);
  2190. }
  2191. _tcscpy(pszHKEY_CURRENT_USER_Real, pszHKEY_USERS);
  2192. _tcscat(pszHKEY_CURRENT_USER_Real, TEXT("\\"));
  2193. _tcscat(pszHKEY_CURRENT_USER_Real, pszCurUserSID);
  2194. while (++argv && *argv != NULL) {
  2195. if (*argv[0] == TEXT('-') || *argv[0] == TEXT('/')) {
  2196. switch ((*argv)[1]) {
  2197. case TEXT('s'):
  2198. case TEXT('S'):
  2199. fSnap = TRUE;
  2200. argv++;
  2201. if (*argv == NULL) {
  2202. PrintUsage();
  2203. return(1);
  2204. }
  2205. pszSnapFileOut = *argv;
  2206. break;
  2207. case TEXT('d'):
  2208. case TEXT('D'):
  2209. fDiff = TRUE;
  2210. argv++;
  2211. if (*argv == NULL) {
  2212. PrintUsage();
  2213. return(1);
  2214. }
  2215. pszSnapFileIn = *argv;
  2216. break;
  2217. case TEXT('l'):
  2218. case TEXT('L'):
  2219. fLoadDiffInfo = TRUE;
  2220. argv++;
  2221. if (*argv == NULL) {
  2222. PrintUsage();
  2223. return(1);
  2224. }
  2225. pszDiffFileIn = *argv;
  2226. break;
  2227. case TEXT('w'):
  2228. case TEXT('W'):
  2229. fWriteDiffInfo = TRUE;
  2230. argv++;
  2231. if (*argv == NULL) {
  2232. PrintUsage();
  2233. return(1);
  2234. }
  2235. pszDiffFileOut = *argv;
  2236. break;
  2237. case TEXT('e'):
  2238. case TEXT('E'):
  2239. fEraseInputFileWhenDone = TRUE;
  2240. break;
  2241. case TEXT('m'):
  2242. case TEXT('M'):
  2243. fMerge = TRUE;
  2244. break;
  2245. case TEXT('b'):
  2246. case TEXT('B'):
  2247. fBreak = TRUE;
  2248. break;
  2249. case TEXT('u'):
  2250. case TEXT('U'):
  2251. fUnmerge = TRUE;
  2252. break;
  2253. case TEXT('r'):
  2254. case TEXT('R'):
  2255. fRemoveDiffInfo = TRUE;
  2256. break;
  2257. case TEXT('n'):
  2258. case TEXT('N'):
  2259. fSafe = TRUE;
  2260. break;
  2261. case TEXT('v'):
  2262. case TEXT('V'):
  2263. fVerbose = TRUE;
  2264. break;
  2265. case TEXT('x'):
  2266. case TEXT('X'):
  2267. argv++;
  2268. if (*argv == NULL) {
  2269. PrintUsage();
  2270. return(1);
  2271. }
  2272. if (!ReadNodeListFile(*argv, &ppszExceptKeys,
  2273. &cExceptKeys, NULL)) {
  2274. PrintUsage();
  2275. return(1);
  2276. }
  2277. fExclusionListSpecified = TRUE;
  2278. break;
  2279. case TEXT('i'):
  2280. case TEXT('I'):
  2281. argv++;
  2282. if (*argv == NULL) {
  2283. PrintUsage();
  2284. return(1);
  2285. }
  2286. if (!ReadNodeListFile(*argv, &ppszIncludeKeys,
  2287. &cIncludeKeys, &pfIncludeKeyMarks)) {
  2288. PrintUsage();
  2289. return(1);
  2290. }
  2291. fInclusionListSpecified = TRUE;
  2292. break;
  2293. case TEXT('@'):
  2294. fDebug = TRUE;
  2295. break;
  2296. default:
  2297. PrintUsage();
  2298. return(1);
  2299. }
  2300. } else {
  2301. PrintUsage();
  2302. return(1);
  2303. }
  2304. }
  2305. DPRINTF((TEXT("fEraseInputFileWhenDone = %d\n"), fEraseInputFileWhenDone));
  2306. DPRINTF((TEXT("fSnap = %d\n"), fSnap));
  2307. DPRINTF((TEXT("fDiff = %d\n"), fDiff));
  2308. DPRINTF((TEXT("fMerge = %d\n"), fMerge));
  2309. DPRINTF((TEXT("fUnmerge = %d\n"), fUnmerge));
  2310. DPRINTF((TEXT("fRemoveDiffInfo = %d\n"), fRemoveDiffInfo));
  2311. DPRINTF((TEXT("fWriteDiffInfo = %d\n"), fWriteDiffInfo));
  2312. DPRINTF((TEXT("fDebug = %d\n"), fDebug));
  2313. DPRINTF((TEXT("fVerbose = %d\n"), fVerbose));
  2314. DPRINTF((TEXT("fBreak = %d\n"), fBreak));
  2315. if (pszSnapFileIn != NULL) {
  2316. DPRINTF((TEXT("pszSnapFileIn = %hs\n"), pszSnapFileIn));
  2317. }
  2318. if (pszSnapFileOut != NULL) {
  2319. DPRINTF((TEXT("pszSnapFileOut = %hs\n"), pszSnapFileOut));
  2320. }
  2321. if (pszDiffFileIn != NULL) {
  2322. DPRINTF((TEXT("pszDiffFileIn = %hs\n"), pszDiffFileIn));
  2323. }
  2324. if (pszDiffFileOut != NULL) {
  2325. DPRINTF((TEXT("pszDiffFileOut = %hs\n"), pszDiffFileOut));
  2326. }
  2327. /*
  2328. * The registry APIs need us to get Backup and Restore privileges
  2329. * to work correctly.
  2330. */
  2331. if (!EnablePrivilege(SE_BACKUP_NAME)) {
  2332. EPRINTF((TEXT("Could not gain %s privilege."), SE_BACKUP_NAME));
  2333. return(0);
  2334. }
  2335. if (!EnablePrivilege(SE_RESTORE_NAME)) {
  2336. EPRINTF((TEXT("Could not gain %s privilege."), SE_RESTORE_NAME));
  2337. return(0);
  2338. }
  2339. #if 0 // other privileges that regedit has we may need.
  2340. if (!EnablePrivilege(SE_CHANGE_NOTIFY_NAME)) {
  2341. EPRINTF((TEXT("Could not gain %s privilege."), SE_CHANGE_NOTIFY_NAME));
  2342. return(0);
  2343. }
  2344. if (!EnablePrivilege(SE_SECURITY_NAME)) {
  2345. EPRINTF((TEXT("Could not gain %s privilege."), SE_SECURITY_NAME));
  2346. return(0);
  2347. }
  2348. #endif // 0
  2349. /*
  2350. * Normalize our inlcude and exception lists before we start.
  2351. */
  2352. for (i = 0; i < cExceptKeys; i++) {
  2353. apszExceptKeys[i] = NormalizePathName(ppszExceptKeys[i], NULL);
  2354. }
  2355. for (i = 0; i < cIncludeKeys; i++) {
  2356. apszIncludeKeys[i] = NormalizePathName(ppszIncludeKeys[i], NULL);
  2357. }
  2358. /*
  2359. * Let the debug dudes see the lists.
  2360. */
  2361. if (fDebug) {
  2362. _tprintf(TEXT("\nUsing normalized inclusion list:\n"));
  2363. for (i = 0; i < cIncludeKeys; i++) {
  2364. _tprintf(TEXT(" %s\n"), ppszIncludeKeys[i]);
  2365. }
  2366. _tprintf(TEXT("\nUsing normalized exclusion list:\n"));
  2367. for (i = 0; i < cExceptKeys; i++) {
  2368. _tprintf(TEXT(" %s\n"), ppszExceptKeys[i]);
  2369. }
  2370. }
  2371. /*
  2372. * Make sure snapshot key is unloaded - help insure
  2373. * temp file is useable.
  2374. */
  2375. RegUnLoadKey(HKEY_LOCAL_MACHINE, pszSnapshotSubkeyName);
  2376. RegUnLoadKey(HKEY_USERS, pszSnapshotSubkeyName);
  2377. if (fVerbose) {
  2378. if (fInclusionListSpecified) {
  2379. _tprintf(TEXT("Using inclusion list:\n"));
  2380. for (i = 0; i < cIncludeKeys; i++) {
  2381. _tprintf(TEXT(" %s\n"), ppszIncludeKeys[i]);
  2382. }
  2383. _tprintf(TEXT("\n"));
  2384. }
  2385. if (fExclusionListSpecified) {
  2386. _tprintf(TEXT("Using exception list:\n"));
  2387. for (i = 0; i < cExceptKeys; i++) {
  2388. _tprintf(TEXT(" %s\n"), ppszExceptKeys[i]);
  2389. }
  2390. _tprintf(TEXT("\n"));
  2391. }
  2392. }
  2393. if (fSnap) {
  2394. VPRINTF((TEXT("Snapping registry.\n")));
  2395. SnapHives(pszSnapFileOut);
  2396. _tprintf(TEXT("\n"));
  2397. }
  2398. if (fDiff) {
  2399. VPRINTF((TEXT("Diffing current registry with %hs.\n"), pszSnapFileIn));
  2400. DiffHive(pszSnapFileIn);
  2401. _tprintf(TEXT("\n"));
  2402. } else if (fLoadDiffInfo) {
  2403. LONG status;
  2404. RegUnLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot); // incase a dummy is loaded
  2405. VPRINTF((TEXT("Loading diff info from %hs.\n"), pszDiffFileIn));
  2406. status = MyRegLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot, pszDiffFileIn);
  2407. if (status != ERROR_SUCCESS) {
  2408. EPRINTF((TEXT("Could not load key %s. Error=%d.\n"), pszDiffRoot, status));
  2409. return(0);
  2410. }
  2411. _tprintf(TEXT("\n"));
  2412. }
  2413. if (fLoadDiffInfo && fDiff) {
  2414. WPRINTF((TEXT("Ignoring -l flag. Diff info was already created by diff operation.\n")));
  2415. }
  2416. if (fMerge) {
  2417. VPRINTF((TEXT("Mergeing diff info into current registry.\n")));
  2418. MergeHive(pszAddKey, pszDelKey);
  2419. _tprintf(TEXT("\n"));
  2420. }
  2421. if (fUnmerge) {
  2422. VPRINTF((TEXT("Unmergeing diff info from current registry.\n")));
  2423. MergeHive(pszDelKey, pszAddKey);
  2424. _tprintf(TEXT("\n"));
  2425. }
  2426. if (fWriteDiffInfo) {
  2427. HKEY hKey;
  2428. LONG status;
  2429. DeleteFileA(pszDiffFileOut); // cannot already exist.
  2430. VPRINTF((TEXT("Saving diff info to %hs.\n"), pszDiffFileOut));
  2431. status = LogRegOpenKey(HKEY_LOCAL_MACHINE, pszDiffRoot, &hKey);
  2432. if (status != ERROR_SUCCESS) {
  2433. EPRINTF((TEXT("Could not open key HKEY_LOCAL_MACHINE\\%s. Error=%d.\n"),
  2434. pszDiffRoot, status));
  2435. return(0);
  2436. }
  2437. status = RegSaveKeyA(hKey, pszDiffFileOut, NULL);
  2438. if (status != ERROR_SUCCESS) {
  2439. EPRINTF((TEXT("Could not save key %s. Error=%d.\n"), pszDiffRoot, status));
  2440. return(0);
  2441. }
  2442. LogRegCloseKey(hKey);
  2443. _tprintf(TEXT("\n"));
  2444. }
  2445. if (fEraseInputFileWhenDone) {
  2446. if (pszDiffFileIn != NULL) {
  2447. VPRINTF((TEXT("Erasing diff info file %hs.\n"), pszDiffFileIn));
  2448. DeleteFileA(pszDiffFileIn);
  2449. }
  2450. if (pszSnapFileIn != NULL) {
  2451. VPRINTF((TEXT("Erasing snapshot file %hs.\n"), pszSnapFileIn));
  2452. DeleteFileA(pszSnapFileIn);
  2453. }
  2454. _tprintf(TEXT("\n"));
  2455. }
  2456. if (fRemoveDiffInfo) {
  2457. VPRINTF((TEXT("Unloading diff info from registry.\n")));
  2458. /*
  2459. * Don't leave loaded keys in
  2460. */
  2461. RegUnLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot);
  2462. _tprintf(TEXT("\n"));
  2463. }
  2464. DeleteSidString(pszCurUserSID);
  2465. while (pKeyLogList != NULL) {
  2466. EPRINTF((TEXT("Leftover open key:%x, %x, %s.\n"),
  2467. pKeyLogList->hKey,
  2468. pKeyLogList->hKeyParent,
  2469. pKeyLogList->psz));
  2470. LogRegCloseKey(pKeyLogList->hKey);
  2471. }
  2472. DeleteFileA(pszDummyFile);
  2473. DeleteFileA(pszDummyFileLog);
  2474. DeleteFileA(pszTempFile);
  2475. DeleteFileA(pszTempFile2);
  2476. DeleteFileA(pszTempFileLog);
  2477. DeleteFileA(pszTempFile2Log);
  2478. return(0);
  2479. }