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.

735 lines
21 KiB

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