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.

438 lines
16 KiB

  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <winuser.h>
  4. #include <lm.h>
  5. #include <shlwapi.h>
  6. #include <comdef.h>
  7. #include "RegistryHelper.h"
  8. #include "BkupRstr.hpp"
  9. #include "folders.h"
  10. #include <memory>
  11. using namespace nsFolders;
  12. using namespace std;
  13. //----------------------------------------------------------------------------
  14. // Function: CopyRegistryKey
  15. //
  16. // Synopsis: Copies a source registry key and all its subkeys to a target registry key.
  17. // Note: the target registry key has to exist already. No roll back.
  18. //
  19. // Arguments:
  20. //
  21. // sourceKey the handle for source registry key
  22. // targetKey the handle for target registry key
  23. // fSetSD whether to set the security descriptor
  24. //
  25. // Returns: ERROR_SUCCESS if successful; otherwise an error code
  26. //
  27. // Modifies: Modifies the target registry key.
  28. //
  29. //----------------------------------------------------------------------------
  30. DWORD CopyRegistryKey(HKEY sourceKey, HKEY targetKey, BOOL fSetSD)
  31. {
  32. WCHAR className[MAX_PATH] = L""; // buffer for class name
  33. DWORD classNameLen = sizeof(className)/sizeof(className[0]); // length of class string
  34. DWORD numOfSubKeys; // number of subkeys
  35. DWORD maxSubKeySize; // longest subkey size
  36. DWORD maxClassSize; // longest class string
  37. DWORD numOfValues; // number of values for key
  38. DWORD maxValueSize; // longest value name
  39. DWORD maxValueDataSize; // longest value data
  40. DWORD securityDescriptorSize; // size of security descriptor
  41. FILETIME lastWriteTime;
  42. DWORD i, j;
  43. DWORD retValue = ERROR_SUCCESS;
  44. // Get the class name and the value count.
  45. retValue = RegQueryInfoKey(sourceKey, // key handle
  46. className, // buffer for class name
  47. &classNameLen, // length of class string
  48. NULL, // reserved
  49. &numOfSubKeys, // number of subkeys
  50. &maxSubKeySize, // longest subkey size
  51. &maxClassSize, // longest class string
  52. &numOfValues, // number of values for this key
  53. &maxValueSize, // longest value name
  54. &maxValueDataSize, // longest value data
  55. &securityDescriptorSize, // security descriptor
  56. &lastWriteTime); // last write time
  57. // fix up the security attributes for the target key
  58. if (retValue == ERROR_SUCCESS && fSetSD)
  59. {
  60. PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) new BYTE[securityDescriptorSize];
  61. if (pSD != NULL)
  62. {
  63. SECURITY_INFORMATION secInfo =
  64. DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
  65. | OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
  66. retValue = RegGetKeySecurity(sourceKey, secInfo, pSD, &securityDescriptorSize);
  67. if (retValue == ERROR_SUCCESS)
  68. retValue = RegSetKeySecurity(targetKey, secInfo, pSD);
  69. delete[] pSD;
  70. }
  71. else
  72. retValue = E_OUTOFMEMORY;
  73. }
  74. // subkeys and values related variables
  75. auto_ptr<WCHAR> subKeyName;
  76. DWORD subKeyNameSize;
  77. auto_ptr<WCHAR> subKeyClassName;
  78. DWORD subKeyClassNameSize;
  79. auto_ptr<WCHAR> valueName;
  80. DWORD valueNameSize;
  81. DWORD valueType;
  82. auto_ptr<BYTE> valueData;
  83. DWORD valueDataSize;
  84. // copy registry values
  85. if (retValue == ERROR_SUCCESS && numOfValues > 0)
  86. {
  87. valueName = auto_ptr<WCHAR>(new WCHAR[maxValueSize + 1]);
  88. valueData = auto_ptr<BYTE>(new BYTE[maxValueDataSize]);
  89. if (valueName.get() != NULL && valueData.get() != NULL)
  90. {
  91. // copy all values from source key to target key
  92. for (i = 0; i < numOfValues; i++)
  93. {
  94. valueNameSize = maxValueSize + 1;
  95. valueDataSize = maxValueDataSize;
  96. retValue = RegEnumValue(sourceKey, i, valueName.get(), &valueNameSize, NULL, &valueType, valueData.get(), &valueDataSize);
  97. if (retValue == ERROR_SUCCESS)
  98. retValue = RegSetValueEx(targetKey, valueName.get(), NULL, valueType, valueData.get(), valueDataSize);
  99. if (retValue != ERROR_SUCCESS)
  100. break;
  101. }
  102. }
  103. else
  104. retValue = E_OUTOFMEMORY;
  105. }
  106. // copy registry subkeys
  107. if (retValue == ERROR_SUCCESS && numOfSubKeys > 0)
  108. {
  109. subKeyName = auto_ptr<WCHAR>(new WCHAR[maxSubKeySize + 1]);
  110. subKeyClassName = auto_ptr<WCHAR>(new WCHAR[maxClassSize + 1]);
  111. if (subKeyName.get() != NULL && subKeyClassName.get() != NULL)
  112. {
  113. // process all subkeys
  114. for (i = 0; i < numOfSubKeys; i++)
  115. {
  116. subKeyNameSize = maxSubKeySize + 1;
  117. subKeyClassNameSize = maxClassSize + 1;
  118. HKEY sourceSubKey;
  119. retValue = RegEnumKeyEx(sourceKey, i, subKeyName.get(), &subKeyNameSize, NULL, subKeyClassName.get(), &subKeyClassNameSize, &lastWriteTime);
  120. if (retValue == ERROR_SUCCESS)
  121. retValue = RegOpenKeyEx(sourceKey, subKeyName.get(), NULL, KEY_ALL_ACCESS|READ_CONTROL|ACCESS_SYSTEM_SECURITY, &sourceSubKey);
  122. if (retValue == ERROR_SUCCESS)
  123. {
  124. BOOL created = FALSE;
  125. HKEY newSubKey;
  126. retValue = RegOpenKeyEx(targetKey, subKeyName.get(), 0,
  127. KEY_ALL_ACCESS|READ_CONTROL |ACCESS_SYSTEM_SECURITY, &newSubKey);
  128. if (retValue == ERROR_FILE_NOT_FOUND)
  129. {
  130. created = TRUE;
  131. retValue = RegCreateKeyEx(targetKey, subKeyName.get(), NULL, subKeyClassName.get(), REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS|ACCESS_SYSTEM_SECURITY, NULL, &newSubKey, NULL);
  132. }
  133. if (retValue == ERROR_SUCCESS)
  134. {
  135. retValue = CopyRegistryKey(sourceSubKey, newSubKey, created);
  136. RegCloseKey(newSubKey);
  137. }
  138. RegCloseKey(sourceSubKey);
  139. }
  140. if (retValue != ERROR_SUCCESS)
  141. break;
  142. }
  143. }
  144. else
  145. retValue = E_FAIL;
  146. }
  147. return retValue;
  148. }
  149. //----------------------------------------------------------------------------
  150. // Function: DeleteRegistryKey
  151. //
  152. // Synopsis: Deletes a registry key and all its subkeys.
  153. //
  154. // Arguments:
  155. //
  156. // hKey the handle for the registry key to be deleted
  157. // lpSubKey the name string for the key to be deleted
  158. //
  159. // Returns: ERROR_SUCCESS if successful; otherwise an error code
  160. //
  161. // Modifies: Modifies the subkey.
  162. //
  163. //----------------------------------------------------------------------------
  164. DWORD DeleteRegistryKey(HKEY hKey, LPCTSTR lpSubKey)
  165. {
  166. DWORD retValue = ERROR_SUCCESS;
  167. _TCHAR subKeyName[MAX_PATH];
  168. DWORD subKeyNameSize = MAX_PATH;
  169. // open the key
  170. HKEY hKeyToDelete;
  171. BOOL bKeyOpened = FALSE;
  172. retValue = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_ALL_ACCESS, &hKeyToDelete);
  173. // delete subkeys
  174. if (retValue == ERROR_SUCCESS)
  175. {
  176. bKeyOpened = TRUE;
  177. do
  178. {
  179. retValue = RegEnumKey(hKeyToDelete, 0, subKeyName, subKeyNameSize);
  180. if (retValue == ERROR_SUCCESS)
  181. {
  182. retValue = DeleteRegistryKey(hKeyToDelete, subKeyName);
  183. }
  184. else if (retValue == ERROR_NO_MORE_ITEMS)
  185. {
  186. retValue = ERROR_SUCCESS;
  187. break;
  188. }
  189. }
  190. while (retValue == ERROR_SUCCESS);
  191. }
  192. // close key
  193. if (bKeyOpened == TRUE)
  194. RegCloseKey(hKeyToDelete);
  195. if (retValue == ERROR_SUCCESS)
  196. {
  197. retValue = RegDeleteKey(hKey, lpSubKey);
  198. }
  199. return retValue;
  200. }
  201. //----------------------------------------------------------------------------
  202. // Function: MoveRegistryFromSourceToTarget
  203. //
  204. // Synopsis: Moves registry key from a source to a taget
  205. //
  206. // Arguments:
  207. // hSrcParent: the handle to source parent registry key
  208. // sSrcKey: the name of source registry key
  209. // hTgtParent: the handle to target parent registry key
  210. // sTgtKey: the name of target registry key
  211. // bTgtKeyCreated: indicate whether the target key is created or not
  212. // bTgtKeyUpdated: indicate whether the target key is updated or not
  213. //
  214. // Returns: ERROR_SUCCESS if successful; otherwise, returns an error code
  215. //
  216. // Modifies: Create and/or modify the target registry key
  217. //
  218. //----------------------------------------------------------------------------
  219. DWORD MoveRegFromSourceToTarget(HKEY hSrcParent,
  220. const _TCHAR* sSrcKey,
  221. HKEY hTgtParent,
  222. const _TCHAR* sTgtKey,
  223. BOOL* bTgtKeyCreated)
  224. {
  225. HKEY hSrcKey, hTgtKey;
  226. DWORD lret;
  227. *bTgtKeyCreated = FALSE;
  228. //open the source Registry key, if it exists
  229. lret = RegOpenKeyEx(hSrcParent, sSrcKey, 0,
  230. KEY_ALL_ACCESS|READ_CONTROL|ACCESS_SYSTEM_SECURITY, &hSrcKey);
  231. if (lret == ERROR_SUCCESS)
  232. {
  233. //
  234. // copy over the registry from source key to target key
  235. //
  236. // open the target key
  237. lret = RegOpenKeyEx(hTgtParent, sTgtKey, 0,
  238. KEY_ALL_ACCESS|READ_CONTROL |ACCESS_SYSTEM_SECURITY, &hTgtKey);
  239. // if cannot open it, create it
  240. if (lret == ERROR_FILE_NOT_FOUND)
  241. {
  242. lret = RegCreateKeyEx(hTgtParent, sTgtKey, NULL, NULL, REG_OPTION_NON_VOLATILE,
  243. KEY_ALL_ACCESS|ACCESS_SYSTEM_SECURITY, NULL, &hTgtKey, NULL);
  244. if (lret == ERROR_SUCCESS)
  245. *bTgtKeyCreated = TRUE;
  246. }
  247. // time to copy registry
  248. if (lret == ERROR_SUCCESS)
  249. {
  250. lret = CopyRegistryKey(hSrcKey, hTgtKey, *bTgtKeyCreated);
  251. RegCloseKey(hTgtKey);
  252. }
  253. RegCloseKey(hSrcKey); // we need to close Mission Critical Software registry key anyway
  254. }
  255. else if (lret == ERROR_FILE_NOT_FOUND)
  256. {
  257. // if the source key is not found, assume it is a success
  258. lret = ERROR_SUCCESS;
  259. }
  260. return lret;
  261. }
  262. //----------------------------------------------------------------------------
  263. // Function: MoveRegistry
  264. //
  265. // Synopsis: Moves registry key from Mission Critical Software\DomainAdmin to Microsoft\ADMT.
  266. //
  267. // Arguments:
  268. //
  269. // Returns: ERROR_SUCCESS if successful; otherwise retuns an error code
  270. //
  271. // Modifies: Deletes the old Mission Critical Software key and creates new Microsoft\ADMT key.
  272. //
  273. //----------------------------------------------------------------------------
  274. DWORD MoveRegistry()
  275. {
  276. DWORD lret = ERROR_SUCCESS;
  277. // some key names
  278. HKEY hMcsADMTKey; // Mission Critical Software ADMT registry key
  279. HKEY hMSADMTKey; // Microsoft ADMT registry key
  280. HKEY hMcsHKCUKey; // Mission Critical Software HKCU registry key
  281. HKEY hMSHKCUKey; // Microsoft HKCU registry key
  282. const _TCHAR* sMcsADMTKey = REGKEY_MCSADMT;
  283. const _TCHAR* sMSADMTKey = REGKEY_MSADMT;
  284. const _TCHAR* sMcsHKCUKey = REGKEY_MCSHKCU;
  285. const _TCHAR* sMSHKCUKey = REGKEY_MSHKCU;
  286. // check whether we need to move the registry key from Mission Critical Software to Microsoft\ADMT or not
  287. // this information is recorded in a REG_DWORD value in Microsoft\ADMT key
  288. lret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sMSADMTKey, 0, KEY_READ, &hMSADMTKey);
  289. if (lret == ERROR_SUCCESS)
  290. {
  291. DWORD type;
  292. DWORD value;
  293. DWORD valueSize = sizeof(value);
  294. lret = RegQueryValueEx(hMSADMTKey, REGVAL_REGISTRYUPDATED, NULL, &type, (LPBYTE)&value, &valueSize);
  295. if (lret == ERROR_SUCCESS && type == REG_DWORD && value == 1)
  296. {
  297. // if RegistryUpdated is REG_DWORD and 1, we don't need to move registry key
  298. RegCloseKey(hMSADMTKey);
  299. return ERROR_SUCCESS;
  300. }
  301. else if (lret == ERROR_FILE_NOT_FOUND)
  302. lret = ERROR_SUCCESS;
  303. RegCloseKey(hMSADMTKey);
  304. }
  305. else if (lret == ERROR_FILE_NOT_FOUND)
  306. {
  307. // if the key does not exist, we should go ahead and move the registry
  308. lret = ERROR_SUCCESS;
  309. }
  310. // check whether MCS ADMT is available or not
  311. if (lret == ERROR_SUCCESS)
  312. {
  313. lret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sMcsADMTKey, 0, KEY_READ, &hMcsADMTKey);
  314. if (lret == ERROR_SUCCESS)
  315. {
  316. // if RegistryUpdated is REG_DWORD and 1, we don't need to move registry key
  317. RegCloseKey(hMcsADMTKey);
  318. }
  319. else if (lret == ERROR_FILE_NOT_FOUND)
  320. return ERROR_SUCCESS;
  321. }
  322. // get backup/restore and system security privileges
  323. BOOL fBkupRstrPrivOn = FALSE, fSystemSecurityPrivOn = FALSE;
  324. if (lret == ERROR_SUCCESS)
  325. {
  326. fBkupRstrPrivOn = GetBkupRstrPriv(NULL, TRUE);
  327. if (fBkupRstrPrivOn == FALSE)
  328. lret = GetLastError();
  329. }
  330. if (lret == ERROR_SUCCESS)
  331. {
  332. fSystemSecurityPrivOn = GetPrivilege(NULL, SE_SECURITY_NAME, TRUE);
  333. if (fSystemSecurityPrivOn == FALSE)
  334. lret = GetLastError();
  335. }
  336. // these two flags are used to keep track of whether two registry keys are created/updated or not
  337. BOOL fMSADMTKeyCreated = FALSE;
  338. BOOL fMSHKCUKeyCreated = FALSE;
  339. if (lret == ERROR_SUCCESS)
  340. {
  341. lret = MoveRegFromSourceToTarget(HKEY_LOCAL_MACHINE, sMcsADMTKey,
  342. HKEY_LOCAL_MACHINE, sMSADMTKey,
  343. &fMSADMTKeyCreated);
  344. }
  345. if (lret == ERROR_SUCCESS)
  346. {
  347. lret = MoveRegFromSourceToTarget(HKEY_CURRENT_USER, sMcsHKCUKey,
  348. HKEY_CURRENT_USER, sMSHKCUKey,
  349. &fMSHKCUKeyCreated);
  350. }
  351. //
  352. // delete keys that we do not need
  353. //
  354. if (lret != ERROR_SUCCESS)
  355. {
  356. if (fMSADMTKeyCreated)
  357. DeleteRegistryKey(HKEY_LOCAL_MACHINE, sMSADMTKey);
  358. if (fMSHKCUKeyCreated)
  359. DeleteRegistryKey(HKEY_CURRENT_USER, sMSHKCUKey);
  360. }
  361. // we have successfully created and copied two registry keys, we delete the old Mission Critical Software keys
  362. // and mark RegistryUpdated registry value
  363. else
  364. {
  365. // set RegistryUpdated registry value to 1
  366. lret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, sMSADMTKey, 0, KEY_ALL_ACCESS, &hMSADMTKey);
  367. if (lret == ERROR_SUCCESS)
  368. {
  369. DWORD type = REG_DWORD;
  370. DWORD value = 1;
  371. lret = RegSetValueEx(hMSADMTKey, REGVAL_REGISTRYUPDATED, NULL, type, (BYTE*)&value, sizeof(value));
  372. RegCloseKey(hMSADMTKey);
  373. }
  374. // if we successfully set RegistryUpdated to 1, delete both old keys
  375. if (lret == ERROR_SUCCESS)
  376. {
  377. DeleteRegistryKey(HKEY_LOCAL_MACHINE, sMcsADMTKey);
  378. DeleteRegistryKey(HKEY_CURRENT_USER, sMcsHKCUKey);
  379. }
  380. }
  381. //
  382. // release privileges
  383. //
  384. if (fBkupRstrPrivOn)
  385. GetBkupRstrPriv(NULL, FALSE);
  386. if (fSystemSecurityPrivOn)
  387. GetPrivilege(NULL, SE_SECURITY_NAME, FALSE);
  388. return lret;
  389. }