Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

512 lines
13 KiB

  1. /****************************************************************************\
  2. LOADHIVE.C / Mass Storage Device Installer (MSDINST.LIB)
  3. Microsoft Confidential
  4. Copyright (c) Microsoft Corporation 2001
  5. All rights reserved
  6. Source file the MSD Installation library which contains the functions
  7. used to manipulate the offline registry hives.
  8. 07/2001 - Jason Cohen (JCOHEN)
  9. Added this new source file for the new MSD Installation project.
  10. \****************************************************************************/
  11. //
  12. // Include File(s):
  13. //
  14. #include "pch.h"
  15. //
  16. // Local Define(s):
  17. //
  18. #define FILE_BOOT_INI _T("boot.ini")
  19. #define INI_SEC_BOOTLDR _T("boot loader")
  20. #define INI_KEY_BOOTDEFAULT _T("default")
  21. #define HIVE_SOFTWARE _T("{dcc62fd6-8739-4d15-9d47-3dbe9d86dbfe}")
  22. #define HIVE_SYSTEM _T("{7ebc3661-e661-4943-95a5-412378cb16d1}")
  23. #define FILE_SOFTWARE _T("SOFTWARE")
  24. #define FILE_SYSTEM _T("SYSTEM")
  25. #define DIR_REGISTRY _T("config")
  26. #define DIR_SYSTEM _T("system32")
  27. #define DIR_SYSTEM_REGISTRY DIR_SYSTEM _T("\\") DIR_REGISTRY
  28. #define REG_KEY_OFFLINE _T("SOFTWARE\\")
  29. #define LIST_SOFTWARE 0
  30. #define LIST_SYSTEM 1
  31. //
  32. // Local Type Define(s):
  33. //
  34. typedef struct _HIVELIST
  35. {
  36. PHKEY phkey;
  37. LPTSTR lpszHiveName;
  38. LPTSTR lpszHiveFile;
  39. }
  40. HIVELIST, *PHIVELIST, *LPHIVELIST;
  41. //
  42. // Local Global(s):
  43. //
  44. static HIVELIST s_HiveList[] =
  45. {
  46. { NULL, HIVE_SOFTWARE, FILE_SOFTWARE },
  47. { NULL, HIVE_SYSTEM, FILE_SYSTEM },
  48. };
  49. //
  50. // Local Prototype(s):
  51. //
  52. static BOOL MyEnablePrivilege(LPTSTR lpszPrivilege, BOOL bEnable);
  53. static BOOL
  54. RegDoOneHive(
  55. LPTSTR lpszHiveName,
  56. LPTSTR lpszHiveFile,
  57. BOOL bCheckOnly,
  58. PHKEY phkey
  59. );
  60. static BOOL
  61. RegDoAllHives(
  62. LPTSTR lpszWindows
  63. );
  64. static BOOL CheckSystem(LPTSTR lpszSysDir, DWORD cbSysDir, BOOL bLoadHive);
  65. static BOOL FindSystem(LPTSTR lpszSysDir, DWORD cbSysDir, DWORD dwIndex, BOOL bLoadHive);
  66. //
  67. // Exported Funtion(s):
  68. //
  69. BOOL
  70. RegLoadOfflineImage(
  71. LPTSTR lpszWindows,
  72. PHKEY phkeySoftware,
  73. PHKEY phkeySystem
  74. )
  75. {
  76. HKEY hkeyLM = NULL;
  77. DWORD dwDis;
  78. BOOL bRet = FALSE;
  79. // We need to init all the key pointers passed in.
  80. //
  81. if ( phkeySoftware )
  82. {
  83. *phkeySoftware = NULL;
  84. bRet = TRUE;
  85. }
  86. if ( phkeySystem )
  87. {
  88. *phkeySystem = NULL;
  89. bRet = TRUE;
  90. }
  91. // Make sure they wanted at least one key loaded.
  92. //
  93. if ( !bRet )
  94. {
  95. return FALSE;
  96. }
  97. // We need this privilege to load the hives.
  98. //
  99. if ( !MyEnablePrivilege(SE_RESTORE_NAME, TRUE) )
  100. {
  101. return FALSE;
  102. }
  103. // Now try to load all the hives they wanted.
  104. //
  105. s_HiveList[LIST_SOFTWARE].phkey = phkeySoftware;
  106. s_HiveList[LIST_SYSTEM].phkey = phkeySystem;
  107. bRet = RegDoAllHives(lpszWindows);
  108. // Set the privilege back to the default.
  109. //
  110. MyEnablePrivilege(SE_RESTORE_NAME, FALSE);
  111. // Return TRUE if everything worked out okay.
  112. //
  113. return bRet;
  114. }
  115. BOOL
  116. RegUnloadOfflineImage(
  117. HKEY hkeySoftware,
  118. HKEY hkeySystem
  119. )
  120. {
  121. BOOL bRet = TRUE;
  122. // If there is nothing to unload, just return.
  123. //
  124. if ( !( hkeySoftware || hkeySystem ) )
  125. {
  126. return TRUE;
  127. }
  128. // We need this privilege to unload the hives.
  129. //
  130. if ( !MyEnablePrivilege(SE_RESTORE_NAME, TRUE) )
  131. {
  132. return FALSE;
  133. }
  134. // Try to unload the hives in the key passed in.
  135. //
  136. s_HiveList[LIST_SOFTWARE].phkey = hkeySoftware ? &hkeySoftware : NULL;
  137. s_HiveList[LIST_SYSTEM].phkey = hkeySystem ? &hkeySystem : NULL;
  138. bRet = RegDoAllHives(NULL);
  139. // Set the privilege back to the default.
  140. //
  141. MyEnablePrivilege(SE_RESTORE_NAME, FALSE);
  142. // Return TRUE if everything worked out okay.
  143. //
  144. return bRet;
  145. }
  146. //
  147. // Local Function(s):
  148. //
  149. static BOOL MyEnablePrivilege(LPTSTR lpszPrivilege, BOOL bEnable)
  150. {
  151. HANDLE hToken;
  152. TOKEN_PRIVILEGES tp;
  153. BOOL bRet = FALSE;
  154. // First obtain the processes token.
  155. //
  156. if ( OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken) )
  157. {
  158. // Get the luid
  159. //
  160. if ( LookupPrivilegeValue(NULL, lpszPrivilege, &tp.Privileges[0].Luid) )
  161. {
  162. tp.PrivilegeCount = 1;
  163. tp.Privileges[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0;
  164. // Enable or disable the privilege.
  165. //
  166. bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
  167. //
  168. // The return value of AdjustTokenPrivileges() can be true even though we didn't set all
  169. // the privileges that we asked for. We need to call GetLastError() to make sure the call succeeded.
  170. //
  171. bRet = bRet && ( ERROR_SUCCESS == GetLastError() );
  172. }
  173. CloseHandle(hToken);
  174. }
  175. return bRet;
  176. }
  177. static BOOL
  178. RegDoOneHive(
  179. LPTSTR lpszHiveName,
  180. LPTSTR lpszHiveFile,
  181. BOOL bCheckOnly,
  182. PHKEY phkey
  183. )
  184. {
  185. BOOL bRet = TRUE;
  186. // Hive name can not be NULL.
  187. //
  188. if ( NULL == lpszHiveName )
  189. {
  190. return FALSE;
  191. }
  192. // If there is a file to load, we are loading, otherwise we are
  193. // unloading the key.
  194. //
  195. if ( lpszHiveFile )
  196. {
  197. // Try to load up the key.
  198. //
  199. if ( ( FileExists(lpszHiveFile) ) &&
  200. ( ERROR_SUCCESS == RegLoadKey(HKEY_LOCAL_MACHINE, lpszHiveName, lpszHiveFile) ) )
  201. {
  202. // See if we are just checking to make sure the hive
  203. // exists and we can load it.
  204. //
  205. if ( bCheckOnly )
  206. {
  207. // NULL these out so we unload the key.
  208. //
  209. lpszHiveFile = NULL;
  210. phkey = NULL;
  211. }
  212. else if ( ( phkey ) &&
  213. ( ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpszHiveName, 0, KEY_ALL_ACCESS, phkey) ) )
  214. {
  215. // Have to return an error if we couldn't open the key.
  216. //
  217. bRet = FALSE;
  218. // Also have to NULL out these values so we unload
  219. // the key.
  220. //
  221. lpszHiveFile = NULL;
  222. phkey = NULL;
  223. }
  224. }
  225. else
  226. {
  227. // Do'h, that sucks. Return FALSE.
  228. //
  229. bRet = FALSE;
  230. }
  231. }
  232. // Now check to see if we need to unload the key.
  233. //
  234. if ( NULL == lpszHiveFile )
  235. {
  236. // First close the key if there is one they passed
  237. // in.
  238. //
  239. if ( phkey && *phkey )
  240. {
  241. RegCloseKey(*phkey);
  242. *phkey = NULL;
  243. }
  244. // Now try to unload the key.
  245. //
  246. if ( ERROR_SUCCESS != RegUnLoadKey(HKEY_LOCAL_MACHINE, lpszHiveName) )
  247. {
  248. bRet = FALSE;
  249. }
  250. }
  251. // Return TRUE if there were no errors.
  252. //
  253. return bRet;
  254. }
  255. static BOOL
  256. RegDoAllHives(
  257. LPTSTR lpszWindows
  258. )
  259. {
  260. BOOL bRet = TRUE,
  261. bLoad = FALSE,
  262. bUndo = FALSE;
  263. TCHAR szHiveFile[MAX_PATH];
  264. LPTSTR lpszEnd;
  265. DWORD dwIndex;
  266. // See if we need to load the files.
  267. //
  268. if ( lpszWindows )
  269. {
  270. // If we are loading, init our file buffers.
  271. //
  272. bLoad = TRUE;
  273. lstrcpyn(szHiveFile, lpszWindows, AS(szHiveFile));
  274. AddPathN(szHiveFile, DIR_SYSTEM_REGISTRY, AS(szHiveFile));
  275. lpszEnd = szHiveFile + lstrlen(szHiveFile);
  276. }
  277. // Loop through all the hives we might have to load/unload.
  278. //
  279. for ( dwIndex = 0; dwIndex < AS(s_HiveList); dwIndex++ )
  280. {
  281. // Now, we only do anything if there is a pointer to the registry key. Then
  282. // only if we are loading or we are unloading and there is something in that pointer.
  283. //
  284. if ( ( s_HiveList[dwIndex].phkey ) &&
  285. ( bLoad || *(s_HiveList[dwIndex].phkey) ) )
  286. {
  287. // If we are loading, setup the full path to the file.
  288. //
  289. if ( bLoad )
  290. {
  291. AddPathN(szHiveFile, s_HiveList[dwIndex].lpszHiveFile, AS(szHiveFile));
  292. }
  293. // Try to load/unload the hive.
  294. //
  295. if ( !RegDoOneHive(s_HiveList[dwIndex].lpszHiveName, bLoad ? szHiveFile : NULL, FALSE, s_HiveList[dwIndex].phkey) )
  296. {
  297. // Failure, so set the return to FALSE. We also have to do
  298. // some other stuff if we are doing a load.
  299. //
  300. bRet = FALSE;
  301. if ( bLoad )
  302. {
  303. // See if we have already loaded anything.
  304. //
  305. if ( bUndo )
  306. {
  307. // We did, so we have to clean up what we loaded.
  308. //
  309. RegDoAllHives(NULL);
  310. }
  311. // Now get out of the loop because we quit once one load fails.
  312. //
  313. break;
  314. }
  315. }
  316. else
  317. {
  318. // We have loaded something, so in case of an error
  319. // we need to know if there is anything to cleanup.
  320. //
  321. bUndo = TRUE;
  322. }
  323. // Chop off the file name if we added it.
  324. //
  325. if ( bLoad )
  326. {
  327. *lpszEnd = NULLCHR;
  328. }
  329. }
  330. }
  331. // Return TRUE if everything went okay.
  332. //
  333. return bRet;
  334. }
  335. #if 0
  336. static BOOL CheckSystem(LPTSTR lpszSysDir, DWORD cbSysDir, BOOL bLoadHive)
  337. {
  338. BOOL bRet = FALSE;
  339. TCHAR szSystem[MAX_PATH],
  340. szValue[256];
  341. LPTSTR lpszBootIni,
  342. lpszFolder,
  343. lpszNewSysDir = lpszSysDir;
  344. // If they gave us room to return something, we can look for a BOOT.INI and
  345. // search for the where the system drive is.
  346. //
  347. if ( cbSysDir )
  348. {
  349. // See if there is a BOOT.INI file on the drive.
  350. //
  351. lstrcpyn(szSystem, lpszSysDir, AS(szSystem));
  352. lpszBootIni = szSystem + lstrlen(szSystem);
  353. AddPathN(szSystem, FILE_BOOT_INI, AS(szSystem));
  354. if ( FileExists(szSystem) )
  355. {
  356. // Need the name of the folder out of the boot.ini.
  357. //
  358. szValue[0] = NULLCHR;
  359. GetPrivateProfileString(INI_SEC_BOOTLDR, INI_KEY_BOOTDEFAULT, NULLSTR, szValue, AS(szValue), szSystem);
  360. if ( lpszFolder = StrChr(szValue, _T('\\')) )
  361. {
  362. // Add our system folder we found to the path passed in.
  363. //
  364. *lpszBootIni = NULLCHR;
  365. AddPathN(szSystem, lpszFolder, AS(szSystem));
  366. // Make sure there is enough room to return the path we found.
  367. //
  368. if ( (DWORD) lstrlen(szSystem) < cbSysDir )
  369. {
  370. lpszNewSysDir = szSystem;
  371. }
  372. }
  373. }
  374. }
  375. // Make sure the folder and hives exist.
  376. //
  377. if ( DirectoryExists(lpszNewSysDir) &&
  378. HiveEngine(lpszNewSysDir, bLoadHive) )
  379. {
  380. bRet = TRUE;
  381. if ( lpszNewSysDir != lpszSysDir )
  382. {
  383. lstrcpy(lpszSysDir, lpszNewSysDir);
  384. }
  385. }
  386. return bRet;
  387. }
  388. static BOOL FindSystem(LPTSTR lpszSysDir, DWORD cbSysDir, DWORD dwIndex, BOOL bLoadHive)
  389. {
  390. DWORD dwDrives;
  391. TCHAR szSystem[MAX_PATH],
  392. szDrive[] = _T("_:\\");
  393. BOOL bFound = FALSE;
  394. // Loop through all the drives on the system.
  395. //
  396. for ( szDrive[0] = _T('A'), dwDrives = GetLogicalDrives();
  397. ( szDrive[0] <= _T('Z') ) && dwDrives && !bFound;
  398. szDrive[0]++, dwDrives >>= 1 )
  399. {
  400. // First check to see if the first bit is set (which means
  401. // this drive exists in the system). Then make sure it is
  402. // a fixed drive.
  403. //
  404. if ( ( dwDrives & 0x1 ) &&
  405. ( GetDriveType(szDrive) == DRIVE_FIXED ) )
  406. {
  407. lstrcpy(szSystem, szDrive);
  408. if ( CheckSystem(szSystem, AS(szSystem), bLoadHive) )
  409. {
  410. // Only stop if this the nth system they wanted
  411. // returned. Used so you can enumerate all the systems
  412. // on all the drives.
  413. //
  414. if ( 0 == dwIndex )
  415. {
  416. // Return the path to the system directory in the
  417. // supplied buffer.
  418. //
  419. lstrcpyn(lpszSysDir, szSystem, cbSysDir);
  420. bFound = TRUE;
  421. }
  422. else
  423. {
  424. // If we are skipping this system because of the index,
  425. // make sure we unload the hives if we loaded them.
  426. //
  427. if ( bLoadHive )
  428. {
  429. //UnloadHives();
  430. }
  431. dwIndex--;
  432. }
  433. }
  434. }
  435. }
  436. return bFound;
  437. }
  438. #endif