Windows NT 4.0 source code leak
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.

2743 lines
80 KiB

4 years ago
  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. return(FALSE);
  772. }
  773. if (!StoreSubKey(hKeyRoot, pszSubkey, hfOut)) {
  774. EPRINTF((TEXT("Snapshot failed.\n")));
  775. if (fFree) {
  776. free(pszSubkey);
  777. }
  778. return(FALSE);
  779. }
  780. if (fFree) {
  781. free(pszSubkey);
  782. }
  783. }
  784. fclose(hfOut);
  785. VPRINTF((TEXT("Snapshot to %hs completed ok.\n"), pszOutFile));
  786. return(TRUE);
  787. }
  788. /*
  789. * Special string searching code that sees if pszSearch is a proper
  790. * substring of pszData where '?'s in pszSearch match any character in
  791. * pszData. pszData must not be '\' when pszSearch is '?'.
  792. *
  793. * returns fMatched.
  794. */
  795. BOOL substrrexp(
  796. LPCTSTR pszSearch,
  797. LPCTSTR pszData)
  798. {
  799. // DPRINTF(("substrrexp(%s,%s) = ", pszData, pszSearch));
  800. while (*pszData != TEXT('\0') && *pszSearch != TEXT('\0')) {
  801. if (*pszSearch != TEXT('?')) {
  802. if (*pszData != *pszSearch) {
  803. break;
  804. }
  805. } else {
  806. if (*pszData == TEXT('\\')) {
  807. break; // prevents \ from matching a ?
  808. }
  809. }
  810. pszData++;
  811. pszSearch++;
  812. }
  813. // DPRINTF(("%d\n", *pszSearch == TEXT('\0')));
  814. return(*pszSearch == TEXT('\0'));
  815. }
  816. /*
  817. * Searches all the node names in the node list given and sets the
  818. * corresponding afMarkFound[] element to TRUE if hKey\pszSubkey is
  819. * referenced within that node name. Returns TRUE if ANY node names
  820. * reference the subkey name.
  821. *
  822. * afMarkFound may be NULL.
  823. * pszSubkey may be NULL.
  824. */
  825. BOOL IsKeyWithinNodeList(
  826. HKEY hKey,
  827. LPTSTR pszSubkey, // optional
  828. LPTSTR *apszNodes,
  829. DWORD cNodes,
  830. BOOL *afMarkFound) // optional
  831. {
  832. DWORD i;
  833. BOOL fRet;
  834. LPTSTR pszFullName;
  835. fRet = FALSE;
  836. pszFullName = GetFullPathFromKey(hKey, pszSubkey);
  837. if (pszFullName != NULL) {
  838. for (i = 0; i < cNodes; i++) {
  839. if (substrrexp(apszNodes[i], pszFullName) &&
  840. (pszFullName[_tcslen(apszNodes[i])] == TEXT('\\') ||
  841. pszFullName[_tcslen(apszNodes[i])] == TEXT('\0'))) {
  842. fRet = TRUE;
  843. if (afMarkFound != NULL) {
  844. afMarkFound[i] = TRUE;
  845. }
  846. }
  847. if (fRet && afMarkFound == NULL) {
  848. break; // no need to cycle if not marking found nodes.
  849. }
  850. }
  851. free(pszFullName);
  852. }
  853. return(fRet);
  854. }
  855. BOOL CopyKeySubkey(
  856. HKEY hKeyFrom,
  857. LPTSTR pszSubkeyFrom,
  858. HKEY hKeyTo,
  859. LPTSTR pszSubkeyTo)
  860. {
  861. LONG status;
  862. HKEY hSubkeyFrom, hSubkeyTo;
  863. BOOL fRet;
  864. DPRINTF((TEXT("CopyKeySubkey(%s, %s)\n"),
  865. ReuseFullPathFromKey(hKeyFrom, pszSubkeyFrom, &pszTemp1),
  866. ReuseFullPathFromKey(hKeyTo, pszSubkeyTo, &pszTemp2)));
  867. /*
  868. * This key could be in our exclusion list - check first.
  869. */
  870. if (IsKeyWithinNodeList(hKeyFrom, pszSubkeyFrom, ppszExceptKeys, cExceptKeys, NULL)) {
  871. if (fDebug) {
  872. DPRINTF((TEXT("Key %s was EXCLUDED.\n"),
  873. ReuseFullPathFromKey(hKeyFrom, pszSubkeyFrom, &pszTemp1)));
  874. }
  875. return(TRUE); // just fake it - its excluded.
  876. }
  877. if (IsKeyWithinNodeList(hKeyTo, pszSubkeyTo, ppszExceptKeys, cExceptKeys, NULL)) {
  878. if (fDebug) {
  879. DPRINTF((TEXT("Key %s was EXCLUDED.\n"),
  880. ReuseFullPathFromKey(hKeyTo, pszSubkeyTo, &pszTemp1)));
  881. }
  882. return(TRUE); // just fake it - its excluded.
  883. }
  884. if (!fSafe) {
  885. status = LogRegOpenKey(hKeyFrom, pszSubkeyFrom, &hSubkeyFrom);
  886. if (status != ERROR_SUCCESS) {
  887. EPRINTF((TEXT("Could not open key %s. Error=%d.\n"),
  888. ReuseFullPathFromKey(hKeyFrom, pszSubkeyFrom, &pszTemp1), status));
  889. return(FALSE);
  890. }
  891. status = LogRegCreateKey(hKeyTo, pszSubkeyTo, &hSubkeyTo);
  892. if (status != ERROR_SUCCESS) {
  893. EPRINTF((TEXT("Could not create key %s. Error=%d.\n"),
  894. ReuseFullPathFromKey(hKeyTo, pszSubkeyTo, &pszTemp1), status));
  895. return(FALSE);
  896. }
  897. fRet = AddNodeInfo(hSubkeyFrom, hSubkeyTo);
  898. LogRegCloseKey(hSubkeyTo);
  899. LogRegCloseKey(hSubkeyFrom);
  900. } else if (fDebug || fVerbose) {
  901. LPTSTR pszInfo = GetFullPathFromKey(hSubkeyFrom, pszSubkeyFrom);
  902. LPTSTR pszTarget = GetFullPathFromKey(hSubkeyTo, pszSubkeyTo);
  903. VPRINTF((TEXT("Would have copied %s to %s.\n"),
  904. ReuseFullPathFromKey(hKeyFrom, pszSubkeyFrom, &pszTemp1),
  905. ReuseFullPathFromKey(hKeyTo, pszSubkeyTo, &pszTemp2)));
  906. free(pszInfo);
  907. free(pszTarget);
  908. fRet = TRUE;
  909. }
  910. return(fRet);
  911. }
  912. /*
  913. * Combines the pszName entries into one string and passes control on to
  914. * CopyKeySubkey().
  915. */
  916. BOOL CopyKeySubkeyEx(
  917. HKEY hKeyFrom,
  918. LPTSTR pszSubkeyName,
  919. HKEY hKeyTo,
  920. LPTSTR pszNameTo1,
  921. LPTSTR pszNameTo2)
  922. {
  923. LPTSTR psz;
  924. psz = malloc((_tcslen(pszNameTo1) + _tcslen(pszNameTo2) +
  925. _tcslen(pszSubkeyName) + 3) * sizeof(TCHAR));
  926. if (psz == NULL) {
  927. MEMFAILED;
  928. return(FALSE);
  929. }
  930. _tcscpy(psz, pszNameTo1);
  931. _tcscat(psz, TEXT("\\"));
  932. _tcscat(psz, pszNameTo2);
  933. _tcscat(psz, TEXT("\\"));
  934. _tcscat(psz, pszSubkeyName);
  935. if (!CopyKeySubkey(hKeyFrom, pszSubkeyName, hKeyTo, psz)) {
  936. free(psz);
  937. return(FALSE);
  938. }
  939. free(psz);
  940. return(TRUE);
  941. }
  942. BOOL CopyKeyValue(
  943. HKEY hKeyFrom,
  944. HKEY hKeyTo,
  945. LPTSTR pszValue)
  946. {
  947. LONG status;
  948. PVOID pBuf;
  949. DWORD dwType, cbData;
  950. DPRINTF((TEXT("CopyKeyValue(%s, %s, %s)\n"),
  951. ReuseFullPathFromKey(hKeyFrom, NULL, &pszTemp1),
  952. ReuseFullPathFromKey(hKeyTo, NULL, &pszTemp2),
  953. pszValue));
  954. /*
  955. * This key could be in our exclusion list - check first.
  956. */
  957. if (IsKeyWithinNodeList(hKeyFrom, pszValue, ppszExceptKeys, cExceptKeys, NULL)) {
  958. if (fDebug) {
  959. DPRINTF((TEXT("Source Value \"%s\" was EXCLUDED.\n"), pszValue));
  960. }
  961. return(TRUE); // just fake it - its excluded.
  962. }
  963. if (IsKeyWithinNodeList(hKeyTo, pszValue, ppszExceptKeys, cExceptKeys, NULL)) {
  964. if (fDebug) {
  965. DPRINTF((TEXT("Target Value \"%s\" was EXCLUDED.\n"), pszValue));
  966. }
  967. return(TRUE); // just fake it - its excluded.
  968. }
  969. status = RegQueryValueEx(hKeyFrom, pszValue, NULL, &dwType, NULL, &cbData);
  970. if (status != ERROR_SUCCESS) {
  971. EPRINTF((TEXT("Could not query value %s size from %s. Error=%d.\n"),
  972. pszValue, ReuseFullPathFromKey(hKeyFrom, NULL, &pszTemp1),
  973. status));
  974. return(FALSE);
  975. }
  976. pBuf = malloc(cbData);
  977. if (pBuf == NULL) {
  978. MEMFAILED;
  979. return(FALSE);
  980. }
  981. status = RegQueryValueEx(hKeyFrom, pszValue, NULL, &dwType, pBuf, &cbData);
  982. if (status != ERROR_SUCCESS) {
  983. EPRINTF((TEXT("Could not query value %s from %s. Error=%d.\n"),
  984. pszValue, ReuseFullPathFromKey(hKeyFrom, NULL, &pszTemp1),
  985. status));
  986. free(pBuf);
  987. return(FALSE);
  988. }
  989. status = RegSetValueEx(hKeyTo, pszValue, 0, dwType, (BYTE *)pBuf, cbData);
  990. free(pBuf);
  991. if (status == ERROR_SUCCESS) {
  992. return(TRUE);
  993. } else {
  994. EPRINTF((TEXT("Could not set value %s. Error=%d.\n"),
  995. ReuseFullPathFromKey(hKeyTo, pszValue, &pszTemp1), status));
  996. return(FALSE);
  997. }
  998. }
  999. /*
  1000. * Combines the pszName entries into one string and passes control on to
  1001. * CopyKeyValue().
  1002. */
  1003. BOOL CopyKeyValueEx(
  1004. HKEY hKeyFrom,
  1005. LPTSTR pszValueName,
  1006. HKEY hKeyTo,
  1007. LPTSTR pszNameTo1,
  1008. LPTSTR pszNameTo2)
  1009. {
  1010. LPTSTR psz;
  1011. HKEY hKeyToFull;
  1012. LONG status;
  1013. psz = malloc((_tcslen(pszNameTo1) + _tcslen(pszNameTo2) + 2) * sizeof(TCHAR));
  1014. if (psz == NULL) {
  1015. MEMFAILED;
  1016. return(FALSE);
  1017. }
  1018. _tcscpy(psz, pszNameTo1);
  1019. _tcscat(psz, TEXT("\\"));
  1020. _tcscat(psz, pszNameTo2);
  1021. status = LogRegCreateKey(hKeyTo, psz, &hKeyToFull);
  1022. if (status != ERROR_SUCCESS) {
  1023. free(psz);
  1024. return(FALSE);
  1025. }
  1026. free(psz);
  1027. if (!CopyKeyValue(hKeyFrom, hKeyToFull, pszValueName)) {
  1028. EPRINTF((TEXT("Key value %s could not be copied from %s to %s.\n"),
  1029. pszValueName,
  1030. ReuseFullPathFromKey(hKeyFrom, (LPCTSTR)NULL, &pszTemp1),
  1031. ReuseFullPathFromKey(hKeyToFull, (LPCTSTR)NULL, &pszTemp2)));
  1032. LogRegCloseKey(hKeyToFull);
  1033. return(FALSE);
  1034. }
  1035. LogRegCloseKey(hKeyToFull);
  1036. return(TRUE);
  1037. }
  1038. BOOL AreValuesEqual(
  1039. HKEY hSubkey1,
  1040. LPTSTR pszValueName1,
  1041. HKEY hSubkey2,
  1042. LPTSTR pszValueName2)
  1043. {
  1044. LONG status;
  1045. BOOL fRet = FALSE;
  1046. DWORD dwType1, cbData1;
  1047. DWORD dwType2, cbData2;
  1048. PVOID pBuf1, pBuf2;
  1049. DPRINTF((TEXT("AreValuesEqual(%s, %s)\n"),
  1050. ReuseFullPathFromKey(hSubkey1, pszValueName1, &pszTemp1),
  1051. ReuseFullPathFromKey(hSubkey2, pszValueName2, &pszTemp2)));
  1052. status = RegQueryValueEx(hSubkey1, pszValueName1, NULL, &dwType1, NULL, &cbData1);
  1053. if (status != ERROR_SUCCESS) {
  1054. EPRINTF((TEXT("Could not get value size of %s. Error=%d.\n"), pszValueName1, status));
  1055. return(FALSE);
  1056. }
  1057. status = RegQueryValueEx(hSubkey2, pszValueName2, NULL, &dwType2, NULL, &cbData2);
  1058. if (status != ERROR_SUCCESS) {
  1059. EPRINTF((TEXT("Could not get value size of %s. Error=%d.\n"), pszValueName2, status));
  1060. return(FALSE);
  1061. }
  1062. if (dwType1 != dwType2 || cbData1 != cbData2) {
  1063. return(FALSE);
  1064. }
  1065. pBuf1 = malloc(cbData1);
  1066. if (pBuf1 == NULL) {
  1067. MEMFAILED;
  1068. return(FALSE);
  1069. }
  1070. status = RegQueryValueEx(hSubkey1, pszValueName1, NULL, &dwType1, pBuf1, &cbData1);
  1071. if (status != ERROR_SUCCESS) {
  1072. EPRINTF((TEXT("Could not get value %s. Error=%d.\n"), pszValueName1, status));
  1073. goto Exit1;
  1074. }
  1075. pBuf2 = malloc(cbData2);
  1076. if (pBuf2 == NULL) {
  1077. MEMFAILED;
  1078. goto Exit1;
  1079. }
  1080. status = RegQueryValueEx(hSubkey2, pszValueName2, NULL, &dwType2, pBuf2, &cbData2);
  1081. if (status != ERROR_SUCCESS) {
  1082. EPRINTF((TEXT("Could not get value %s. Error=%d.\n"), pszValueName2, status));
  1083. goto Exit2;
  1084. }
  1085. fRet = memcmp(pBuf1, pBuf2, cbData1) == 0;
  1086. Exit2:
  1087. free(pBuf2);
  1088. Exit1:
  1089. free(pBuf1);
  1090. return(fRet);
  1091. }
  1092. int _CRTAPI1 mycmp(
  1093. LPCTSTR *ppsz1,
  1094. LPCTSTR *ppsz2)
  1095. {
  1096. return(_tcscmp(*ppsz1, *ppsz2));
  1097. }
  1098. VOID FreeSortedValues(
  1099. LPTSTR *ppsz,
  1100. DWORD cValues)
  1101. {
  1102. DWORD i;
  1103. if (cValues) {
  1104. for (i = 0; i < cValues; i++) {
  1105. free(ppsz[i]);
  1106. }
  1107. free(ppsz);
  1108. }
  1109. }
  1110. LPTSTR * EnumAndSortValues(
  1111. HKEY hKey,
  1112. DWORD cValues,
  1113. DWORD cchMaxValueName)
  1114. {
  1115. LONG status;
  1116. LPTSTR *ppsz;
  1117. DWORD cch, dwType, cb;
  1118. DWORD i;
  1119. DPRINTF((TEXT("EnumAndSortValues(%s, %d, %d)\n"),
  1120. ReuseFullPathFromKey(hKey, (LPCTSTR)NULL, &pszTemp1),
  1121. cValues,
  1122. cchMaxValueName));
  1123. cchMaxValueName++;
  1124. ppsz = malloc(cValues * sizeof(LPTSTR));
  1125. if (ppsz == NULL) {
  1126. MEMFAILED;
  1127. return(NULL);
  1128. }
  1129. for (i = 0; i < cValues; i++) {
  1130. ppsz[i] = malloc(cchMaxValueName * sizeof(TCHAR));
  1131. if (ppsz[i] == NULL) {
  1132. MEMFAILED;
  1133. if (i > 0) {
  1134. FreeSortedValues(ppsz, i);
  1135. }
  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++; // STUPID 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. if (i > 0) {
  1196. FreeSortedSubkeys(ppsz, i);
  1197. }
  1198. return(NULL);
  1199. }
  1200. cch = cchMaxSubkeyName;
  1201. status = RegEnumKeyEx(hKey, i, ppsz[i], &cch, NULL, NULL, NULL, &ft);
  1202. if (status != ERROR_SUCCESS) {
  1203. if (status != ERROR_NO_MORE_ITEMS) {
  1204. EPRINTF((TEXT("Could not enumerate key %d of %s. Error=%d.\n"),
  1205. i, ReuseFullPathFromKey(hKey, (LPCTSTR)NULL, &pszTemp1), status));
  1206. }
  1207. FreeSortedSubkeys(ppsz, i + 1);
  1208. return(NULL);
  1209. }
  1210. }
  1211. qsort(ppsz, cSubkeys, sizeof(LPTSTR), mycmp);
  1212. if (fDebug && fVerbose) {
  1213. DPRINTF((TEXT("--Subkey List--\n")));
  1214. for (i = 0; i < cSubkeys; i++) {
  1215. DPRINTF((TEXT(" %s\n"), ppsz[i]));
  1216. }
  1217. }
  1218. return(ppsz);
  1219. }
  1220. /*
  1221. * Recursively compares two nodes in the registry and places the added and
  1222. * deleted differences into subnodes of the Diffkey given.
  1223. *
  1224. * Additions go into hRootDiffKey\pszAddKey\<pszSubkeyName1>
  1225. * Deletions go into hRootDiffKey\pszDelKey\<pszSubkeyName1>
  1226. */
  1227. BOOL DiffNodes(
  1228. HKEY hKeyRoot,
  1229. LPTSTR pszSubkeyName1, // Key BEFORE changes (modified name)
  1230. LPTSTR pszSubkeyName2, // Key AFTER changes (original name)
  1231. HKEY hRootDiffKey)
  1232. {
  1233. DWORD status;
  1234. DWORD cSubkeys1, cchMaxSubkey1, cValues1, cchMaxValueName1, cbMaxValueData1;
  1235. DWORD cSubkeys2, cchMaxSubkey2, cValues2, cchMaxValueName2, cbMaxValueData2;
  1236. FILETIME FileTime1, FileTime2;
  1237. HKEY hSubkey1, hSubkey2;
  1238. LPTSTR pszNewSubkeyName1, pszNewSubkeyName2;
  1239. LPTSTR *apszValueName1, *apszValueName2, *apszSubkeyName1, *apszSubkeyName2;
  1240. BOOL fRet;
  1241. DWORD i1, i2;
  1242. int comp;
  1243. LPTSTR pszFullDelKey, pszFullAddKey;
  1244. DPRINTF((TEXT("DiffNodes(%s and %s to %s.)\n"),
  1245. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName1, &pszTemp1),
  1246. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName2, &pszTemp2),
  1247. ReuseFullPathFromKey(hRootDiffKey, (LPCTSTR)NULL, &pszTemp3)));
  1248. if (!GetKeyNameWithPrefix(&pszFullDelKey, hKeyRoot, pszDelKey)) {
  1249. return(FALSE);
  1250. }
  1251. if (!GetKeyNameWithPrefix(&pszFullAddKey, hKeyRoot, pszAddKey)) {
  1252. Exit0:
  1253. free(pszFullDelKey);
  1254. return(FALSE);
  1255. }
  1256. /*
  1257. * Skip it if its in the exception list
  1258. */
  1259. for (i1 = 0; i1 < cExceptKeys; i1++) {
  1260. if (!_tcscmp(pszSubkeyName1, ppszExceptKeys[i1])) {
  1261. DPRINTF((TEXT("Diff on node %s EXCEPTED.\n"),
  1262. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName1, &pszTemp1)));
  1263. return(TRUE);
  1264. }
  1265. }
  1266. /*
  1267. * Open subkeys
  1268. */
  1269. status = LogRegOpenKey(hKeyRoot, pszSubkeyName1, &hSubkey1);
  1270. if (status != ERROR_SUCCESS) {
  1271. EPRINTF((TEXT("Could not open key %s. Error=%d\n"),
  1272. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName1, &pszTemp1),
  1273. status));
  1274. return(FALSE);
  1275. }
  1276. status = LogRegOpenKey(hKeyRoot, pszSubkeyName2, &hSubkey2);
  1277. if (status != ERROR_SUCCESS) {
  1278. EPRINTF((TEXT("Could not open key %s. Error=%d\n"),
  1279. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName2, &pszTemp1),
  1280. status));
  1281. EPRINTF((TEXT("Try adding this key to the exception list.\n")));
  1282. return(FALSE);
  1283. }
  1284. /*
  1285. * Enumerate subkeys
  1286. */
  1287. status = MyRegQueryInfoKey(hSubkey1, &cSubkeys1, &cchMaxSubkey1, &cValues1,
  1288. &cchMaxValueName1, &cbMaxValueData1, &FileTime1);
  1289. if (status != ERROR_SUCCESS) {
  1290. if (status != ERROR_NO_MORE_ITEMS) {
  1291. EPRINTF((TEXT("Could not enumerate key %s. Error=%d.\n"),
  1292. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName1, &pszTemp1),
  1293. status));
  1294. }
  1295. return(FALSE);
  1296. }
  1297. cchMaxSubkey1++;
  1298. cchMaxValueName1++;
  1299. cbMaxValueData1++;
  1300. status = MyRegQueryInfoKey(hSubkey2, &cSubkeys2, &cchMaxSubkey2, &cValues2,
  1301. &cchMaxValueName2, &cbMaxValueData2, &FileTime2);
  1302. if (status != ERROR_SUCCESS) {
  1303. if (status != ERROR_NO_MORE_ITEMS) {
  1304. EPRINTF((TEXT("Could not enumerate key %s. Error=%d.\n"),
  1305. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName2, &pszTemp1),
  1306. status));
  1307. }
  1308. return(FALSE);
  1309. }
  1310. cchMaxSubkey2++;
  1311. cchMaxValueName2++;
  1312. cbMaxValueData2++;
  1313. /*
  1314. * Compare subkey values
  1315. */
  1316. if (CompareFileTime(&FileTime1, &FileTime2)) {
  1317. /*
  1318. * Timestamps differ so values may be different.
  1319. *
  1320. * Enumerate values on nodes, sort, and compare.
  1321. */
  1322. if (cValues1) {
  1323. apszValueName1 = EnumAndSortValues(hSubkey1, cValues1, cchMaxValueName1);
  1324. if (apszValueName1 == NULL) {
  1325. Exit1:
  1326. LogRegCloseKey(hSubkey1);
  1327. LogRegCloseKey(hSubkey2);
  1328. free(pszFullAddKey);
  1329. goto Exit0;
  1330. }
  1331. }
  1332. if (cValues2) {
  1333. apszValueName2 = EnumAndSortValues(hSubkey2, cValues2, cchMaxValueName2);
  1334. if (apszValueName2 == NULL) {
  1335. Exit2:
  1336. FreeSortedValues(apszValueName1, cValues1);
  1337. goto Exit1;
  1338. }
  1339. }
  1340. i1 = i2 = 0;
  1341. while (i1 < cValues1 && i2 < cValues2) {
  1342. comp = _tcscmp(apszValueName1[i1], apszValueName2[i2]);
  1343. if (comp < 0) {
  1344. /*
  1345. * Value1 is NOT in Key2. Add Value1 to Del Node.
  1346. */
  1347. if (!CopyKeyValueEx(hSubkey1, apszValueName1[i1], hRootDiffKey,
  1348. pszFullDelKey, pszSubkeyName2)) {
  1349. Exit3:
  1350. FreeSortedValues(apszValueName2, cValues2);
  1351. goto Exit2;
  1352. }
  1353. i1++;
  1354. } else if (comp > 0) {
  1355. /*
  1356. * Value2 is NOT in Key1, Add Value2 to Add Node.
  1357. */
  1358. if (!CopyKeyValueEx(hSubkey2, apszValueName2[i2], hRootDiffKey,
  1359. pszFullAddKey, pszSubkeyName2)) {
  1360. goto Exit3;
  1361. }
  1362. i2++;
  1363. } else {
  1364. /*
  1365. * Compare data of Value1 and Value2
  1366. */
  1367. if (!AreValuesEqual(hSubkey1, apszValueName1[i1],
  1368. hSubkey2, apszValueName2[i2])) {
  1369. /*
  1370. * Value has changed. Add to both Add and Del nodes.
  1371. */
  1372. if (!CopyKeyValueEx(hSubkey1, apszValueName1[i1], hRootDiffKey,
  1373. pszFullDelKey, pszSubkeyName2)) {
  1374. goto Exit3;
  1375. }
  1376. if (!CopyKeyValueEx(hSubkey2, apszValueName2[i2], hRootDiffKey,
  1377. pszFullAddKey, pszSubkeyName2)) {
  1378. goto Exit3;
  1379. }
  1380. }
  1381. i1++;
  1382. i2++;
  1383. }
  1384. }
  1385. while (i1 < cValues1) {
  1386. if (!CopyKeyValueEx(hSubkey1, apszValueName1[i1], hRootDiffKey,
  1387. pszFullDelKey, pszSubkeyName2)) {
  1388. goto Exit3;
  1389. }
  1390. i1++;
  1391. }
  1392. while (i2 < cValues2) {
  1393. if (!CopyKeyValueEx(hSubkey2, apszValueName2[i2], hRootDiffKey,
  1394. pszFullAddKey, pszSubkeyName2)) {
  1395. goto Exit3;
  1396. }
  1397. i2++;
  1398. }
  1399. FreeSortedValues(apszValueName1, cValues1);
  1400. FreeSortedValues(apszValueName2, cValues2);
  1401. }
  1402. /*
  1403. * Enumerate subkeys and compare.
  1404. */
  1405. if (cSubkeys1) {
  1406. apszSubkeyName1 = EnumAndSortSubkeys(hSubkey1, cSubkeys1, cchMaxSubkey1);
  1407. if (apszSubkeyName1 == NULL) {
  1408. goto Exit1;
  1409. }
  1410. }
  1411. if (cSubkeys2) {
  1412. apszSubkeyName2 = EnumAndSortSubkeys(hSubkey2, cSubkeys2, cchMaxSubkey2);
  1413. if (apszSubkeyName2 == NULL) {
  1414. Exit4:
  1415. FreeSortedSubkeys(apszSubkeyName1, cSubkeys1);
  1416. goto Exit1;
  1417. }
  1418. }
  1419. i1 = i2 = 0;
  1420. while (i1 < cSubkeys1 && i2 < cSubkeys2) {
  1421. comp = _tcscmp(apszSubkeyName1[i1], apszSubkeyName2[i2]);
  1422. if (comp < 0) {
  1423. /*
  1424. * Subkey1 is NOT in Key2. Add Subkey1 to Del Node.
  1425. */
  1426. if (!CopyKeySubkeyEx(hSubkey1, apszSubkeyName1[i1], hRootDiffKey,
  1427. pszFullDelKey, pszSubkeyName2)) {
  1428. Exit5:
  1429. FreeSortedSubkeys(apszSubkeyName2, cSubkeys2);
  1430. goto Exit4;
  1431. }
  1432. i1++;
  1433. } else if (comp > 0) {
  1434. /*
  1435. * Subkey2 is NOT in Key1, Add Subkey2 to Add Node.
  1436. */
  1437. if (!CopyKeySubkeyEx(hSubkey2, apszSubkeyName2[i2], hRootDiffKey,
  1438. pszFullAddKey, pszSubkeyName2)) {
  1439. goto Exit5;
  1440. }
  1441. i2++;
  1442. } else {
  1443. /*
  1444. * Compare subkeys of Subkey1 and Subkey2
  1445. */
  1446. pszNewSubkeyName1 = malloc((_tcslen(pszSubkeyName1) +
  1447. _tcslen(apszSubkeyName1[i1]) + 2) * sizeof(TCHAR));
  1448. if (pszNewSubkeyName1 == NULL) {
  1449. MEMFAILED;
  1450. goto Exit5;
  1451. }
  1452. _tcscpy(pszNewSubkeyName1, pszSubkeyName1);
  1453. _tcscat(pszNewSubkeyName1, TEXT("\\"));
  1454. _tcscat(pszNewSubkeyName1, apszSubkeyName1[i1]);
  1455. pszNewSubkeyName2 = malloc((_tcslen(pszSubkeyName2) +
  1456. _tcslen(apszSubkeyName2[i2]) + 2) * sizeof(TCHAR));
  1457. if (pszNewSubkeyName2 == NULL) {
  1458. MEMFAILED;
  1459. free(pszNewSubkeyName1);
  1460. goto Exit5;
  1461. }
  1462. _tcscpy(pszNewSubkeyName2, pszSubkeyName2);
  1463. _tcscat(pszNewSubkeyName2, TEXT("\\"));
  1464. _tcscat(pszNewSubkeyName2, apszSubkeyName2[i2]);
  1465. fRet = DiffNodes(hKeyRoot, pszNewSubkeyName1, pszNewSubkeyName2,
  1466. hRootDiffKey);
  1467. free(pszNewSubkeyName1);
  1468. free(pszNewSubkeyName2);
  1469. if (fRet == FALSE) {
  1470. goto Exit5;
  1471. }
  1472. i1++;
  1473. i2++;
  1474. }
  1475. }
  1476. while (i1 < cSubkeys1) {
  1477. if (!CopyKeySubkeyEx(hSubkey1, apszSubkeyName1[i1], hRootDiffKey,
  1478. pszFullDelKey, pszSubkeyName2)) {
  1479. goto Exit5;
  1480. }
  1481. i1++;
  1482. }
  1483. while (i2 < cSubkeys2) {
  1484. if (!CopyKeySubkeyEx(hSubkey2, apszSubkeyName2[i2], hRootDiffKey,
  1485. pszFullAddKey, pszSubkeyName2)) {
  1486. goto Exit5;
  1487. }
  1488. i2++;
  1489. }
  1490. FreeSortedSubkeys(apszSubkeyName1, cSubkeys1);
  1491. FreeSortedSubkeys(apszSubkeyName2, cSubkeys2);
  1492. LogRegCloseKey(hSubkey1);
  1493. LogRegCloseKey(hSubkey2);
  1494. free(pszFullAddKey);
  1495. free(pszFullDelKey);
  1496. return(TRUE);
  1497. }
  1498. /*
  1499. * Removes a key and all its subkeys from the registry. Returns fSuccess.
  1500. */
  1501. BOOL DeleteKeyNode(
  1502. HKEY hKey,
  1503. LPCTSTR lpszSubkey)
  1504. {
  1505. LONG status;
  1506. HKEY hSubkey;
  1507. DWORD cSubkeys;
  1508. DWORD cchMaxSubkey;
  1509. DWORD i;
  1510. LPTSTR *apszSubkeyNames;
  1511. if (fDebug) {
  1512. DPRINTF((TEXT("DeleteKeyNode(%s)\n"),
  1513. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1)));
  1514. }
  1515. /*
  1516. * First, just try to delete it. We might just be lucky!
  1517. */
  1518. status = RegDeleteKey(hKey, lpszSubkey);
  1519. if (status == ERROR_SUCCESS || status == ERROR_FILE_NOT_FOUND) {
  1520. return(TRUE);
  1521. }
  1522. /*
  1523. * Ok ok, so we weren't lucky.
  1524. */
  1525. status = LogRegOpenKey(hKey, lpszSubkey, &hSubkey);
  1526. if (status != ERROR_SUCCESS) {
  1527. EPRINTF((TEXT("Could not open key %s for deletion. Error=%d\n"),
  1528. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1), status));
  1529. return(FALSE);
  1530. }
  1531. status = MyRegQueryInfoKey(hSubkey, &cSubkeys, &cchMaxSubkey, NULL, NULL,
  1532. NULL, NULL);
  1533. if (status != ERROR_SUCCESS) {
  1534. EPRINTF((TEXT("Could not get info on key %s for deletion. Error=%d\n"),
  1535. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1), status));
  1536. Exit1:
  1537. LogRegCloseKey(hSubkey);
  1538. return(FALSE);
  1539. }
  1540. cchMaxSubkey++;
  1541. apszSubkeyNames = EnumAndSortSubkeys(hSubkey, cSubkeys, cchMaxSubkey);
  1542. if (apszSubkeyNames == NULL) {
  1543. EPRINTF((TEXT("Could not enumerate key %s for deletion.\n"),
  1544. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1)));
  1545. goto Exit1;
  1546. }
  1547. for (i = 0; i < cSubkeys; i++) {
  1548. DeleteKeyNode(hSubkey, apszSubkeyNames[i]);
  1549. }
  1550. FreeSortedSubkeys(apszSubkeyNames, cSubkeys);
  1551. LogRegCloseKey(hSubkey);
  1552. /*
  1553. * Ok, the key no longer has subkeys so we should be able to delete it now.
  1554. */
  1555. status = RegDeleteKey(hKey, lpszSubkey);
  1556. if (status != ERROR_SUCCESS) {
  1557. EPRINTF((TEXT("Could not delete key %s. Error=%d.\n"),
  1558. ReuseFullPathFromKey(hKey, lpszSubkey, &pszTemp1), status));
  1559. return(FALSE);
  1560. }
  1561. return(TRUE);
  1562. }
  1563. LONG MyRegLoadKey(
  1564. HKEY hKey,
  1565. LPCTSTR pszSubkey,
  1566. LPCSTR pszFile)
  1567. {
  1568. LONG status;
  1569. #ifdef UNICODE
  1570. LPWSTR pszWBuf;
  1571. pszWBuf = malloc((strlen(pszTempFile) + 1) * sizeof(WCHAR));
  1572. if (pszWBuf != NULL) {
  1573. _stprintf(pszWBuf, TEXT("%hs"), pszFile);
  1574. status = RegLoadKey(hKey, pszSubkey, pszWBuf);
  1575. free(pszWBuf);
  1576. } else {
  1577. status = ERROR_NOT_ENOUGH_MEMORY;
  1578. }
  1579. #else
  1580. status = RegLoadKey(hKey, pszSubkey, pszFile);
  1581. #endif // UNICODE
  1582. return(status);
  1583. }
  1584. BOOL DiffHive(
  1585. LPSTR pszSnapFileIn)
  1586. {
  1587. FILE *hfIn, *hfOut;
  1588. LPTSTR pszSubkeyName;
  1589. LPVOID pBuf;
  1590. DWORD cb, i;
  1591. LONG status;
  1592. HKEY hKeyRoot, hKeyDiffRoot;
  1593. DPRINTF((TEXT("DiffHive(%hs)\n"),
  1594. pszSnapFileIn));
  1595. /*
  1596. * remove any diff info laying around in the registry.
  1597. */
  1598. RegUnLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot);
  1599. DeleteKeyNode(HKEY_LOCAL_MACHINE, pszDiffRoot);
  1600. /*
  1601. * Load an empty file to create the regdiff key off of the
  1602. * HKEY_LOCAL_MACHINE root key.
  1603. * (a hack that should not be necessary!)
  1604. */
  1605. DeleteFileA(pszDummyFile);
  1606. status = MyRegLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot, pszDummyFile);
  1607. if (status != ERROR_SUCCESS) {
  1608. EPRINTF((TEXT("Unable to load %s\\%s from %hs.\n"),
  1609. pszHKEY_LOCAL_MACHINE, pszDiffRoot, pszDummyFile));
  1610. return(FALSE);
  1611. }
  1612. /*
  1613. * Open snapshot file
  1614. */
  1615. hfIn = fopen(pszSnapFileIn, "rb");
  1616. if (hfIn == NULL) {
  1617. EPRINTF((TEXT("Could not open %hs.\n"), pszSnapFileIn));
  1618. return(FALSE);
  1619. }
  1620. /*
  1621. * for each section...
  1622. */
  1623. DeleteFileA(pszTempFile); // RegSaveKey will fail if this exists.
  1624. while(fread(&cb, 1, sizeof(DWORD), hfIn) == sizeof(DWORD) && !ferror(hfIn)) {
  1625. /*
  1626. * alocate a buffer for full key name.
  1627. */
  1628. pszSubkeyName = malloc(cb);
  1629. if (pszSubkeyName == NULL) {
  1630. MEMFAILED;
  1631. Exit4:
  1632. fclose(hfIn);
  1633. return(FALSE);
  1634. }
  1635. /*
  1636. * read full key name
  1637. */
  1638. if (fread(pszSubkeyName, 1, cb, hfIn) != cb || ferror(hfIn)) {
  1639. EPRINTF((TEXT("Read failure. [key name.]\n")));
  1640. Exit6:
  1641. free(pszSubkeyName);
  1642. goto Exit4;
  1643. }
  1644. /*
  1645. * read root key handle
  1646. */
  1647. if (fread(&hKeyRoot, 1, sizeof(HKEY), hfIn) != sizeof(HKEY) || ferror(hfIn)) {
  1648. EPRINTF((TEXT("Read failure. [Root key handle.]\n")));
  1649. goto Exit6;
  1650. }
  1651. /*
  1652. * Find out if pszSubkeyName is covered by our include key list.
  1653. * If so, do a diff on it.
  1654. */
  1655. if (IsKeyWithinNodeList(hKeyRoot, pszSubkeyName, ppszIncludeKeys,
  1656. cIncludeKeys, afIncludeKeyMarks)) {
  1657. /*
  1658. * read sizeof key data
  1659. */
  1660. if (fread(&cb, 1, sizeof(DWORD), hfIn) != sizeof(DWORD) || ferror(hfIn)) {
  1661. EPRINTF((TEXT("Read failure. [key data length.]\n")));
  1662. goto Exit6;
  1663. }
  1664. /*
  1665. * Allocate key data buffer
  1666. */
  1667. pBuf = malloc(cb);
  1668. if (pBuf == NULL) {
  1669. MEMFAILED;
  1670. goto Exit6;
  1671. }
  1672. /*
  1673. * Read key data
  1674. */
  1675. if (fread(pBuf, 1, cb, hfIn) != cb || ferror(hfIn)) {
  1676. EPRINTF((TEXT("Read failure. [key data.]\n")));
  1677. Exit7:
  1678. free(pBuf);
  1679. goto Exit6;
  1680. }
  1681. /*
  1682. * Create temp file.
  1683. */
  1684. hfOut = fopen(pszTempFile, "wb");
  1685. if (hfOut == NULL) {
  1686. EPRINTF((TEXT("File open error. [temp file %hs.]\n"),
  1687. pszTempFile));
  1688. goto Exit7;
  1689. }
  1690. /*
  1691. * Write data to temp file
  1692. */
  1693. if (fwrite(pBuf, 1, cb, hfOut) != cb || ferror(hfOut)) {
  1694. EPRINTF((TEXT("Write failure. [temp file data.]\n")));
  1695. Exit8:
  1696. fclose(hfOut);
  1697. goto Exit7;
  1698. }
  1699. /*
  1700. * close temp file
  1701. */
  1702. fclose(hfOut);
  1703. /*
  1704. * load temp file into registry.
  1705. */
  1706. VPRINTF((TEXT(" Loading key %s.\n"),
  1707. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName, &pszTemp1)));
  1708. status = MyRegLoadKey(hKeyRoot, pszSnapshotSubkeyName, pszTempFile);
  1709. if (status != ERROR_SUCCESS) {
  1710. EPRINTF((TEXT("Could not load key %s from %hs. Error=%d.\n"),
  1711. ReuseFullPathFromKey(hKeyRoot, pszSnapshotSubkeyName, &pszTemp1),
  1712. pszTempFile, status));
  1713. goto Exit8;
  1714. }
  1715. status = LogRegCreateKey(HKEY_LOCAL_MACHINE, pszDiffRoot, &hKeyDiffRoot);
  1716. if (status != ERROR_SUCCESS) {
  1717. EPRINTF((TEXT("Could not create %s. Error=%d\n"),
  1718. ReuseFullPathFromKey(HKEY_LOCAL_MACHINE, pszDiffRoot, &pszTemp1),
  1719. status));
  1720. Exit9:
  1721. status = RegUnLoadKey(hKeyRoot, pszSnapshotSubkeyName);
  1722. if (status != ERROR_SUCCESS) {
  1723. EPRINTF((TEXT(" Unloading key %s, Error=%d.\n"),
  1724. ReuseFullPathFromKey(hKeyRoot, pszSnapshotSubkeyName, &pszTemp1),
  1725. status));
  1726. }
  1727. goto Exit8;
  1728. }
  1729. /*
  1730. * Compare nodes and put differences into add and delete keys
  1731. */
  1732. VPRINTF((TEXT(" Diffing node %s.\n"),
  1733. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName, &pszTemp1)));
  1734. if (!DiffNodes(hKeyRoot, pszSnapshotSubkeyName, pszSubkeyName,
  1735. hKeyDiffRoot)) {
  1736. EPRINTF((TEXT("Diff on node %s failed.\n"),
  1737. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName, &pszTemp1)));
  1738. LogRegCloseKey(hKeyDiffRoot);
  1739. //Exit10:
  1740. goto Exit9;
  1741. }
  1742. LogRegCloseKey(hKeyDiffRoot);
  1743. /*
  1744. * unload temporary key node
  1745. */
  1746. VPRINTF((TEXT(" Unloading %s.\n"),
  1747. ReuseFullPathFromKey(hKeyRoot, pszSubkeyName, &pszTemp1)));
  1748. status = RegUnLoadKey(hKeyRoot, pszSnapshotSubkeyName);
  1749. if (status != ERROR_SUCCESS) {
  1750. DPRINTF((TEXT("Unloading key %s, Error=%d.\n"),
  1751. ReuseFullPathFromKey(hKeyRoot, pszSnapshotSubkeyName, &pszTemp1),
  1752. status));
  1753. }
  1754. /*
  1755. * free buffers
  1756. */
  1757. free(pBuf);
  1758. } else {
  1759. /*
  1760. * skip past this snapshot node in the file.
  1761. */
  1762. fseek(hfIn, sizeof(HKEY), SEEK_CUR);
  1763. /*
  1764. * read sizeof key data
  1765. */
  1766. if (fread(&cb, 1, sizeof(DWORD), hfIn) != sizeof(DWORD) || ferror(hfIn)) {
  1767. EPRINTF((TEXT("Read failure. [key data length.]\n")));
  1768. goto Exit6;
  1769. }
  1770. fseek(hfIn, cb, SEEK_CUR);
  1771. }
  1772. free(pszSubkeyName);
  1773. /*
  1774. * delete temp file
  1775. */
  1776. DeleteFileA(pszTempFile);
  1777. }
  1778. /*
  1779. * Close add and delete keys.
  1780. */
  1781. fclose(hfIn);
  1782. /*
  1783. * Make sure all nodes in the include keys list were diffed.
  1784. */
  1785. for (i = 0; i < cIncludeKeys; i++) {
  1786. if (afIncludeKeyMarks[i] == FALSE) {
  1787. WPRINTF((TEXT("Node %s was not included in %hs.\nDiff may be incomplete."),
  1788. ppszIncludeKeys[i], pszSnapFileIn));
  1789. }
  1790. }
  1791. return(TRUE);
  1792. }
  1793. /*
  1794. * Adds values and subkeys found on hKeyInfo to hKeyTarget.
  1795. *
  1796. * Returns fSuccess.
  1797. */
  1798. BOOL AddNodeInfo(
  1799. HKEY hKeyInfo,
  1800. HKEY hKeyTarget)
  1801. {
  1802. DWORD cSubkeys = (DWORD)-1;
  1803. DWORD cchMaxSubkeyName, cValues, cchMaxValueName;
  1804. LPTSTR pszValueName, pszSubkeyName;
  1805. LONG status;
  1806. DWORD i, cch, dwType, cb;
  1807. if (fDebug) {
  1808. DPRINTF((TEXT("AddNodeInfo(%s, %s)\n"),
  1809. ReuseFullPathFromKey(hKeyInfo, (LPCTSTR)NULL, &pszTemp1),
  1810. ReuseFullPathFromKey(hKeyTarget, (LPCTSTR)NULL, &pszTemp2)));
  1811. }
  1812. if (IsKeyWithinNodeList(hKeyTarget, NULL, ppszExceptKeys, cExceptKeys, NULL)) {
  1813. if (fDebug) {
  1814. DPRINTF((TEXT("Key %s was EXCLUDED.\n"),
  1815. ReuseFullPathFromKey(hKeyTarget, (LPCTSTR)NULL, &pszTemp1)));
  1816. }
  1817. return(TRUE); // just fake it - its excluded.
  1818. }
  1819. status = MyRegQueryInfoKey(hKeyInfo, &cSubkeys, &cchMaxSubkeyName,
  1820. &cValues, &cchMaxValueName, NULL, NULL);
  1821. if (status == ERROR_SUCCESS) {
  1822. cchMaxSubkeyName++;
  1823. cchMaxValueName++;
  1824. pszValueName = malloc(cchMaxValueName * sizeof(TCHAR));
  1825. if (pszValueName == NULL) {
  1826. MEMFAILED;
  1827. return(FALSE);
  1828. }
  1829. /*
  1830. * Enumerate all the values and copy them to the target.
  1831. */
  1832. for (i = 0; i < cValues; i++) {
  1833. cch = cchMaxValueName;
  1834. cb = 0;
  1835. status = RegEnumValue(hKeyInfo, i, pszValueName, &cch, NULL, &dwType, NULL, &cb);
  1836. if (status == ERROR_SUCCESS) {
  1837. if (!fSafe) {
  1838. status = CopyKeyValue(hKeyInfo, hKeyTarget, pszValueName);
  1839. } else {
  1840. if (fDebug || fVerbose) {
  1841. WPRINTF((TEXT("Would have copied value \"%s\" to \"%s\".\n"),
  1842. ReuseFullPathFromKey(hKeyInfo, pszValueName, &pszTemp1),
  1843. ReuseFullPathFromKey(hKeyTarget, (LPCTSTR)NULL, &pszTemp2)));
  1844. }
  1845. status = TRUE;
  1846. }
  1847. if (!status) {
  1848. EPRINTF((TEXT("Unable to copy value %s from %s to %s.\n"),
  1849. pszValueName,
  1850. ReuseFullPathFromKey(hKeyInfo, (LPCTSTR)NULL, &pszTemp1),
  1851. ReuseFullPathFromKey(hKeyTarget, (LPCTSTR)NULL, &pszTemp2)));
  1852. }
  1853. } else {
  1854. EPRINTF((TEXT("Could not enumerate value %d of %s.\n"),
  1855. i + 1, ReuseFullPathFromKey(hKeyInfo, (LPCTSTR)NULL, &pszTemp1)));
  1856. }
  1857. }
  1858. free(pszValueName);
  1859. pszSubkeyName = malloc(cchMaxSubkeyName * sizeof(TCHAR));
  1860. if (pszSubkeyName == NULL) {
  1861. MEMFAILED;
  1862. return(0);
  1863. }
  1864. for (i = 0; i < cSubkeys; i++) {
  1865. status = RegEnumKey(hKeyInfo, i, pszSubkeyName, cchMaxSubkeyName);
  1866. if (status == ERROR_SUCCESS) {
  1867. status = CopyKeySubkey(hKeyInfo, pszSubkeyName, hKeyTarget, pszSubkeyName);
  1868. if (!status) {
  1869. EPRINTF((TEXT("Unable to copy subkey %s.\n"), pszSubkeyName));
  1870. }
  1871. } else {
  1872. EPRINTF((TEXT("Could not enumerate value %d of %d.\n"), i + 1, cSubkeys));
  1873. }
  1874. }
  1875. free(pszSubkeyName);
  1876. }
  1877. return(TRUE);
  1878. }
  1879. /*
  1880. * Deletes values and leaf keys found on hKeyInfo from hKeyTarget.
  1881. *
  1882. * Returns:
  1883. * 0 error
  1884. * 1 leaf node
  1885. * 2 nonleaf node
  1886. */
  1887. int DelNodeInfo(
  1888. HKEY hKeyInfo,
  1889. HKEY hKeyTarget)
  1890. {
  1891. DWORD cSubkeys, i, cch, dwType, cb;
  1892. DWORD cchMaxSubkeyName, cValues, cchMaxValueName;
  1893. LPTSTR pszValueName, pszSubkeyName;
  1894. LONG status;
  1895. int iLeafNode;
  1896. if (fDebug) {
  1897. LPTSTR psz1, psz2;
  1898. psz1 = GetFullPathFromKey(hKeyInfo, NULL);
  1899. psz2 = GetFullPathFromKey(hKeyTarget, NULL);
  1900. DPRINTF((TEXT("DelNodeInfo(%s, %s)\n"), psz1, psz2));
  1901. free(psz1);
  1902. free(psz2);
  1903. }
  1904. if (IsKeyWithinNodeList(hKeyTarget, NULL, ppszExceptKeys, cExceptKeys, NULL)) {
  1905. if (fDebug) {
  1906. LPTSTR psz = GetFullPathFromKey(hKeyTarget, NULL);
  1907. DPRINTF((TEXT("Key %s was EXCLUDED.\n"), psz));
  1908. free(psz);
  1909. }
  1910. return(TRUE); // just fake it - its excluded.
  1911. }
  1912. status = MyRegQueryInfoKey(hKeyInfo, &cSubkeys, &cchMaxSubkeyName,
  1913. &cValues, &cchMaxValueName, NULL, NULL);
  1914. if (status == ERROR_SUCCESS) {
  1915. cchMaxSubkeyName++;
  1916. cchMaxValueName++;
  1917. pszValueName = malloc(cchMaxValueName * sizeof(TCHAR));
  1918. if (pszValueName == NULL) {
  1919. MEMFAILED;
  1920. return(0);
  1921. }
  1922. /*
  1923. * Enumerate all the values and delete them from the target.
  1924. */
  1925. for (i = 0; i < cValues; i++) {
  1926. cch = cchMaxValueName;
  1927. cb = 0;
  1928. status = RegEnumValue(hKeyInfo, i, pszValueName, &cch, NULL, &dwType, NULL, &cb);
  1929. if (status == ERROR_SUCCESS) {
  1930. if (!fSafe) {
  1931. status = RegDeleteValue(hKeyTarget, pszValueName);
  1932. } else {
  1933. if (fDebug || fVerbose) {
  1934. LPTSTR psz = GetFullPathFromKey(hKeyTarget, NULL);
  1935. VPRINTF((TEXT("Would have deleted value \"%s\" from \"%s\".\n"),
  1936. pszValueName, psz));
  1937. free(psz);
  1938. }
  1939. status = ERROR_SUCCESS;
  1940. }
  1941. if (status != ERROR_SUCCESS) {
  1942. EPRINTF((TEXT("Unable to delete value %s.\n"), pszValueName));
  1943. }
  1944. } else {
  1945. EPRINTF((TEXT("Could not enumerate value %d of %d.\n"), i + 1, cValues));
  1946. }
  1947. }
  1948. free(pszValueName);
  1949. pszSubkeyName = malloc(cchMaxSubkeyName * sizeof(TCHAR));
  1950. if (pszSubkeyName == NULL) {
  1951. MEMFAILED;
  1952. return(0);
  1953. }
  1954. /*
  1955. * Enumerate all the subkeys and recurse.
  1956. */
  1957. for (i = 0; i < cSubkeys; i++) {
  1958. status = RegEnumKey(hKeyInfo, i, pszSubkeyName, cchMaxSubkeyName);
  1959. if (status == ERROR_SUCCESS) {
  1960. HKEY hSubkeyInfo, hSubkeyTarget;
  1961. status = LogRegOpenKey(hKeyInfo, pszSubkeyName, &hSubkeyInfo);
  1962. if (status == ERROR_SUCCESS) {
  1963. status = LogRegOpenKey(hKeyTarget, pszSubkeyName, &hSubkeyTarget);
  1964. if (status == ERROR_SUCCESS) {
  1965. iLeafNode = DelNodeInfo(hSubkeyInfo, hSubkeyTarget);
  1966. LogRegCloseKey(hSubkeyTarget);
  1967. } else if (status == ERROR_FILE_NOT_FOUND) {
  1968. iLeafNode = 2; // target is gone already.
  1969. } else {
  1970. iLeafNode = 0; // target not accessible.
  1971. EPRINTF((TEXT("%s could not be deleted.\n"), pszSubkeyName));
  1972. }
  1973. LogRegCloseKey(hSubkeyInfo);
  1974. } else {
  1975. iLeafNode = 0; // somethings wrong with our info.
  1976. }
  1977. if (iLeafNode == 1) {
  1978. /*
  1979. * If the key is a leaf, delete it.
  1980. */
  1981. if (!fSafe) {
  1982. status = RegDeleteKey(hKeyTarget, pszSubkeyName); // leaf
  1983. if (status != ERROR_SUCCESS && status != ERROR_FILE_NOT_FOUND) {
  1984. LPTSTR psz = GetFullPathFromKey(hKeyTarget, NULL);
  1985. EPRINTF((TEXT("Could not delete key \"%s\" from \"%s\".\n"),
  1986. pszSubkeyName, psz));
  1987. free(psz);
  1988. }
  1989. } else if (fDebug || fVerbose) {
  1990. LPTSTR psz = GetFullPathFromKey(hKeyTarget, NULL);
  1991. VPRINTF((TEXT("Would have deleted key \"%s\" from \"%s\"\n"),
  1992. pszSubkeyName, psz));
  1993. free(psz);
  1994. }
  1995. } else if (iLeafNode == 0) {
  1996. /*
  1997. * propigate errors upline.
  1998. */
  1999. free(pszSubkeyName);
  2000. return(0);
  2001. }
  2002. }
  2003. }
  2004. free(pszSubkeyName);
  2005. /*
  2006. * Now reenumerate the TARGET key to find out if its now a leaf.
  2007. */
  2008. MyRegQueryInfoKey(hKeyTarget, &cSubkeys, NULL, &cValues,
  2009. NULL, NULL, NULL);
  2010. if (cSubkeys == 0 && cValues == 0) {
  2011. iLeafNode = 1;
  2012. } else {
  2013. iLeafNode = 2;
  2014. }
  2015. }
  2016. return(iLeafNode);
  2017. }
  2018. /*
  2019. * The DiffRoot contains subkeys of the form:
  2020. * diffroot\add\canonicalkeyname
  2021. * diffroot\del\canonicalkeyname
  2022. *
  2023. * The pszAddKey and pszDelKey allow this function to work in reverse.
  2024. *
  2025. * returns fSuccess.
  2026. */
  2027. BOOL MergeHive(
  2028. LPTSTR pszAddName,
  2029. LPTSTR pszDelName)
  2030. {
  2031. LONG status;
  2032. HKEY hKeyDiffRoot, hKeyRoot, hKey;
  2033. DPRINTF((TEXT("MergeHive(%s, %s)\n"),
  2034. pszAddName, pszDelName));
  2035. status = LogRegOpenKey(HKEY_LOCAL_MACHINE, pszDiffRoot, &hKeyDiffRoot);
  2036. if (status != ERROR_SUCCESS) {
  2037. if (status != ERROR_FILE_NOT_FOUND) {
  2038. EPRINTF((TEXT("Could not open key KEY_LOCAL_MACHINE\\%s. Error=%d.\n"),
  2039. pszDiffRoot, status));
  2040. } else {
  2041. VPRINTF((TEXT("No diff information found.\n")));
  2042. }
  2043. return(FALSE);
  2044. }
  2045. status = LogRegOpenKey(hKeyDiffRoot, pszDelName, &hKeyRoot);
  2046. if (status == ERROR_SUCCESS) {
  2047. status = LogRegOpenKey(hKeyRoot, pszHKEY_LOCAL_MACHINE, &hKey);
  2048. if (status == ERROR_SUCCESS) {
  2049. DelNodeInfo(hKey, HKEY_LOCAL_MACHINE);
  2050. LogRegCloseKey(hKey);
  2051. }
  2052. status = LogRegOpenKey(hKeyRoot, pszHKEY_USERS, &hKey);
  2053. if (status == ERROR_SUCCESS) {
  2054. DelNodeInfo(hKey, HKEY_USERS);
  2055. LogRegCloseKey(hKey);
  2056. }
  2057. LogRegCloseKey(hKeyRoot);
  2058. }
  2059. status = LogRegOpenKey(hKeyDiffRoot, pszAddName, &hKeyRoot);
  2060. if (status == ERROR_SUCCESS) {
  2061. status = LogRegOpenKey(hKeyRoot, pszHKEY_LOCAL_MACHINE, &hKey);
  2062. if (status == ERROR_SUCCESS) {
  2063. AddNodeInfo(hKey, HKEY_LOCAL_MACHINE);
  2064. LogRegCloseKey(hKey);
  2065. }
  2066. status = LogRegOpenKey(hKeyRoot, pszHKEY_USERS, &hKey);
  2067. if (status == ERROR_SUCCESS) {
  2068. AddNodeInfo(hKey, HKEY_USERS);
  2069. LogRegCloseKey(hKey);
  2070. }
  2071. LogRegCloseKey(hKeyRoot);
  2072. }
  2073. LogRegCloseKey(hKeyDiffRoot);
  2074. return(TRUE);
  2075. }
  2076. BOOL ReadNodeListFile(
  2077. LPSTR pszFile,
  2078. LPTSTR **papszNodeList,
  2079. DWORD *pcNodes,
  2080. BOOL **pafNodeMarks)
  2081. {
  2082. FILE *hfIn;
  2083. TCHAR szBuf[MAX_PATH];
  2084. LPTSTR pszEOL, pszRootkey, pszSubkey;
  2085. HKEY hKeyRoot;
  2086. BOOL fFree;
  2087. DPRINTF((TEXT("ReadNodeListFile(%hs)\n"), pszFile));
  2088. *pcNodes = 0;
  2089. if (pafNodeMarks != NULL) {
  2090. *pafNodeMarks = NULL;
  2091. }
  2092. *papszNodeList = NULL;
  2093. hfIn = fopen(pszFile, "r");
  2094. if (hfIn == NULL) {
  2095. EPRINTF((TEXT("Could not read %hs.\n"), pszFile));
  2096. return(FALSE);
  2097. }
  2098. while (!feof(hfIn)) {
  2099. if (fgets((char *)szBuf, MAX_PATH * sizeof(TCHAR), hfIn) == NULL) {
  2100. break;
  2101. }
  2102. #ifdef UNICODE
  2103. {
  2104. WCHAR szwBuf[MAX_PATH];
  2105. _stprintf(szwBuf, TEXT("%hs"), (LPTSTR)szBuf);
  2106. _tcscpy(szBuf, szwBuf);
  2107. }
  2108. #endif
  2109. pszEOL = _tcsrchr(szBuf, TEXT('\n'));
  2110. if (pszEOL == NULL) {
  2111. EPRINTF((TEXT("Line too long in %hs.\n"), pszFile));
  2112. return(FALSE);
  2113. }
  2114. *pszEOL = TEXT('\0');
  2115. if (!KeyPartsFromNodeName(szBuf, &pszRootkey, &pszSubkey, &hKeyRoot, &fFree)) {
  2116. EPRINTF((TEXT("Invalid path %s in %hs.\n"), szBuf, pszFile));
  2117. if (fFree) {
  2118. free(pszSubkey);
  2119. }
  2120. return(FALSE);
  2121. }
  2122. if (*pcNodes == 0) {
  2123. *papszNodeList = malloc(sizeof(LPTSTR));
  2124. if (*papszNodeList == NULL) {
  2125. MEMFAILED;
  2126. return(FALSE);
  2127. }
  2128. } else {
  2129. *papszNodeList = realloc(*papszNodeList, sizeof(LPTSTR) * ((*pcNodes) + 1));
  2130. if (*papszNodeList == NULL) {
  2131. MEMFAILED;
  2132. return(FALSE);
  2133. }
  2134. }
  2135. (*papszNodeList)[*pcNodes] = malloc((_tcslen(pszRootkey) +
  2136. _tcslen(pszSubkey) + 2) * sizeof(TCHAR));
  2137. if ((*papszNodeList)[*pcNodes] == NULL) {
  2138. MEMFAILED;
  2139. return(FALSE);
  2140. }
  2141. _tcscpy((*papszNodeList)[*pcNodes], pszRootkey);
  2142. _tcscat((*papszNodeList)[*pcNodes], TEXT("\\"));
  2143. _tcscat((*papszNodeList)[*pcNodes], pszSubkey);
  2144. DPRINTF((TEXT("Read in %s\n"), (*papszNodeList)[*pcNodes]));
  2145. (*pcNodes)++;
  2146. if (fFree) {
  2147. free(pszSubkey);
  2148. }
  2149. }
  2150. fclose(hfIn);
  2151. if (pafNodeMarks != NULL) {
  2152. *pafNodeMarks = malloc(sizeof(BOOL) * (*pcNodes));
  2153. if (*pafNodeMarks == NULL) {
  2154. MEMFAILED;
  2155. return(FALSE);
  2156. }
  2157. /*
  2158. * Set all NodeMarks to FALSE.
  2159. */
  2160. memset(*pafNodeMarks, 0, sizeof(BOOL) * (*pcNodes));
  2161. }
  2162. return((*pcNodes) != 0);
  2163. }
  2164. _CRTAPI1 CDECL main (argc, argv)
  2165. int argc;
  2166. char *argv[];
  2167. {
  2168. DWORD i;
  2169. if (argc == 1) {
  2170. PrintUsage();
  2171. return(1);
  2172. }
  2173. /*
  2174. * find out what the nodename is for the current user (current SID text form)
  2175. * so we can snapshot the current user the same way we do other root nodes.
  2176. */
  2177. pszCurUserSID = GetCurUserSidString();
  2178. if (pszCurUserSID == NULL) {
  2179. EPRINTF((TEXT("Could not get current user SID.\n")));
  2180. return(1);
  2181. }
  2182. DPRINTF((TEXT("Current user Sid:%s\n"), pszCurUserSID));
  2183. /*
  2184. * Set up pszHKEY_CURRENT_USER_Real
  2185. */
  2186. pszHKEY_CURRENT_USER_Real = malloc((_tcslen(pszHKEY_USERS) + 1 +
  2187. _tcslen(pszCurUserSID) + 1) * sizeof(TCHAR));
  2188. if (pszHKEY_CURRENT_USER_Real == NULL) {
  2189. MEMFAILED;
  2190. return(1);
  2191. }
  2192. _tcscpy(pszHKEY_CURRENT_USER_Real, pszHKEY_USERS);
  2193. _tcscat(pszHKEY_CURRENT_USER_Real, TEXT("\\"));
  2194. _tcscat(pszHKEY_CURRENT_USER_Real, pszCurUserSID);
  2195. while (++argv && *argv != NULL) {
  2196. if (*argv[0] == TEXT('-') || *argv[0] == TEXT('/')) {
  2197. switch ((*argv)[1]) {
  2198. case TEXT('s'):
  2199. case TEXT('S'):
  2200. fSnap = TRUE;
  2201. argv++;
  2202. if (*argv == NULL) {
  2203. PrintUsage();
  2204. return(1);
  2205. }
  2206. pszSnapFileOut = *argv;
  2207. break;
  2208. case TEXT('d'):
  2209. case TEXT('D'):
  2210. fDiff = TRUE;
  2211. argv++;
  2212. if (*argv == NULL) {
  2213. PrintUsage();
  2214. return(1);
  2215. }
  2216. pszSnapFileIn = *argv;
  2217. break;
  2218. case TEXT('l'):
  2219. case TEXT('L'):
  2220. fLoadDiffInfo = TRUE;
  2221. argv++;
  2222. if (*argv == NULL) {
  2223. PrintUsage();
  2224. return(1);
  2225. }
  2226. pszDiffFileIn = *argv;
  2227. break;
  2228. case TEXT('w'):
  2229. case TEXT('W'):
  2230. fWriteDiffInfo = TRUE;
  2231. argv++;
  2232. if (*argv == NULL) {
  2233. PrintUsage();
  2234. return(1);
  2235. }
  2236. pszDiffFileOut = *argv;
  2237. break;
  2238. case TEXT('e'):
  2239. case TEXT('E'):
  2240. fEraseInputFileWhenDone = TRUE;
  2241. break;
  2242. case TEXT('m'):
  2243. case TEXT('M'):
  2244. fMerge = TRUE;
  2245. break;
  2246. case TEXT('b'):
  2247. case TEXT('B'):
  2248. fBreak = TRUE;
  2249. break;
  2250. case TEXT('u'):
  2251. case TEXT('U'):
  2252. fUnmerge = TRUE;
  2253. break;
  2254. case TEXT('r'):
  2255. case TEXT('R'):
  2256. fRemoveDiffInfo = TRUE;
  2257. break;
  2258. case TEXT('n'):
  2259. case TEXT('N'):
  2260. fSafe = TRUE;
  2261. break;
  2262. case TEXT('v'):
  2263. case TEXT('V'):
  2264. fVerbose = TRUE;
  2265. break;
  2266. case TEXT('x'):
  2267. case TEXT('X'):
  2268. argv++;
  2269. if (*argv == NULL) {
  2270. PrintUsage();
  2271. return(1);
  2272. }
  2273. if (!ReadNodeListFile(*argv, &ppszExceptKeys,
  2274. &cExceptKeys, NULL)) {
  2275. PrintUsage();
  2276. return(1);
  2277. }
  2278. fExclusionListSpecified = TRUE;
  2279. break;
  2280. case TEXT('i'):
  2281. case TEXT('I'):
  2282. argv++;
  2283. if (*argv == NULL) {
  2284. PrintUsage();
  2285. return(1);
  2286. }
  2287. if (!ReadNodeListFile(*argv, &ppszIncludeKeys,
  2288. &cIncludeKeys, &pfIncludeKeyMarks)) {
  2289. PrintUsage();
  2290. return(1);
  2291. }
  2292. fInclusionListSpecified = TRUE;
  2293. break;
  2294. case TEXT('@'):
  2295. fDebug = TRUE;
  2296. break;
  2297. default:
  2298. PrintUsage();
  2299. return(1);
  2300. }
  2301. } else {
  2302. PrintUsage();
  2303. return(1);
  2304. }
  2305. }
  2306. DPRINTF((TEXT("fEraseInputFileWhenDone = %d\n"), fEraseInputFileWhenDone));
  2307. DPRINTF((TEXT("fSnap = %d\n"), fSnap));
  2308. DPRINTF((TEXT("fDiff = %d\n"), fDiff));
  2309. DPRINTF((TEXT("fMerge = %d\n"), fMerge));
  2310. DPRINTF((TEXT("fUnmerge = %d\n"), fUnmerge));
  2311. DPRINTF((TEXT("fRemoveDiffInfo = %d\n"), fRemoveDiffInfo));
  2312. DPRINTF((TEXT("fWriteDiffInfo = %d\n"), fWriteDiffInfo));
  2313. DPRINTF((TEXT("fDebug = %d\n"), fDebug));
  2314. DPRINTF((TEXT("fVerbose = %d\n"), fVerbose));
  2315. DPRINTF((TEXT("fBreak = %d\n"), fBreak));
  2316. if (pszSnapFileIn != NULL) {
  2317. DPRINTF((TEXT("pszSnapFileIn = %hs\n"), pszSnapFileIn));
  2318. }
  2319. if (pszSnapFileOut != NULL) {
  2320. DPRINTF((TEXT("pszSnapFileOut = %hs\n"), pszSnapFileOut));
  2321. }
  2322. if (pszDiffFileIn != NULL) {
  2323. DPRINTF((TEXT("pszDiffFileIn = %hs\n"), pszDiffFileIn));
  2324. }
  2325. if (pszDiffFileOut != NULL) {
  2326. DPRINTF((TEXT("pszDiffFileOut = %hs\n"), pszDiffFileOut));
  2327. }
  2328. /*
  2329. * The registry APIs need us to get Backup and Restore privileges
  2330. * to work correctly.
  2331. */
  2332. if (!EnablePrivilege(SE_BACKUP_NAME)) {
  2333. EPRINTF((TEXT("Could not gain %s privilege."), SE_BACKUP_NAME));
  2334. return(0);
  2335. }
  2336. if (!EnablePrivilege(SE_RESTORE_NAME)) {
  2337. EPRINTF((TEXT("Could not gain %s privilege."), SE_RESTORE_NAME));
  2338. return(0);
  2339. }
  2340. #if 0 // other privileges that regedit has we may need.
  2341. if (!EnablePrivilege(SE_CHANGE_NOTIFY_NAME)) {
  2342. EPRINTF((TEXT("Could not gain %s privilege."), SE_CHANGE_NOTIFY_NAME));
  2343. return(0);
  2344. }
  2345. if (!EnablePrivilege(SE_SECURITY_NAME)) {
  2346. EPRINTF((TEXT("Could not gain %s privilege."), SE_SECURITY_NAME));
  2347. return(0);
  2348. }
  2349. #endif // 0
  2350. /*
  2351. * Normalize our inlcude and exception lists before we start.
  2352. */
  2353. for (i = 0; i < cExceptKeys; i++) {
  2354. apszExceptKeys[i] = NormalizePathName(ppszExceptKeys[i], NULL);
  2355. }
  2356. for (i = 0; i < cIncludeKeys; i++) {
  2357. apszIncludeKeys[i] = NormalizePathName(ppszIncludeKeys[i], NULL);
  2358. }
  2359. /*
  2360. * Let the debug dudes see the lists.
  2361. */
  2362. if (fDebug) {
  2363. _tprintf(TEXT("\nUsing normalized inclusion list:\n"));
  2364. for (i = 0; i < cIncludeKeys; i++) {
  2365. _tprintf(TEXT(" %s\n"), ppszIncludeKeys[i]);
  2366. }
  2367. _tprintf(TEXT("\nUsing normalized exclusion list:\n"));
  2368. for (i = 0; i < cExceptKeys; i++) {
  2369. _tprintf(TEXT(" %s\n"), ppszExceptKeys[i]);
  2370. }
  2371. }
  2372. /*
  2373. * Make sure snapshot key is unloaded - help insure
  2374. * temp file is useable.
  2375. */
  2376. RegUnLoadKey(HKEY_LOCAL_MACHINE, pszSnapshotSubkeyName);
  2377. RegUnLoadKey(HKEY_USERS, pszSnapshotSubkeyName);
  2378. if (fVerbose) {
  2379. if (fInclusionListSpecified) {
  2380. _tprintf(TEXT("Using inclusion list:\n"));
  2381. for (i = 0; i < cIncludeKeys; i++) {
  2382. _tprintf(TEXT(" %s\n"), ppszIncludeKeys[i]);
  2383. }
  2384. _tprintf(TEXT("\n"));
  2385. }
  2386. if (fExclusionListSpecified) {
  2387. _tprintf(TEXT("Using exception list:\n"));
  2388. for (i = 0; i < cExceptKeys; i++) {
  2389. _tprintf(TEXT(" %s\n"), ppszExceptKeys[i]);
  2390. }
  2391. _tprintf(TEXT("\n"));
  2392. }
  2393. }
  2394. if (fSnap) {
  2395. VPRINTF((TEXT("Snapping registry.\n")));
  2396. SnapHives(pszSnapFileOut);
  2397. _tprintf(TEXT("\n"));
  2398. }
  2399. if (fDiff) {
  2400. VPRINTF((TEXT("Diffing current registry with %hs.\n"), pszSnapFileIn));
  2401. DiffHive(pszSnapFileIn);
  2402. _tprintf(TEXT("\n"));
  2403. } else if (fLoadDiffInfo) {
  2404. LONG status;
  2405. RegUnLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot); // incase a dummy is loaded
  2406. VPRINTF((TEXT("Loading diff info from %hs.\n"), pszDiffFileIn));
  2407. status = MyRegLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot, pszDiffFileIn);
  2408. if (status != ERROR_SUCCESS) {
  2409. EPRINTF((TEXT("Could not load key %s. Error=%d.\n"), pszDiffRoot, status));
  2410. return(0);
  2411. }
  2412. _tprintf(TEXT("\n"));
  2413. }
  2414. if (fLoadDiffInfo && fDiff) {
  2415. WPRINTF((TEXT("Ignoring -l flag. Diff info was already created by diff operation.\n")));
  2416. }
  2417. if (fMerge) {
  2418. VPRINTF((TEXT("Mergeing diff info into current registry.\n")));
  2419. MergeHive(pszAddKey, pszDelKey);
  2420. _tprintf(TEXT("\n"));
  2421. }
  2422. if (fUnmerge) {
  2423. VPRINTF((TEXT("Unmergeing diff info from current registry.\n")));
  2424. MergeHive(pszDelKey, pszAddKey);
  2425. _tprintf(TEXT("\n"));
  2426. }
  2427. if (fWriteDiffInfo) {
  2428. HKEY hKey;
  2429. LONG status;
  2430. DeleteFileA(pszDiffFileOut); // cannot already exist.
  2431. VPRINTF((TEXT("Saving diff info to %hs.\n"), pszDiffFileOut));
  2432. status = LogRegOpenKey(HKEY_LOCAL_MACHINE, pszDiffRoot, &hKey);
  2433. if (status != ERROR_SUCCESS) {
  2434. EPRINTF((TEXT("Could not open key HKEY_LOCAL_MACHINE\\%s. Error=%d.\n"),
  2435. pszDiffRoot, status));
  2436. return(0);
  2437. }
  2438. status = RegSaveKeyA(hKey, pszDiffFileOut, NULL);
  2439. if (status != ERROR_SUCCESS) {
  2440. EPRINTF((TEXT("Could not save key %s. Error=%d.\n"), pszDiffRoot, status));
  2441. return(0);
  2442. }
  2443. LogRegCloseKey(hKey);
  2444. _tprintf(TEXT("\n"));
  2445. }
  2446. if (fEraseInputFileWhenDone) {
  2447. if (pszDiffFileIn != NULL) {
  2448. VPRINTF((TEXT("Erasing diff info file %hs.\n"), pszDiffFileIn));
  2449. DeleteFileA(pszDiffFileIn);
  2450. }
  2451. if (pszSnapFileIn != NULL) {
  2452. VPRINTF((TEXT("Erasing snapshot file %hs.\n"), pszSnapFileIn));
  2453. DeleteFileA(pszSnapFileIn);
  2454. }
  2455. _tprintf(TEXT("\n"));
  2456. }
  2457. if (fRemoveDiffInfo) {
  2458. VPRINTF((TEXT("Unloading diff info from registry.\n")));
  2459. /*
  2460. * Don't leave loaded keys in
  2461. */
  2462. RegUnLoadKey(HKEY_LOCAL_MACHINE, pszDiffRoot);
  2463. _tprintf(TEXT("\n"));
  2464. }
  2465. DeleteSidString(pszCurUserSID);
  2466. while (pKeyLogList != NULL) {
  2467. EPRINTF((TEXT("Leftover open key:%x, %x, %s.\n"),
  2468. pKeyLogList->hKey,
  2469. pKeyLogList->hKeyParent,
  2470. pKeyLogList->psz));
  2471. LogRegCloseKey(pKeyLogList->hKey);
  2472. }
  2473. DeleteFileA(pszDummyFile);
  2474. DeleteFileA(pszDummyFileLog);
  2475. DeleteFileA(pszTempFile);
  2476. DeleteFileA(pszTempFile2);
  2477. DeleteFileA(pszTempFileLog);
  2478. DeleteFileA(pszTempFile2Log);
  2479. return(0);
  2480. }