Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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