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.

460 lines
14 KiB

  1. /*
  2. regback.c - registry backup program
  3. this program allows the user to back up active registry hives,
  4. while the system is running.
  5. basic structure:
  6. DoFullBackup ennumerate entries in HiveList, computes which
  7. ones to save and where, and calls DoSpecificBackup for each.
  8. Three argument case of app is just a call to DoSpecificBackup.
  9. */
  10. #include "regutil.h"
  11. #define MACH_NAME L"machine"
  12. #define USERS_NAME L"users"
  13. BOOLEAN DumpUserHive;
  14. PWSTR DirectoryPath;
  15. PWSTR UserHiveFileName;
  16. PWSTR HivePath;
  17. HKEY HiveRoot;
  18. PWSTR HiveName;
  19. LONG
  20. DoFullBackup(
  21. PWSTR DirectoryPath,
  22. PWSTR UserHiveFileName
  23. );
  24. LONG
  25. DoSpecificBackup(
  26. PWSTR HivePath,
  27. HKEY HiveRoot,
  28. PWSTR HiveName
  29. );
  30. BOOL
  31. CtrlCHandler(
  32. IN ULONG CtrlType
  33. )
  34. {
  35. RTDisconnectFromRegistry( &RegistryContext );
  36. return FALSE;
  37. }
  38. int
  39. __cdecl
  40. main(
  41. int argc,
  42. char *argv[]
  43. )
  44. {
  45. char *s;
  46. LONG Error;
  47. PWSTR w;
  48. if (!RTEnableBackupRestorePrivilege()) {
  49. FatalError( "Unable to enable backup/restore priviledge.", 0, 0 );
  50. }
  51. InitCommonCode( CtrlCHandler,
  52. "REGBACK",
  53. "directoryPath [-u | -U outputFile]",
  54. "directoryPath specifies where to save the output files.\n"
  55. "\n"
  56. "-u specifies to dump the logged on user's profile. Default name is\n"
  57. " username.dat User -U with a file name to save it under a different name.\n"
  58. "\n"
  59. "outputFile specifies the file name to use for the user profile\n"
  60. "\n"
  61. "If the -m switch is specified to backup the registry of a remote machine\n"
  62. " then the directoryPath is relative to that machine.\n"
  63. );
  64. DirectoryPath = NULL;
  65. UserHiveFileName = NULL;
  66. HivePath = NULL;
  67. HiveRoot = NULL;
  68. HiveName = NULL;
  69. while (--argc) {
  70. s = *++argv;
  71. if (*s == '-' || *s == '/') {
  72. while (*++s) {
  73. switch( tolower( *s ) ) {
  74. case 'u':
  75. DumpUserHive = TRUE;
  76. if (*s == 'U') {
  77. if (!--argc) {
  78. Usage( "Missing argument to -U switch", 0 );
  79. }
  80. UserHiveFileName = GetArgAsUnicode( *++argv );
  81. }
  82. break;
  83. default:
  84. CommonSwitchProcessing( &argc, &argv, *s );
  85. break;
  86. }
  87. }
  88. }
  89. else
  90. if (DirectoryPath == NULL) {
  91. HivePath = DirectoryPath = GetArgAsUnicode( s );
  92. }
  93. else
  94. if (HivePath != NULL) {
  95. if (HiveRoot == NULL) {
  96. w = GetArgAsUnicode( s );
  97. if (!_wcsicmp( w, MACH_NAME )) {
  98. HiveRoot = HKEY_LOCAL_MACHINE;
  99. }
  100. else
  101. if (!_wcsicmp( w, USERS_NAME )) {
  102. HiveRoot = HKEY_USERS;
  103. }
  104. else {
  105. Usage( "Invalid hive type specified (%ws)", (ULONG_PTR)w );
  106. }
  107. }
  108. else
  109. if (HiveName == NULL) {
  110. HiveName = GetArgAsUnicode( s );
  111. }
  112. else {
  113. Usage( "Too many arguments specified.", 0 );
  114. }
  115. }
  116. else {
  117. Usage( NULL, 0 );
  118. }
  119. }
  120. if (DirectoryPath == NULL) {
  121. Usage( NULL, 0 );
  122. }
  123. Error = RTConnectToRegistry( MachineName,
  124. HiveFileName,
  125. HiveRootName,
  126. Win95Path,
  127. Win95UserPath,
  128. NULL,
  129. &RegistryContext
  130. );
  131. if (Error != NO_ERROR) {
  132. FatalError( "Unable to access registry specifed (%u)", Error, 0 );
  133. }
  134. if (HiveRoot == NULL) {
  135. Error = DoFullBackup( DirectoryPath, UserHiveFileName );
  136. }
  137. else {
  138. Error = DoSpecificBackup( HivePath, HiveRoot, HiveName );
  139. }
  140. RTDisconnectFromRegistry( &RegistryContext );
  141. return Error;
  142. }
  143. typedef BOOL (*PFNGETPROFILESDIRECTORYW)(LPWSTR lpProfile, LPDWORD dwSize);
  144. LONG
  145. DoFullBackup(
  146. PWSTR DirectoryPath,
  147. PWSTR UserHiveFileName
  148. )
  149. /*++
  150. Routine Description:
  151. Scan the hivelist, for each hive which has a file (i.e. not hardware)
  152. if the file is in the config dir (e.g. not some remote profile) call
  153. DoSpecificBackup to save the hive out.
  154. Arguments:
  155. DirectoryPath - specifies where to write the output files.
  156. UserHiveFileName - optional parameter that specifies the name of the file
  157. to use when saving the user profile. If NULL, then
  158. username.dat is used.
  159. Return Value:
  160. 0 for success, otherwise, non-zero error code.
  161. --*/
  162. {
  163. PWSTR w;
  164. LONG Error;
  165. HKEY HiveListKey;
  166. PWSTR KeyName;
  167. PWSTR FileName;
  168. PWSTR Name;
  169. DWORD ValueIndex;
  170. DWORD ValueType;
  171. DWORD ValueNameLength;
  172. DWORD ValueDataLength;
  173. WCHAR ConfigPath[ MAX_PATH ];
  174. WCHAR ProfilePath[ MAX_PATH ];
  175. WCHAR MyHiveName[ MAX_PATH ];
  176. WCHAR MyHivePath[ MAX_PATH ];
  177. WCHAR FilePath[ MAX_PATH ];
  178. DWORD dwSize;
  179. HANDLE hInstDll;
  180. PFNGETPROFILESDIRECTORYW pfnGetProfilesDirectory;
  181. hInstDll = LoadLibrary (TEXT("userenv.dll"));
  182. if (!hInstDll) {
  183. return (GetLastError());
  184. }
  185. pfnGetProfilesDirectory = (PFNGETPROFILESDIRECTORYW)GetProcAddress (hInstDll,
  186. "GetProfilesDirectoryW");
  187. if (!pfnGetProfilesDirectory) {
  188. FreeLibrary (hInstDll);
  189. return (GetLastError());
  190. }
  191. dwSize = MAX_PATH;
  192. if (!pfnGetProfilesDirectory(ProfilePath, &dwSize)) {
  193. FreeLibrary (hInstDll);
  194. return (GetLastError());
  195. }
  196. FreeLibrary (hInstDll);
  197. //
  198. // get handle to hivelist key
  199. //
  200. KeyName = L"HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Hivelist";
  201. Error = RTOpenKey( &RegistryContext,
  202. NULL,
  203. KeyName,
  204. MAXIMUM_ALLOWED,
  205. 0,
  206. &HiveListKey
  207. );
  208. if (Error != NO_ERROR) {
  209. FatalError( "Unable to open key '%ws' (%u)\n",
  210. (ULONG_PTR)KeyName,
  211. (ULONG)Error
  212. );
  213. return Error;
  214. }
  215. //
  216. // get path data for system hive, which will allow us to compute
  217. // path name to config dir in form that hivelist uses.
  218. // (an NT internal form of path) this is NOT the way the path to
  219. // the config directory should generally be computed.
  220. //
  221. ValueDataLength = sizeof( ConfigPath );
  222. Error = RTQueryValueKey( &RegistryContext,
  223. HiveListKey,
  224. L"\\Registry\\Machine\\System",
  225. &ValueType,
  226. &ValueDataLength,
  227. ConfigPath
  228. );
  229. if (Error != NO_ERROR) {
  230. FatalError( "Unable to query 'SYSTEM' hive path.", 0, Error );
  231. }
  232. w = wcsrchr( ConfigPath, L'\\' );
  233. if (w) {
  234. *w = UNICODE_NULL;
  235. }
  236. //
  237. // ennumerate entries in hivelist. for each entry, find it's hive file
  238. // path. if it's file path matches ConfigPath, then save it.
  239. // else, print a message telling the user that it must be saved
  240. // manually, unless the file name is of the form ....\username\ntuser.dat
  241. // in which case save it as username.dat
  242. //
  243. for (ValueIndex = 0; TRUE; ValueIndex++) {
  244. ValueType = REG_NONE;
  245. ValueNameLength = sizeof( MyHiveName ) / sizeof( WCHAR );
  246. ValueDataLength = sizeof( MyHivePath );
  247. Error = RTEnumerateValueKey( &RegistryContext,
  248. HiveListKey,
  249. ValueIndex,
  250. &ValueType,
  251. &ValueNameLength,
  252. MyHiveName,
  253. &ValueDataLength,
  254. MyHivePath
  255. );
  256. if (Error == ERROR_NO_MORE_ITEMS) {
  257. break;
  258. }
  259. else
  260. if (Error != NO_ERROR) {
  261. return Error;
  262. }
  263. if (ValueType == REG_SZ && ValueDataLength > sizeof( UNICODE_NULL )) {
  264. //
  265. // there's a file, compute it's path, hive branch, etc
  266. //
  267. if (w = wcsrchr( MyHivePath, L'\\' )) {
  268. *w++ = UNICODE_NULL;
  269. }
  270. FileName = w;
  271. if (w = wcsrchr( MyHiveName, L'\\' )) {
  272. *w++ = UNICODE_NULL;
  273. }
  274. Name = w;
  275. HiveRoot = NULL;
  276. if (w = wcsrchr( MyHiveName, L'\\' )) {
  277. w += 1;
  278. if (!_wcsicmp( w, L"MACHINE" )) {
  279. HiveRoot = HKEY_LOCAL_MACHINE;
  280. }
  281. else
  282. if (!_wcsicmp( w, L"USER" )) {
  283. HiveRoot = HKEY_USERS;
  284. }
  285. else {
  286. Error = ERROR_PATH_NOT_FOUND;
  287. }
  288. }
  289. if (FileName != NULL && Name != NULL && HiveRoot != NULL) {
  290. if (!wcscmp( ConfigPath, MyHivePath )) {
  291. //
  292. // hive's file is in config dir, we can back it up
  293. // without fear of collision
  294. //
  295. swprintf( FilePath, L"%s\\%s", DirectoryPath, FileName );
  296. Error = DoSpecificBackup( FilePath,
  297. HiveRoot,
  298. Name
  299. );
  300. }
  301. else
  302. if (DumpUserHive && !_wcsnicmp( ProfilePath, MyHivePath, wcslen( ProfilePath ) )) {
  303. //
  304. // hive's file is in profile dir, we can back it up
  305. // without fear of collision if we use username.dat
  306. // for the file name.
  307. //
  308. if (UserHiveFileName != NULL) {
  309. FileName = UserHiveFileName;
  310. }
  311. else {
  312. FileName = wcsrchr(MyHivePath, '\\') + 1;
  313. }
  314. swprintf( FilePath, L"%s\\%s.dat", DirectoryPath, FileName );
  315. printf( "%ws %ws %ws\n",
  316. FilePath,
  317. HiveRoot == HKEY_LOCAL_MACHINE ? MACH_NAME : USERS_NAME,
  318. Name
  319. );
  320. Error = DoSpecificBackup( FilePath,
  321. HiveRoot,
  322. Name
  323. );
  324. }
  325. else {
  326. printf( "\n***Hive = '%ws'\\'%ws'\nStored in file '%ws'\\'%ws'\n",
  327. MyHiveName,
  328. Name,
  329. MyHivePath,
  330. FileName
  331. );
  332. printf( "Must be backed up manually\n" );
  333. printf( "regback <filename you choose> %ws %ws\n\n",
  334. HiveRoot == HKEY_LOCAL_MACHINE ? MACH_NAME : USERS_NAME,
  335. Name
  336. );
  337. }
  338. }
  339. }
  340. }
  341. return Error;
  342. }
  343. LONG
  344. DoSpecificBackup(
  345. PWSTR HivePath,
  346. HKEY HiveRoot,
  347. PWSTR HiveName
  348. )
  349. /*
  350. Do backup of one hive to one file. Any valid hive and any
  351. valid file will do. RegSaveKey does all the real work.
  352. Arguments:
  353. HivePath - file name to pass directly to OS
  354. HiveRoot - HKEY_LOCAL_MACHINE or HKEY_USERS
  355. HiveName - 1st level subkey under machine or users
  356. */
  357. {
  358. HKEY HiveKey;
  359. ULONG Disposition;
  360. LONG Error;
  361. char *Reason;
  362. //
  363. // print some status
  364. //
  365. printf( "saving %ws to %ws", HiveName, HivePath );
  366. //
  367. // get a handle to the hive. use special create call what will
  368. // use privileges
  369. //
  370. Reason = "accessing";
  371. Error = RTCreateKey( &RegistryContext,
  372. HiveRoot,
  373. HiveName,
  374. KEY_READ,
  375. REG_OPTION_BACKUP_RESTORE,
  376. NULL,
  377. &HiveKey,
  378. &Disposition
  379. );
  380. if (Error == NO_ERROR) {
  381. Reason = "saving";
  382. Error = RegSaveKey( HiveKey, HivePath, NULL );
  383. RTCloseKey( &RegistryContext, HiveKey );
  384. }
  385. if (Error != NO_ERROR) {
  386. printf( " - error %s (%u)\n", Reason, Error );
  387. }
  388. else {
  389. printf( "\n" );
  390. }
  391. return Error;
  392. }