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.

651 lines
18 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. pnpreg.c
  5. Abstract:
  6. The module contains the the initialization code for the executive
  7. component. It also contains the display string and shutdown system
  8. services.
  9. Author:
  10. Robert B. Nelson (robertn) 10-Feb-1998
  11. Revision History:
  12. --*/
  13. #include <windows.h>
  14. #include <aclapi.h>
  15. #include <regstr.h>
  16. #include <stdio.h>
  17. #include <malloc.h>
  18. #include <tchar.h>
  19. PSID g_pAdminSid;
  20. PSID g_pSystemSid;
  21. SECURITY_DESCRIPTOR g_DeviceParametersSD;
  22. PACL g_pDeviceParametersDacl;
  23. SECURITY_DESCRIPTOR g_LockedPrivateKeysSD;
  24. PACL g_pLockedPrivateKeysDacl;
  25. #if DBG || UMODETEST
  26. #define DBGF_ERRORS 0x00000001
  27. #define DBGF_WARNINGS 0x00000002
  28. #define DBGF_REGISTRY 0x00000010
  29. void RegFixDebugMessage(LPTSTR format, ...);
  30. #define DBGTRACE(l, x) (g_RegFixDebugFlag & (l) ? RegFixDebugMessage x : (void)0)
  31. DWORD g_RegFixDebugFlag = DBGF_WARNINGS | DBGF_ERRORS;
  32. TCHAR g_szCurrentKeyName[4096];
  33. DWORD g_dwCurrentKeyNameLength = 0;
  34. #else
  35. #define DBGTRACE(l, x)
  36. #endif
  37. VOID
  38. FreeSecurityDescriptors(
  39. VOID
  40. )
  41. /*++
  42. Routine Description:
  43. This function deallocates the data structures allocated and initialized by
  44. CreateDeviceParametersSD.
  45. Arguments:
  46. None.
  47. Return Value:
  48. None.
  49. --*/
  50. {
  51. if (g_pDeviceParametersDacl) {
  52. LocalFree(g_pDeviceParametersDacl);
  53. g_pDeviceParametersDacl = NULL;
  54. }
  55. if (g_pLockedPrivateKeysDacl) {
  56. LocalFree(g_pLockedPrivateKeysDacl);
  57. g_pLockedPrivateKeysDacl = NULL;
  58. }
  59. if (g_pAdminSid != NULL) {
  60. FreeSid(g_pAdminSid);
  61. g_pAdminSid = NULL;
  62. }
  63. if (g_pSystemSid != NULL) {
  64. FreeSid(g_pSystemSid);
  65. g_pSystemSid = NULL;
  66. }
  67. }
  68. BOOL
  69. CreateSecurityDescriptors(
  70. VOID
  71. )
  72. /*++
  73. Routine Description:
  74. This function creates a properly initialized Security Descriptor for the
  75. Device Parameters key and its subkeys. The SIDs and DACL created by this
  76. routine must be freed by calling FreeDeviceParametersSD.
  77. Arguments:
  78. None.
  79. Return Value:
  80. Pointer to the initialized Security Descriptor. NULL is returned if an
  81. error occurs.
  82. --*/
  83. {
  84. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  85. EXPLICIT_ACCESS ExplicitAccess[2];
  86. DWORD dwError;
  87. BOOL bSuccess;
  88. DWORD i;
  89. //
  90. // Create SIDs - Admins and System
  91. //
  92. bSuccess = AllocateAndInitializeSid( &NtAuthority,
  93. 2,
  94. SECURITY_BUILTIN_DOMAIN_RID,
  95. DOMAIN_ALIAS_RID_ADMINS,
  96. 0, 0, 0, 0, 0, 0,
  97. &g_pAdminSid);
  98. bSuccess = bSuccess && AllocateAndInitializeSid( &NtAuthority,
  99. 1,
  100. SECURITY_LOCAL_SYSTEM_RID,
  101. 0, 0, 0, 0, 0, 0, 0,
  102. &g_pSystemSid);
  103. if (bSuccess) {
  104. //
  105. // Initialize Access structures describing the ACEs we want:
  106. // System Full Control
  107. // Admins Full Control
  108. //
  109. // We'll take advantage of the fact that the unlocked private keys is
  110. // the same as the device parameters key and they are a superset of the
  111. // locked private keys.
  112. //
  113. // When we create the DACL for the private key we'll specify a subset of
  114. // the ExplicitAccess array.
  115. //
  116. for (i = 0; i < 2; i++) {
  117. ExplicitAccess[i].grfAccessMode = SET_ACCESS;
  118. ExplicitAccess[i].grfInheritance = CONTAINER_INHERIT_ACE;
  119. ExplicitAccess[i].Trustee.pMultipleTrustee = NULL;
  120. ExplicitAccess[i].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  121. ExplicitAccess[i].Trustee.TrusteeForm = TRUSTEE_IS_SID;
  122. ExplicitAccess[i].Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  123. }
  124. ExplicitAccess[0].grfAccessPermissions = KEY_ALL_ACCESS;
  125. ExplicitAccess[0].Trustee.ptstrName = (LPTSTR)g_pSystemSid;
  126. ExplicitAccess[1].grfAccessPermissions = KEY_ALL_ACCESS;
  127. ExplicitAccess[1].Trustee.ptstrName = (LPTSTR)g_pAdminSid;
  128. //
  129. // Create the DACL with the both the above ACEs for the DeviceParameters
  130. //
  131. dwError = SetEntriesInAcl( 2,
  132. ExplicitAccess,
  133. NULL,
  134. &g_pDeviceParametersDacl );
  135. if (dwError == ERROR_SUCCESS)
  136. {
  137. //
  138. // Create the DACL with just the system ACE for the locked private
  139. // keys.
  140. //
  141. dwError = SetEntriesInAcl( 1,
  142. ExplicitAccess,
  143. NULL,
  144. &g_pLockedPrivateKeysDacl );
  145. }
  146. bSuccess = dwError == ERROR_SUCCESS;
  147. }
  148. //
  149. // Initialize the DeviceParameters security descriptor
  150. //
  151. bSuccess = bSuccess && InitializeSecurityDescriptor( &g_DeviceParametersSD,
  152. SECURITY_DESCRIPTOR_REVISION );
  153. //
  154. // Set the new DACL in the security descriptor
  155. //
  156. bSuccess = bSuccess && SetSecurityDescriptorDacl( &g_DeviceParametersSD,
  157. TRUE,
  158. g_pDeviceParametersDacl,
  159. FALSE);
  160. //
  161. // validate the new security descriptor
  162. //
  163. bSuccess = bSuccess && IsValidSecurityDescriptor( &g_DeviceParametersSD );
  164. //
  165. // Initialize the DeviceParameters security descriptor
  166. //
  167. bSuccess = bSuccess && InitializeSecurityDescriptor( &g_LockedPrivateKeysSD,
  168. SECURITY_DESCRIPTOR_REVISION );
  169. //
  170. // Set the new DACL in the security descriptor
  171. //
  172. bSuccess = bSuccess && SetSecurityDescriptorDacl( &g_LockedPrivateKeysSD,
  173. TRUE,
  174. g_pLockedPrivateKeysDacl,
  175. FALSE);
  176. //
  177. // validate the new security descriptor
  178. //
  179. bSuccess = bSuccess && IsValidSecurityDescriptor( &g_LockedPrivateKeysSD );
  180. if (!bSuccess) {
  181. FreeSecurityDescriptors();
  182. }
  183. return bSuccess;
  184. }
  185. VOID
  186. EnumKeysAndApplyDacls(
  187. IN HKEY hParentKey,
  188. IN LPTSTR pszKeyName,
  189. IN DWORD dwLevel,
  190. IN BOOL bInDeviceParameters,
  191. IN BOOL bApplyTopDown,
  192. IN PSECURITY_DESCRIPTOR pPrivateKeySD,
  193. IN PSECURITY_DESCRIPTOR pDeviceParametersSD
  194. )
  195. /*++
  196. Routine Description:
  197. This function applies the DACL in pSD to all the keys rooted at hKey
  198. including hKey itself.
  199. Arguments:
  200. hParentKey Handle to a registry key.
  201. pszKeyName Name of the key.
  202. dwLevel Number of levels remaining to recurse.
  203. pSD Pointer to a security descriptor containing a DACL.
  204. Return Value:
  205. None.
  206. --*/
  207. {
  208. LONG RegStatus;
  209. DWORD dwMaxSubKeySize;
  210. LPTSTR pszSubKey;
  211. DWORD index;
  212. HKEY hKey;
  213. BOOL bNewInDeviceParameters;
  214. #if DBG || UMODETEST
  215. DWORD dwStartKeyNameLength = g_dwCurrentKeyNameLength;
  216. if (g_dwCurrentKeyNameLength != 0) {
  217. g_szCurrentKeyName[ g_dwCurrentKeyNameLength++ ] = TEXT('\\');
  218. }
  219. _tcscpy(&g_szCurrentKeyName[g_dwCurrentKeyNameLength], pszKeyName);
  220. g_dwCurrentKeyNameLength += _tcslen(pszKeyName);
  221. #endif
  222. DBGTRACE( DBGF_REGISTRY,
  223. (TEXT("EnumKeysAndApplyDacls(0x%08X, \"%s\", %d, %s, %s, 0x%08X, 0x%08X)\n"),
  224. hParentKey,
  225. g_szCurrentKeyName,
  226. dwLevel,
  227. bInDeviceParameters ? TEXT("TRUE") : TEXT("FALSE"),
  228. bApplyTopDown ? TEXT("TRUE") : TEXT("FALSE"),
  229. pPrivateKeySD,
  230. pDeviceParametersSD) );
  231. if (bApplyTopDown) {
  232. RegStatus = RegOpenKeyEx( hParentKey,
  233. pszKeyName,
  234. 0,
  235. WRITE_DAC,
  236. &hKey
  237. );
  238. if (RegStatus != ERROR_SUCCESS) {
  239. DBGTRACE( DBGF_ERRORS,
  240. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegOpenKeyEx() failed, error = %d\n"),
  241. g_szCurrentKeyName, RegStatus));
  242. return;
  243. }
  244. DBGTRACE( DBGF_REGISTRY,
  245. (TEXT("Setting security on %s on the way down\n"),
  246. g_szCurrentKeyName) );
  247. //
  248. // apply the new security to the registry key
  249. //
  250. RegStatus = RegSetKeySecurity( hKey,
  251. DACL_SECURITY_INFORMATION,
  252. bInDeviceParameters ?
  253. pDeviceParametersSD :
  254. pPrivateKeySD
  255. );
  256. if (RegStatus != ERROR_SUCCESS) {
  257. DBGTRACE( DBGF_ERRORS,
  258. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegSetKeySecurity() failed, error = %d\n"),
  259. g_szCurrentKeyName, RegStatus));
  260. }
  261. //
  262. // Close the key and reopen it later for read (which hopefully was just
  263. // granted in the DACL we just wrote
  264. //
  265. RegCloseKey( hKey );
  266. }
  267. RegStatus = RegOpenKeyEx( hParentKey,
  268. pszKeyName,
  269. 0,
  270. KEY_READ | WRITE_DAC,
  271. &hKey
  272. );
  273. if (RegStatus != ERROR_SUCCESS) {
  274. DBGTRACE( DBGF_ERRORS,
  275. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegOpenKeyEx() failed, error = %d\n"),
  276. g_szCurrentKeyName, RegStatus));
  277. return;
  278. }
  279. //
  280. // Determine length of longest subkey
  281. //
  282. RegStatus = RegQueryInfoKey( hKey,
  283. NULL,
  284. NULL,
  285. NULL,
  286. NULL,
  287. &dwMaxSubKeySize,
  288. NULL,
  289. NULL,
  290. NULL,
  291. NULL,
  292. NULL,
  293. NULL );
  294. if (RegStatus == ERROR_SUCCESS) {
  295. //
  296. // Allocate a buffer to hold the subkey names. RegQueryInfoKey returns the
  297. // size in characters and doesn't include the NUL terminator.
  298. //
  299. pszSubKey = LocalAlloc(0, ++dwMaxSubKeySize * sizeof(TCHAR));
  300. if (pszSubKey != NULL) {
  301. //
  302. // Enumerate all the subkeys and then call ourselves recursively for each
  303. // until dwLevel reaches 0.
  304. //
  305. for (index = 0; ; index++) {
  306. RegStatus = RegEnumKey( hKey,
  307. index,
  308. pszSubKey,
  309. dwMaxSubKeySize
  310. );
  311. if (RegStatus != ERROR_SUCCESS) {
  312. if (RegStatus != ERROR_NO_MORE_ITEMS) {
  313. DBGTRACE( DBGF_ERRORS,
  314. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegEnumKeyEx() failed, error = %d\n"),
  315. g_szCurrentKeyName,
  316. RegStatus) );
  317. }
  318. break;
  319. }
  320. bNewInDeviceParameters = bInDeviceParameters ||
  321. (dwLevel == 3 &&
  322. _tcsicmp( pszSubKey,
  323. REGSTR_KEY_DEVICEPARAMETERS ) == 0);
  324. EnumKeysAndApplyDacls( hKey,
  325. pszSubKey,
  326. dwLevel + 1,
  327. bNewInDeviceParameters,
  328. bApplyTopDown,
  329. pPrivateKeySD,
  330. pDeviceParametersSD
  331. );
  332. }
  333. LocalFree( pszSubKey );
  334. }
  335. }
  336. else
  337. {
  338. DBGTRACE( DBGF_ERRORS,
  339. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegQueryInfoKey() failed, error = %d\n"),
  340. g_szCurrentKeyName, RegStatus));
  341. }
  342. if (!bApplyTopDown) {
  343. DBGTRACE( DBGF_REGISTRY,
  344. (TEXT("Setting security on %s on the way back up\n"),
  345. g_szCurrentKeyName) );
  346. //
  347. // apply the new security to the registry key
  348. //
  349. RegStatus = RegSetKeySecurity( hKey,
  350. DACL_SECURITY_INFORMATION,
  351. bInDeviceParameters ?
  352. pDeviceParametersSD :
  353. pPrivateKeySD
  354. );
  355. if (RegStatus != ERROR_SUCCESS) {
  356. DBGTRACE( DBGF_ERRORS,
  357. (TEXT("EnumKeysAndApplyDacls(\"%s\") RegSetKeySecurity() failed, error = %d\n"),
  358. g_szCurrentKeyName, RegStatus));
  359. }
  360. }
  361. RegCloseKey( hKey );
  362. #if DBG || UMODETEST
  363. g_dwCurrentKeyNameLength = dwStartKeyNameLength;
  364. g_szCurrentKeyName[g_dwCurrentKeyNameLength] = TEXT('\0');
  365. #endif
  366. }
  367. VOID
  368. LockUnlockEnumTree(
  369. LPTSTR pszMachineName,
  370. BOOL bLock
  371. )
  372. {
  373. PSECURITY_DESCRIPTOR pSD;
  374. HKEY hParentKey;
  375. LONG RegStatus;
  376. if (pszMachineName != NULL) {
  377. RegStatus = RegConnectRegistry( pszMachineName,
  378. HKEY_LOCAL_MACHINE,
  379. &hParentKey );
  380. if (RegStatus != ERROR_SUCCESS) {
  381. DBGTRACE( DBGF_ERRORS,
  382. (TEXT("Could not connect to remote registry on %s, status = %d\n"),
  383. pszMachineName,
  384. RegStatus) );
  385. }
  386. } else {
  387. hParentKey = HKEY_LOCAL_MACHINE;
  388. }
  389. if (CreateSecurityDescriptors()) {
  390. EnumKeysAndApplyDacls( hParentKey,
  391. REGSTR_PATH_SYSTEMENUM,
  392. 0,
  393. FALSE,
  394. !bLock,
  395. bLock ? &g_LockedPrivateKeysSD : &g_DeviceParametersSD,
  396. &g_DeviceParametersSD
  397. );
  398. FreeSecurityDescriptors();
  399. }
  400. }
  401. #if DBG || UMODETEST
  402. void
  403. RegFixDebugMessage(LPWSTR format, ...)
  404. {
  405. va_list args;
  406. va_start(args, format);
  407. _vtprintf(format, args);
  408. }
  409. #endif
  410. #if UMODETEST
  411. void
  412. usage(int argc, TCHAR **argv)
  413. {
  414. PTCHAR pszProgram;
  415. if ((pszProgram = _tcsrchr(argv[0], TEXT('\\'))) != NULL) {
  416. pszProgram++;
  417. } else {
  418. pszProgram = argv[0];
  419. }
  420. _tprintf(TEXT("%s: Lock or Unlock PnP Registry (Enum key)\n\n"), pszProgram);
  421. _tprintf(TEXT("Usage: %s [-m <machine>] -l | -u\n"), pszProgram);
  422. _tprintf(TEXT(" -m <machine> Remote machine without leading \\\\\n"));
  423. _tprintf(TEXT(" -l Locks Enum key\n"));
  424. _tprintf(TEXT(" -u Unlocks Enum key\n\n"));
  425. _tprintf(TEXT("Note: -m is optional. Only one of -l or -u may be used.\n"));
  426. }
  427. int __cdecl
  428. _tmain(int argc, TCHAR **argv)
  429. {
  430. LPTSTR pszMachineName = NULL;
  431. LPTSTR pszArg;
  432. int idxArg;
  433. if ( argc == 1 )
  434. {
  435. usage(argc, argv);
  436. return 0;
  437. }
  438. for (idxArg = 1; idxArg < argc; idxArg++)
  439. {
  440. pszArg = argv[ idxArg ];
  441. if (*pszArg == '/' || *pszArg == '-')
  442. {
  443. pszArg++;
  444. while (pszArg != NULL && *pszArg != '\0') {
  445. switch (*pszArg)
  446. {
  447. case '/': // Ignore these, caused by cmds like /m/l
  448. pszArg++;
  449. break;
  450. case 'l':
  451. case 'L':
  452. pszArg++;
  453. LockUnlockEnumTree( pszMachineName, TRUE );
  454. break;
  455. case 'm':
  456. case 'M':
  457. pszArg++;
  458. if (*pszArg == ':' || *pszArg == '=')
  459. {
  460. if (pszArg[ 1 ] != '\0')
  461. {
  462. pszMachineName = ++pszArg;
  463. }
  464. }
  465. else if (*pszArg != '\0')
  466. {
  467. pszMachineName = pszArg;
  468. }
  469. else if ((idxArg + 1) < argc && (argv[ idxArg + 1 ][0] != '/' && argv[ idxArg + 1 ][0] != '-'))
  470. {
  471. pszMachineName = argv[ ++idxArg ];
  472. }
  473. if (pszMachineName == NULL)
  474. {
  475. _tprintf(
  476. TEXT("%c%c : missing machine name argument\n"),
  477. argv[ idxArg ][ 0 ], pszArg [ - 1 ]
  478. );
  479. usage(argc, argv);
  480. return 1;
  481. }
  482. pszArg = NULL;
  483. break;
  484. case 'u':
  485. case 'U':
  486. pszArg++;
  487. LockUnlockEnumTree( pszMachineName, FALSE );
  488. break;
  489. case 'v':
  490. case 'V':
  491. pszArg++;
  492. g_RegFixDebugFlag |= DBGF_REGISTRY;
  493. break;
  494. default:
  495. _tprintf(
  496. TEXT("%c%c : invalid option\n"),
  497. argv[ idxArg ][ 0 ], *pszArg
  498. );
  499. break;
  500. }
  501. }
  502. }
  503. }
  504. return 0;
  505. }
  506. #endif