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.

1694 lines
48 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. SafeInit.c (WinSAFER Initialization)
  5. Abstract:
  6. This module implements the WinSAFER APIs to initialize and
  7. deinitialize all housekeeping and handle tracking structures.
  8. Author:
  9. Jeffrey Lawson (JLawson) - Nov 1999
  10. Environment:
  11. User mode only.
  12. Exported Functions:
  13. CodeAuthzInitialize (privately exported)
  14. SaferiChangeRegistryScope (privately exported)
  15. Revision History:
  16. Created - Nov 1999
  17. --*/
  18. #include "pch.h"
  19. #pragma hdrstop
  20. #include <winsafer.h>
  21. #include <winsaferp.h>
  22. #include <winsafer.rh>
  23. #include "saferp.h"
  24. //#define SAFER_REGISTRY_NOTIFICATIONS
  25. //
  26. // Controls the maximum number of level handles that we will
  27. // permit to be opened at any time.
  28. //
  29. #define MAXIMUM_LEVEL_HANDLES 64
  30. //
  31. // Various globals that are used for the cache of levels and
  32. // identities so that we do not need to go to the registry each time.
  33. //
  34. BOOLEAN g_bInitializedFirstTime = FALSE;
  35. CRITICAL_SECTION g_TableCritSec;
  36. HANDLE g_hKeyCustomRoot;
  37. DWORD g_dwKeyOptions;
  38. DWORD g_dwLevelHandleSequence = 1; // monotonically increasing
  39. DWORD g_dwNumHandlesAllocated = 0; // Number of outstanding handles
  40. //
  41. // All of the following global variables are cached settings that are
  42. // read and parsed from the policy the first time it is needed.
  43. // All of the variables within this block should be considered "stale"
  44. // when the g_bNeedCacheReload flag is TRUE.
  45. //
  46. BOOLEAN g_bNeedCacheReload; // indicates the following vars are stale.
  47. RTL_GENERIC_TABLE g_CodeLevelObjTable;
  48. RTL_GENERIC_TABLE g_CodeIdentitiesTable;
  49. RTL_HANDLE_TABLE g_LevelHandleTable;
  50. BOOLEAN g_bHonorScopeUser;
  51. PAUTHZLEVELTABLERECORD g_DefaultCodeLevel; // effective
  52. PAUTHZLEVELTABLERECORD g_DefaultCodeLevelUser;
  53. PAUTHZLEVELTABLERECORD g_DefaultCodeLevelMachine;
  54. LARGE_INTEGER g_SaferPolicyTimeStamp;
  55. //
  56. // Handles used to receive registry change notifications against the
  57. // currently loaded policy and invalidate the internal cache.
  58. //
  59. #ifdef SAFER_REGISTRY_NOTIFICATIONS
  60. HANDLE g_hRegNotifyEvent; // from CreateEvent
  61. HANDLE g_hWaitNotifyObject; // from RegisterWaitForSingleObject
  62. HANDLE g_hKeyNotifyBase1, g_hKeyNotifyBase2;
  63. #endif
  64. NTSTATUS NTAPI
  65. SaferpSetSingleIdentificationPath(
  66. IN BOOLEAN bAllowCreation,
  67. IN OUT PAUTHZIDENTSTABLERECORD pIdentRecord,
  68. IN PSAFER_PATHNAME_IDENTIFICATION pIdentChanges,
  69. IN BOOL UpdateCache
  70. );
  71. FORCEINLINE BOOLEAN
  72. CodeAuthzpIsPowerOfTwo(
  73. ULONG ulValue
  74. )
  75. /*++
  76. Routine Description:
  77. Determines if the specified value is a whole power of 2.
  78. (ie, exactly one of the following: 1, 2, 4, 8, 16, 32, 64, ...)
  79. Arguments:
  80. ulValue - Integer value to test.
  81. Return Value:
  82. Returns TRUE on success, FALSE on failure.
  83. --*/
  84. {
  85. while (ulValue != 0) {
  86. if (ulValue & 1) {
  87. ulValue >>= 1;
  88. break;
  89. }
  90. ulValue >>= 1;
  91. }
  92. return (ulValue == 0);
  93. }
  94. FORCEINLINE ULONG
  95. CodeAuthzpMakePowerOfTwo(
  96. ULONG ulValue
  97. )
  98. /*++
  99. Routine Description:
  100. Rounds the specified number up to the next whole power of 2.
  101. (ie, exactly one of the following: 1, 2, 4, 8, 16, 32, 64, ...)
  102. Arguments:
  103. ulValue - Integer value to operate on.
  104. Return Value:
  105. Returns the rounded result.
  106. --*/
  107. {
  108. if (ulValue) {
  109. ULONG ulOriginal = ulValue;
  110. ULONG bitmask;
  111. for (bitmask = 1; ulValue != 0 && bitmask != 0 &&
  112. (ulValue & ~bitmask) != 0; bitmask <<= 1) {
  113. ulValue = ulValue & ~bitmask;
  114. }
  115. ASSERTMSG("failed to make a power of two",
  116. CodeAuthzpIsPowerOfTwo(ulValue));
  117. if (ulOriginal > ulValue) {
  118. // if we ended up rounding down, then round it up!
  119. ulValue <<= 1;
  120. }
  121. ASSERT(ulValue >= ulOriginal);
  122. }
  123. return ulValue;
  124. }
  125. BOOLEAN
  126. CodeAuthzInitialize (
  127. IN HANDLE Handle,
  128. IN DWORD Reason,
  129. IN PVOID Reserved
  130. )
  131. /*++
  132. Routine Description:
  133. This is the callback procedure used by the Advapi initialization
  134. and deinitialization.
  135. Arguments:
  136. Handle -
  137. Reason -
  138. Reserved -
  139. Return Value:
  140. Returns TRUE on success, FALSE on failure.
  141. --*/
  142. {
  143. NTSTATUS Status;
  144. UNREFERENCED_PARAMETER(Reserved);
  145. UNREFERENCED_PARAMETER(Handle);
  146. if (Reason == DLL_PROCESS_ATTACH) {
  147. Status = CodeAuthzInitializeGlobals();
  148. if (!NT_SUCCESS(Status)) return FALSE;
  149. } else if (Reason == DLL_PROCESS_DETACH) {
  150. CodeAuthzDeinitializeGlobals();
  151. }
  152. return TRUE;
  153. }
  154. #ifdef SAFER_REGISTRY_NOTIFICATIONS
  155. static VOID NTAPI
  156. SaferpRegistryNotificationRegister(VOID)
  157. {
  158. if (g_hRegNotifyEvent != NULL)
  159. {
  160. // Note that it is okay to call RNCKV again on the same
  161. // registry handle even if there is still an outstanding
  162. // change notification registered.
  163. if (g_hKeyNotifyBase1 != NULL) {
  164. RegNotifyChangeKeyValue(
  165. g_hKeyNotifyBase1, TRUE,
  166. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
  167. g_hRegNotifyEvent,
  168. TRUE);
  169. }
  170. if (g_hKeyNotifyBase2 != NULL) {
  171. RegNotifyChangeKeyValue(
  172. g_hKeyNotifyBase2, TRUE,
  173. REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
  174. g_hRegNotifyEvent,
  175. TRUE);
  176. }
  177. }
  178. }
  179. static VOID NTAPI
  180. SaferpRegistryNotificationCallback (PVOID pvArg1, BOOLEAN bArg2)
  181. {
  182. UNREFERENCED_PARAMETER(pvArg1);
  183. UNREFERENCED_PARAMETER(bArg2);
  184. g_bNeedCacheReload = TRUE;
  185. }
  186. #endif
  187. NTSTATUS NTAPI
  188. CodeAuthzInitializeGlobals(VOID)
  189. /*++
  190. Routine Description:
  191. Performs one-time startup operations that should be done before
  192. any other handle or cache table operations are attempted.
  193. Arguments:
  194. nothing
  195. Return Value:
  196. Returns STATUS_SUCCESS on success.
  197. --*/
  198. {
  199. NTSTATUS Status;
  200. ULONG ulHandleEntrySize;
  201. if (g_bInitializedFirstTime) {
  202. // Already initialized.
  203. return STATUS_SUCCESS;
  204. }
  205. //
  206. // Initialize a bunch of tables for their first usage.
  207. //
  208. Status = RtlInitializeCriticalSection(&g_TableCritSec);
  209. if (!NT_SUCCESS(Status)) {
  210. return Status;
  211. }
  212. g_bInitializedFirstTime = g_bNeedCacheReload = TRUE;
  213. CodeAuthzLevelObjpInitializeTable(&g_CodeLevelObjTable);
  214. CodeAuthzGuidIdentsInitializeTable(&g_CodeIdentitiesTable);
  215. g_hKeyCustomRoot = NULL;
  216. g_dwKeyOptions = 0;
  217. //
  218. // Initialize the table that will be used to track opened
  219. // WinSafer Level handles. Note that RtlInitializeHandleTable
  220. // requires a structure size that is a whole power of 2.
  221. //
  222. ulHandleEntrySize = CodeAuthzpMakePowerOfTwo(sizeof(AUTHZLEVELHANDLESTRUCT));
  223. RtlInitializeHandleTable(
  224. MAXIMUM_LEVEL_HANDLES,
  225. ulHandleEntrySize, // was sizeof(AUTHZLEVELHANDLESTRUCT)
  226. &g_LevelHandleTable);
  227. g_dwNumHandlesAllocated = 0;
  228. #ifdef SAFER_REGISTRY_NOTIFICATIONS
  229. //
  230. // Create the event to catch modifications to the registry changes.
  231. // This allows us to notice policy changes and reload as necessary.
  232. //
  233. g_hRegNotifyEvent = CreateEvent(
  234. NULL, // Security Descriptor
  235. TRUE, // reset type
  236. FALSE, // initial state
  237. NULL // object name
  238. );
  239. if (g_hRegNotifyEvent != INVALID_HANDLE_VALUE) {
  240. if (!RegisterWaitForSingleObject(
  241. &g_hWaitNotifyObject,
  242. g_hRegNotifyEvent,
  243. SaferpRegistryNotificationCallback,
  244. NULL,
  245. INFINITE,
  246. WT_EXECUTEINWAITTHREAD))
  247. {
  248. CloseHandle(g_hRegNotifyEvent);
  249. g_hRegNotifyEvent = g_hWaitNotifyObject = NULL;
  250. }
  251. } else {
  252. g_hRegNotifyEvent = g_hWaitNotifyObject = NULL;
  253. }
  254. g_hKeyNotifyBase1 = g_hKeyNotifyBase2 = NULL;
  255. #endif
  256. return STATUS_SUCCESS;
  257. }
  258. VOID NTAPI
  259. CodeAuthzDeinitializeGlobals(VOID)
  260. /*++
  261. Routine Description:
  262. Performs one-time deinitialization operations.
  263. Arguments:
  264. nothing
  265. Return Value:
  266. Returns STATUS_SUCCESS on success.
  267. --*/
  268. {
  269. if (g_bInitializedFirstTime) {
  270. #ifdef SAFER_REGISTRY_NOTIFICATIONS
  271. if (g_hWaitNotifyObject != NULL) {
  272. UnregisterWait(g_hWaitNotifyObject);
  273. CloseHandle(g_hWaitNotifyObject);
  274. }
  275. if (g_hRegNotifyEvent != NULL) {
  276. CloseHandle(g_hRegNotifyEvent);
  277. }
  278. if (g_hKeyNotifyBase1 != NULL) {
  279. NtClose(g_hKeyNotifyBase1);
  280. }
  281. if (g_hKeyNotifyBase2 != NULL) {
  282. NtClose(g_hKeyNotifyBase2);
  283. }
  284. #endif
  285. CodeAuthzLevelObjpEntireTableFree(&g_CodeLevelObjTable);
  286. CodeAuthzGuidIdentsEntireTableFree(&g_CodeIdentitiesTable);
  287. RtlDestroyHandleTable(&g_LevelHandleTable);
  288. g_dwNumHandlesAllocated = 0;
  289. if (g_hKeyCustomRoot != NULL) {
  290. NtClose(g_hKeyCustomRoot);
  291. g_hKeyCustomRoot = NULL;
  292. g_dwKeyOptions = 0;
  293. }
  294. g_bInitializedFirstTime = FALSE;
  295. RtlDeleteCriticalSection(&g_TableCritSec);
  296. }
  297. }
  298. BOOL WINAPI
  299. SaferiChangeRegistryScope(
  300. IN HKEY hKeyCustomRoot OPTIONAL,
  301. IN DWORD dwKeyOptions
  302. )
  303. /*++
  304. Routine Description:
  305. Closes and invalidates all currently open level handles and
  306. reloads all cached levels and identities. The outstanding
  307. handles are closed and freed during this operation.
  308. If a hKeyCustomRoot is specified, all future level and identity
  309. operations will be performed on the levels and identies defined
  310. within that registry scope. Otherwise, such operations will be
  311. done on the normal HKLM/HKCU policy store locations.
  312. Arguments:
  313. hKeyCustomRoot - If specified, this should be an opened
  314. registry key handle to the base of the policy
  315. storage that should be used for all future operations.
  316. dwKeyOptions - Additional flags that should be passed in with
  317. the dwOptions parameter to any RegCreateKey operations,
  318. such as REG_OPTION_VOLATILE.
  319. Return Value:
  320. Returns TRUE on success, FALSE on failure. On error, GetLastError()
  321. will return a more specific indicator of the nature of the failure.
  322. --*/
  323. {
  324. NTSTATUS Status;
  325. Status = CodeAuthzReloadCacheTables(
  326. (HANDLE) hKeyCustomRoot,
  327. dwKeyOptions,
  328. FALSE
  329. );
  330. if (NT_SUCCESS(Status)) {
  331. return TRUE;
  332. } else {
  333. BaseSetLastNTError(Status);
  334. return FALSE;
  335. }
  336. }
  337. NTSTATUS NTAPI
  338. CodeAuthzReloadCacheTables(
  339. IN HANDLE hKeyCustomRoot OPTIONAL,
  340. IN DWORD dwKeyOptions,
  341. IN BOOLEAN bImmediateLoad
  342. )
  343. /*++
  344. Routine Description:
  345. Closes and invalidates all currently open level handles and
  346. reloads all cached levels and identities. The outstanding
  347. handles are closed and freed during this operation.
  348. If a hKeyCustomRoot is specified, all future level and identity
  349. operations will be performed on the levels and identies defined
  350. within that registry scope. Otherwise, such operations will be
  351. done on the normal HKLM/HKCU policy store locations.
  352. Arguments:
  353. hKeyCustomRoot - If specified, this should be an opened
  354. registry key handle to the base of the policy
  355. storage that should be used for all future operations.
  356. bPopulateDefaults - If TRUE, then the default set of Level definitions
  357. will be inserted into the Registry if no existing Levels
  358. were found at the specified scope.
  359. Return Value:
  360. Returns STATUS_SUCCESS on success.
  361. --*/
  362. {
  363. NTSTATUS Status = STATUS_SUCCESS;
  364. //
  365. // Ensure that the general globals have been initialized.
  366. //
  367. if (!g_bInitializedFirstTime) {
  368. Status = STATUS_UNSUCCESSFUL;
  369. goto ExitHandler;
  370. }
  371. RtlEnterCriticalSection(&g_TableCritSec);
  372. //
  373. // Initialize and blank out the tables we will be using.
  374. //
  375. CodeAuthzLevelObjpEntireTableFree(&g_CodeLevelObjTable);
  376. CodeAuthzGuidIdentsEntireTableFree(&g_CodeIdentitiesTable);
  377. //
  378. // Increment the sequence number. This has the effect of
  379. // immediately invalidating all currently open handles, but
  380. // allows the caller to still close them properly. Any
  381. // attempt by the caller to actually use one of the old
  382. // handles will result in a STATUS_INVALID_HANDLE error.
  383. //
  384. g_dwLevelHandleSequence++;
  385. //
  386. // Reset the rest of our variables.
  387. //
  388. if (g_hKeyCustomRoot != NULL) {
  389. NtClose(g_hKeyCustomRoot);
  390. g_hKeyCustomRoot = NULL;
  391. }
  392. #ifdef SAFER_REGISTRY_NOTIFICATIONS
  393. if (g_hKeyNotifyBase1 != NULL) {
  394. NtClose(g_hKeyNotifyBase1);
  395. g_hKeyNotifyBase1 = NULL;
  396. }
  397. if (g_hKeyNotifyBase2 != NULL) {
  398. NtClose(g_hKeyNotifyBase2);
  399. g_hKeyNotifyBase2 = NULL;
  400. }
  401. #endif
  402. g_DefaultCodeLevel = g_DefaultCodeLevelMachine =
  403. g_DefaultCodeLevelUser = NULL;
  404. g_bHonorScopeUser = FALSE;
  405. g_bNeedCacheReload = FALSE;
  406. g_dwKeyOptions = 0;
  407. //
  408. // Save a duplicated copy of the custom registry handle.
  409. //
  410. if (ARGUMENT_PRESENT(hKeyCustomRoot))
  411. {
  412. const static UNICODE_STRING SubKeyName = { 0, 0, NULL };
  413. OBJECT_ATTRIBUTES ObjectAttributes;
  414. InitializeObjectAttributes(&ObjectAttributes,
  415. (PUNICODE_STRING) &SubKeyName,
  416. OBJ_CASE_INSENSITIVE,
  417. hKeyCustomRoot,
  418. NULL
  419. );
  420. Status = NtOpenKey(&g_hKeyCustomRoot,
  421. KEY_READ,
  422. &ObjectAttributes);
  423. if (!NT_SUCCESS(Status)) {
  424. goto ExitHandler2;
  425. }
  426. g_dwKeyOptions = dwKeyOptions;
  427. #ifdef SAFER_REGISTRY_NOTIFICATIONS
  428. #error "open for KEY_NOTIFY"
  429. #endif
  430. }
  431. else
  432. {
  433. #ifdef SAFER_REGISTRY_NOTIFICATIONS
  434. #endif
  435. }
  436. //
  437. // Perform the actual load now, if needed.
  438. //
  439. g_bNeedCacheReload = TRUE;
  440. if (bImmediateLoad) {
  441. Status = CodeAuthzpImmediateReloadCacheTables();
  442. } else {
  443. Status = STATUS_SUCCESS;
  444. }
  445. ExitHandler2:
  446. RtlLeaveCriticalSection(&g_TableCritSec);
  447. ExitHandler:
  448. return Status;
  449. }
  450. NTSTATUS NTAPI
  451. CodeAuthzpImmediateReloadCacheTables(
  452. VOID
  453. )
  454. /*++
  455. Routine Description:
  456. Assumes that CodeAuthzReloadCacheTables() has already been called
  457. with the specified scope already, and that this function has not
  458. yet been called since the last reload.
  459. Arguments:
  460. none
  461. Return Value:
  462. returns STATUS_SUCCESS on successful completion.
  463. --*/
  464. {
  465. NTSTATUS Status;
  466. DWORD dwFlagValue;
  467. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  468. ASSERT(RtlIsGenericTableEmpty(&g_CodeIdentitiesTable) &&
  469. RtlIsGenericTableEmpty(&g_CodeLevelObjTable));
  470. ASSERT(g_bNeedCacheReload != FALSE);
  471. //
  472. // Need to clear the cache reload flag, otherwise we
  473. // might cause undesired infinite recursion later with
  474. // some of the CodeAuthzPol_xxx functions.
  475. //
  476. g_bNeedCacheReload = FALSE;
  477. //
  478. // Begin loading the new policy settings from the specified location.
  479. //
  480. if (g_hKeyCustomRoot != NULL)
  481. {
  482. //
  483. // Read in the definitions of all WinSafer Levels from
  484. // the custom registry root specified.
  485. //
  486. CodeAuthzLevelObjpLoadTable(
  487. &g_CodeLevelObjTable,
  488. SAFER_SCOPEID_REGISTRY,
  489. g_hKeyCustomRoot);
  490. //
  491. // The HonorScopeUser flag is not relevant when a custom
  492. // registry scope is used, but we set it to false anyways.
  493. //
  494. g_bHonorScopeUser = FALSE;
  495. //
  496. // Load the Code Identities from the custom registry root.
  497. //
  498. CodeAuthzGuidIdentsLoadTableAll(
  499. &g_CodeLevelObjTable,
  500. &g_CodeIdentitiesTable,
  501. SAFER_SCOPEID_REGISTRY,
  502. g_hKeyCustomRoot);
  503. //
  504. // Load the Default Level specified by the custom registry root.
  505. //
  506. Status = CodeAuthzPol_GetInfoRegistry_DefaultLevel(
  507. SAFER_SCOPEID_REGISTRY,
  508. sizeof(DWORD), &dwFlagValue, NULL);
  509. if (NT_SUCCESS(Status)) {
  510. g_DefaultCodeLevelMachine =
  511. CodeAuthzLevelObjpLookupByLevelId(
  512. &g_CodeLevelObjTable, dwFlagValue);
  513. } else {
  514. g_DefaultCodeLevelMachine = NULL;
  515. }
  516. g_DefaultCodeLevelUser = NULL;
  517. }
  518. else // !ARGUMENT_PRESENT(hKeyCustomRoot)
  519. {
  520. g_hKeyCustomRoot = NULL;
  521. //
  522. // Read in the definitions of all WinSafer Levels from
  523. // the HKEY_LOCAL_MACHINE registry scope.
  524. //
  525. CodeAuthzLevelObjpLoadTable(
  526. &g_CodeLevelObjTable,
  527. SAFER_SCOPEID_MACHINE,
  528. NULL);
  529. g_bHonorScopeUser = TRUE;
  530. //
  531. // Load in all Code Identities from the HKEY_LOCAL_MACHINE
  532. // and possibly the HKEY_CURRENT_USER scope too.
  533. //
  534. CodeAuthzGuidIdentsLoadTableAll(
  535. &g_CodeLevelObjTable,
  536. &g_CodeIdentitiesTable,
  537. SAFER_SCOPEID_MACHINE,
  538. NULL);
  539. if (g_bHonorScopeUser) {
  540. CodeAuthzGuidIdentsLoadTableAll(
  541. &g_CodeLevelObjTable,
  542. &g_CodeIdentitiesTable,
  543. SAFER_SCOPEID_USER,
  544. NULL);
  545. }
  546. //
  547. // Load the Default Level specified by the machine scope.
  548. //
  549. Status = CodeAuthzPol_GetInfoRegistry_DefaultLevel(
  550. SAFER_SCOPEID_MACHINE,
  551. sizeof(DWORD), &dwFlagValue, NULL);
  552. if (NT_SUCCESS(Status)) {
  553. g_DefaultCodeLevelMachine =
  554. CodeAuthzLevelObjpLookupByLevelId(
  555. &g_CodeLevelObjTable, dwFlagValue);
  556. } else {
  557. g_DefaultCodeLevelMachine = NULL;
  558. }
  559. //
  560. // Load the Default Level specified by the user scope.
  561. //
  562. Status = CodeAuthzPol_GetInfoRegistry_DefaultLevel(
  563. SAFER_SCOPEID_USER,
  564. sizeof(DWORD), &dwFlagValue, NULL);
  565. if (NT_SUCCESS(Status)) {
  566. g_DefaultCodeLevelUser =
  567. CodeAuthzLevelObjpLookupByLevelId(
  568. &g_CodeLevelObjTable, dwFlagValue);
  569. } else {
  570. g_DefaultCodeLevelUser = NULL;
  571. }
  572. }
  573. //
  574. // Compute the effective Default Level (take the least privileged).
  575. //
  576. CodeAuthzpRecomputeEffectiveDefaultLevel();
  577. GetSystemTimeAsFileTime((LPFILETIME) &g_SaferPolicyTimeStamp);
  578. //
  579. // Now that we have fully loaded the policy, set a change
  580. // notification hook so that we can be alerted to updates.
  581. //
  582. #ifdef SAFER_REGISTRY_NOTIFICATIONS
  583. g_bNeedCacheReload = FALSE;
  584. SaferpRegistryNotificationRegister();
  585. #endif
  586. return STATUS_SUCCESS;
  587. }
  588. VOID NTAPI
  589. CodeAuthzpRecomputeEffectiveDefaultLevel(
  590. VOID
  591. )
  592. /*++
  593. Routine Description:
  594. Arguments:
  595. nothing
  596. Return Value:
  597. nothing.
  598. --*/
  599. {
  600. if (g_DefaultCodeLevelMachine != NULL &&
  601. g_DefaultCodeLevelUser != NULL &&
  602. g_bHonorScopeUser)
  603. {
  604. g_DefaultCodeLevel =
  605. (g_DefaultCodeLevelMachine->dwLevelId <
  606. g_DefaultCodeLevelUser->dwLevelId ?
  607. g_DefaultCodeLevelMachine : g_DefaultCodeLevelUser);
  608. } else if (g_DefaultCodeLevelMachine != NULL) {
  609. g_DefaultCodeLevel = g_DefaultCodeLevelMachine;
  610. } else if (g_bHonorScopeUser) {
  611. g_DefaultCodeLevel = g_DefaultCodeLevelUser;
  612. } else {
  613. g_DefaultCodeLevel = NULL;
  614. }
  615. //
  616. // If we still don't have a default Level, then try to pick
  617. // the Fully Trusted level as default. It still might fail
  618. // in the case where the Fully Trusted level doesn't exist,
  619. // but that shouldn't ever happen.
  620. //
  621. if (!g_DefaultCodeLevel) {
  622. g_DefaultCodeLevel = CodeAuthzLevelObjpLookupByLevelId(
  623. &g_CodeLevelObjTable, SAFER_LEVELID_FULLYTRUSTED);
  624. // ASSERT(g_DefaultCodeLevel != NULL);
  625. }
  626. }
  627. NTSTATUS NTAPI
  628. CodeAuthzpDeleteKeyRecursively(
  629. IN HANDLE hBaseKey,
  630. IN PUNICODE_STRING pSubKey OPTIONAL
  631. )
  632. /*++
  633. Routine Description:
  634. Recursively delete the key, including all child values and keys.
  635. Arguments:
  636. hkey - the base registry key handle to start from.
  637. pszSubKey - subkey to delete from.
  638. Return Value:
  639. Returns ERROR_SUCCESS on success, otherwise error.
  640. --*/
  641. {
  642. NTSTATUS Status;
  643. BOOLEAN bCloseSubKey;
  644. HANDLE hSubKey;
  645. OBJECT_ATTRIBUTES ObjectAttributes;
  646. UNICODE_STRING UnicodeString;
  647. PKEY_BASIC_INFORMATION pKeyBasicInfo;
  648. DWORD dwQueryBufferSize = 0, dwActualSize = 0;
  649. //
  650. // Open the subkey so we can enumerate any children
  651. //
  652. if (ARGUMENT_PRESENT(pSubKey) &&
  653. pSubKey->Buffer != NULL)
  654. {
  655. InitializeObjectAttributes(&ObjectAttributes,
  656. pSubKey,
  657. OBJ_CASE_INSENSITIVE,
  658. hBaseKey,
  659. NULL
  660. );
  661. Status = NtOpenKey(&hSubKey, KEY_READ | DELETE, &ObjectAttributes);
  662. if (!NT_SUCCESS(Status)) {
  663. return Status;
  664. }
  665. bCloseSubKey = TRUE;
  666. } else {
  667. hSubKey = hBaseKey;
  668. bCloseSubKey = FALSE;
  669. }
  670. //
  671. // To delete a registry key, we must first ensure that all
  672. // children subkeys are deleted (registry values do not need
  673. // to be deleted in order to delete the key itself). To do
  674. // this we loop enumerate
  675. //
  676. dwQueryBufferSize = 256;
  677. pKeyBasicInfo = RtlAllocateHeap(RtlProcessHeap(), 0,
  678. dwQueryBufferSize);
  679. for (;;)
  680. {
  681. Status = NtEnumerateKey(
  682. hSubKey, 0, KeyBasicInformation,
  683. pKeyBasicInfo, dwQueryBufferSize, &dwActualSize);
  684. if (Status == STATUS_BUFFER_TOO_SMALL ||
  685. Status == STATUS_BUFFER_OVERFLOW)
  686. {
  687. if (dwActualSize <= dwQueryBufferSize) {
  688. ASSERT(FALSE);
  689. break; // should not happen, so stop now.
  690. }
  691. if (pKeyBasicInfo != NULL) {
  692. RtlFreeHeap(RtlProcessHeap(), 0, pKeyBasicInfo);
  693. }
  694. dwQueryBufferSize = dwActualSize; // request a little more.
  695. pKeyBasicInfo = RtlAllocateHeap(RtlProcessHeap(), 0,
  696. dwQueryBufferSize);
  697. if (!pKeyBasicInfo) {
  698. break; // stop now, but we don't care about the error.
  699. }
  700. Status = NtEnumerateKey(
  701. hSubKey, 0, KeyBasicInformation,
  702. pKeyBasicInfo, dwQueryBufferSize, &dwActualSize);
  703. }
  704. if (Status == STATUS_NO_MORE_ENTRIES) {
  705. // we've finished deleting all subkeys, stop now.
  706. Status = STATUS_SUCCESS;
  707. break;
  708. }
  709. if (!NT_SUCCESS(Status) || !pKeyBasicInfo) {
  710. break;
  711. }
  712. UnicodeString.Buffer = pKeyBasicInfo->Name;
  713. UnicodeString.MaximumLength = (USHORT) pKeyBasicInfo->NameLength;
  714. UnicodeString.Length = (USHORT) (pKeyBasicInfo->NameLength - sizeof(WCHAR));
  715. Status = CodeAuthzpDeleteKeyRecursively(hSubKey, &UnicodeString);
  716. if (!NT_SUCCESS(Status)) {
  717. break;
  718. }
  719. }
  720. if (pKeyBasicInfo != NULL) {
  721. RtlFreeHeap(RtlProcessHeap(), 0, pKeyBasicInfo);
  722. }
  723. Status = NtDeleteKey(hSubKey);
  724. if (bCloseSubKey) {
  725. NtClose(hSubKey);
  726. }
  727. return Status;
  728. }
  729. NTSTATUS NTAPI
  730. CodeAuthzpFormatLevelKeyPath(
  731. IN DWORD dwLevelId,
  732. IN OUT PUNICODE_STRING UnicodeSuffix
  733. )
  734. /*++
  735. Routine Description:
  736. Internal function to generate the path to a given subkey within the
  737. WinSafer policy store for the storage of a given Level. The
  738. resulting path can then be supplied to CodeAuthzpOpenPolicyRootKey
  739. Arguments:
  740. dwLevelId - the LevelId to process.
  741. UnicodeSuffix - Specifies the output buffer. The Buffer and
  742. MaximumLength fields must be supplied, but the Length
  743. field is ignored.
  744. Return Value:
  745. Returns STATUS_SUCCESS on success.
  746. --*/
  747. {
  748. NTSTATUS Status;
  749. UNICODE_STRING UnicodeTemp;
  750. if (!ARGUMENT_PRESENT(UnicodeSuffix)) {
  751. Status = STATUS_ACCESS_VIOLATION;
  752. goto ExitHandler;
  753. }
  754. UnicodeSuffix->Length = 0;
  755. Status = RtlAppendUnicodeToString(
  756. UnicodeSuffix,
  757. SAFER_OBJECTS_REGSUBKEY L"\\");
  758. if (!NT_SUCCESS(Status)) {
  759. goto ExitHandler;
  760. }
  761. UnicodeTemp.Buffer = &UnicodeSuffix->Buffer[
  762. UnicodeSuffix->Length / sizeof(WCHAR) ];
  763. UnicodeTemp.MaximumLength = (UnicodeSuffix->MaximumLength -
  764. UnicodeSuffix->Length);
  765. Status = RtlIntegerToUnicodeString(dwLevelId,
  766. 10,
  767. &UnicodeTemp);
  768. if (!NT_SUCCESS(Status)) {
  769. goto ExitHandler;
  770. }
  771. UnicodeSuffix->Length += UnicodeTemp.Length;
  772. ExitHandler:
  773. return Status;
  774. }
  775. NTSTATUS NTAPI
  776. CodeAuthzpFormatIdentityKeyPath(
  777. IN DWORD dwLevelId,
  778. IN LPCWSTR szIdentityType,
  779. IN REFGUID refIdentGuid,
  780. IN OUT PUNICODE_STRING UnicodeSuffix
  781. )
  782. /*++
  783. Routine Description:
  784. Internal function to generate the path to a given subkey within the
  785. WinSafer policy store for the storage of a given Code Identity. The
  786. resulting path can then be supplied to CodeAuthzpOpenPolicyRootKey
  787. Arguments:
  788. dwLevelId - the LevelId to process.
  789. szIdentityType - should be one of the following string constants:
  790. SAFER_PATHS_REGSUBKEY,
  791. SAFER_HASHMD5_REGSUBKEY,
  792. SAFER_SOURCEURL_REGSUBKEY
  793. refIdentGuid - the GUID of the code identity.
  794. UnicodeSuffix - Specifies the output buffer. The Buffer and
  795. MaximumLength fields must be supplied, but the Length
  796. field is ignored.
  797. Return Value:
  798. Returns STATUS_SUCCESS on success.
  799. --*/
  800. {
  801. NTSTATUS Status;
  802. UNICODE_STRING UnicodeTemp;
  803. if (!ARGUMENT_PRESENT(refIdentGuid)) {
  804. Status = STATUS_INVALID_PARAMETER;
  805. goto ExitHandler;
  806. }
  807. if (!ARGUMENT_PRESENT(UnicodeSuffix)) {
  808. Status = STATUS_ACCESS_VIOLATION;
  809. goto ExitHandler;
  810. }
  811. UnicodeSuffix->Length = 0;
  812. Status = RtlAppendUnicodeToString(
  813. UnicodeSuffix,
  814. SAFER_CODEIDS_REGSUBKEY L"\\");
  815. if (!NT_SUCCESS(Status)) {
  816. goto ExitHandler;
  817. }
  818. UnicodeTemp.Buffer = &UnicodeSuffix->Buffer[
  819. UnicodeSuffix->Length / sizeof(WCHAR) ];
  820. UnicodeTemp.MaximumLength = (UnicodeSuffix->MaximumLength -
  821. UnicodeSuffix->Length);
  822. Status = RtlIntegerToUnicodeString(dwLevelId,
  823. 10,
  824. &UnicodeTemp);
  825. if (!NT_SUCCESS(Status)) {
  826. goto ExitHandler;
  827. }
  828. UnicodeSuffix->Length += UnicodeTemp.Length;
  829. Status = RtlAppendUnicodeToString(
  830. UnicodeSuffix,
  831. L"\\");
  832. if (!NT_SUCCESS(Status)) {
  833. goto ExitHandler;
  834. }
  835. Status = RtlAppendUnicodeToString(
  836. UnicodeSuffix,
  837. szIdentityType);
  838. if (!NT_SUCCESS(Status)) {
  839. goto ExitHandler;
  840. }
  841. Status = RtlAppendUnicodeToString(
  842. UnicodeSuffix,
  843. L"\\");
  844. if (!NT_SUCCESS(Status)) {
  845. goto ExitHandler;
  846. }
  847. Status = RtlStringFromGUID(refIdentGuid, &UnicodeTemp);
  848. if (!NT_SUCCESS(Status)) {
  849. goto ExitHandler;
  850. }
  851. Status = RtlAppendUnicodeStringToString(
  852. UnicodeSuffix, &UnicodeTemp);
  853. RtlFreeUnicodeString(&UnicodeTemp);
  854. ExitHandler:
  855. return Status;
  856. }
  857. NTSTATUS NTAPI
  858. CodeAuthzpOpenPolicyRootKey(
  859. IN DWORD dwScopeId,
  860. IN HANDLE hKeyCustomBase OPTIONAL,
  861. IN LPCWSTR szRegistrySuffix OPTIONAL,
  862. IN ACCESS_MASK DesiredAccess,
  863. IN BOOLEAN bCreateKey,
  864. OUT HANDLE *OpenedHandle
  865. )
  866. /*++
  867. Routine Description:
  868. Internal function to generate the path to a given subkey within the
  869. WinSAFER policy store within the registry and then open that key.
  870. The specified subkeys can optionally be automatically created if
  871. they do not already exist.
  872. Arguments:
  873. dwScopeId - input scope identifier. This must be one of
  874. SAFER_SCOPEID_MACHINE or SAFER_SCOPEID_USER or SAFER_SCOPEID_REGISTRY.
  875. hKeyCustomBase - only used if dwScopeId is SAFER_SCOPEID_REGISTRY.
  876. szRegistrySuffix - optionally specifies a subkey name to open under
  877. the scope being referenced.
  878. DesiredAccess - specifies the access that should be used to open
  879. the registry key. For example, use KEY_READ for read access.
  880. bCreateKey - if true, the key will be created if it does not exist.
  881. OpenedHandle - pointer that recieves the opened handle. This handle
  882. must be closed by the caller with NtClose()
  883. Return Value:
  884. Returns STATUS_SUCCESS on success.
  885. --*/
  886. {
  887. NTSTATUS Status;
  888. WCHAR KeyPathBuffer[MAX_PATH];
  889. HANDLE hKeyPolicyBase;
  890. UNICODE_STRING SubKeyName;
  891. OBJECT_ATTRIBUTES ObjectAttributes;
  892. USHORT KeyLength = 0;
  893. //
  894. // Verify that we were given a pointer to write the final handle to.
  895. //
  896. if (!ARGUMENT_PRESENT(OpenedHandle)) {
  897. return STATUS_INVALID_PARAMETER_4;
  898. }
  899. if (ARGUMENT_PRESENT(szRegistrySuffix))
  900. {
  901. KeyLength = (wcslen(szRegistrySuffix) + 1 ) * sizeof(WCHAR);
  902. }
  903. //
  904. // Evaluate the Scope and build the full registry path that we will
  905. // use to open a handle to this key.
  906. //
  907. SubKeyName.Buffer = KeyPathBuffer;
  908. SubKeyName.Length = 0;
  909. SubKeyName.MaximumLength = sizeof(KeyPathBuffer);
  910. if (dwScopeId == SAFER_SCOPEID_MACHINE)
  911. {
  912. KeyLength += sizeof(WCHAR) + sizeof(SAFER_HKCU_REGBASE) + sizeof(L"\\Registry\\Machine\\");
  913. if (SubKeyName.MaximumLength < KeyLength)
  914. {
  915. SubKeyName.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0,
  916. KeyLength);
  917. if (SubKeyName.Buffer == NULL)
  918. {
  919. return STATUS_NO_MEMORY;
  920. }
  921. SubKeyName.MaximumLength = KeyLength;
  922. }
  923. Status = RtlAppendUnicodeToString(&SubKeyName,
  924. L"\\Registry\\Machine\\" SAFER_HKLM_REGBASE );
  925. hKeyPolicyBase = NULL;
  926. }
  927. else if (dwScopeId == SAFER_SCOPEID_USER)
  928. {
  929. UNICODE_STRING CurrentUserKeyPath;
  930. Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath );
  931. if (NT_SUCCESS( Status ) )
  932. {
  933. KeyLength += CurrentUserKeyPath.Length + sizeof(WCHAR) +
  934. sizeof(SAFER_HKCU_REGBASE);
  935. if (SubKeyName.MaximumLength < KeyLength)
  936. {
  937. SubKeyName.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0,
  938. KeyLength);
  939. if (SubKeyName.Buffer == NULL)
  940. {
  941. return STATUS_NO_MEMORY;
  942. }
  943. SubKeyName.MaximumLength = KeyLength;
  944. }
  945. Status = RtlAppendUnicodeStringToString(
  946. &SubKeyName, &CurrentUserKeyPath );
  947. RtlFreeUnicodeString( &CurrentUserKeyPath );
  948. }
  949. if (!NT_SUCCESS(Status)) {
  950. goto Cleanup;
  951. }
  952. Status = RtlAppendUnicodeToString( &SubKeyName,
  953. L"\\" SAFER_HKCU_REGBASE );
  954. if (!NT_SUCCESS( Status )) {
  955. goto Cleanup;
  956. }
  957. hKeyPolicyBase = NULL;
  958. }
  959. else if (dwScopeId == SAFER_SCOPEID_REGISTRY)
  960. {
  961. ASSERT(hKeyCustomBase != NULL);
  962. hKeyPolicyBase = hKeyCustomBase;
  963. if (SubKeyName.MaximumLength < KeyLength)
  964. {
  965. SubKeyName.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0,
  966. KeyLength);
  967. if (SubKeyName.Buffer == NULL)
  968. {
  969. return STATUS_NO_MEMORY;
  970. }
  971. SubKeyName.MaximumLength = KeyLength;
  972. }
  973. }
  974. else {
  975. return STATUS_INVALID_PARAMETER_1;
  976. }
  977. //
  978. // Append whatever suffix we're supposed to append if one was given.
  979. //
  980. if (ARGUMENT_PRESENT(szRegistrySuffix)) {
  981. if (SubKeyName.Length > 0)
  982. {
  983. // We are appending a suffix to a partial path, so
  984. // make sure there is at least a single backslash
  985. // dividing the two strings (extra are fine).
  986. if (*szRegistrySuffix != L'\\') {
  987. Status = RtlAppendUnicodeToString(&SubKeyName, L"\\");
  988. if (!NT_SUCCESS(Status)) {
  989. goto Cleanup;
  990. }
  991. }
  992. } else if (hKeyPolicyBase != NULL) {
  993. // Otherwise we are opening a key relative to a custom
  994. // specified key, and the supplied suffix happens to be
  995. // the first part of the path, so ensure there are no
  996. // leading backslashes.
  997. while (*szRegistrySuffix != UNICODE_NULL &&
  998. *szRegistrySuffix == L'\\') szRegistrySuffix++;
  999. }
  1000. Status = RtlAppendUnicodeToString(&SubKeyName, szRegistrySuffix);
  1001. if (!NT_SUCCESS(Status)) {
  1002. goto Cleanup;
  1003. }
  1004. }
  1005. //
  1006. // Open a handle to the registry path that we are supposed to open.
  1007. //
  1008. InitializeObjectAttributes(&ObjectAttributes,
  1009. &SubKeyName,
  1010. OBJ_CASE_INSENSITIVE,
  1011. hKeyPolicyBase,
  1012. NULL
  1013. );
  1014. if (bCreateKey) {
  1015. Status = NtCreateKey(OpenedHandle, DesiredAccess,
  1016. &ObjectAttributes, 0, NULL,
  1017. g_dwKeyOptions, NULL);
  1018. if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1019. {
  1020. BOOLEAN bAtLeastOnce;
  1021. USHORT uIndex, uFinalLength;
  1022. //
  1023. // If we fail on the first try to open the full path, then
  1024. // it is possible that one or more of the parent keys did
  1025. // not already exist, so we have to retry for each.
  1026. //
  1027. uFinalLength = (SubKeyName.Length / sizeof(WCHAR));
  1028. bAtLeastOnce = FALSE;
  1029. for (uIndex = 0; uIndex < uFinalLength; uIndex++) {
  1030. if (SubKeyName.Buffer[uIndex] == L'\\' ) {
  1031. HANDLE hTempKey;
  1032. SubKeyName.Length = uIndex * sizeof(WCHAR);
  1033. Status = NtCreateKey(&hTempKey, DesiredAccess,
  1034. &ObjectAttributes, 0, NULL,
  1035. g_dwKeyOptions, NULL);
  1036. if (NT_SUCCESS(Status)) {
  1037. NtClose(hTempKey);
  1038. } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1039. // one of the keys leading up here still failed.
  1040. break;
  1041. }
  1042. bAtLeastOnce = TRUE;
  1043. }
  1044. }
  1045. if (bAtLeastOnce) {
  1046. SubKeyName.Length = uFinalLength * sizeof(WCHAR);
  1047. Status = NtCreateKey(OpenedHandle, DesiredAccess,
  1048. &ObjectAttributes, 0, NULL,
  1049. g_dwKeyOptions, NULL);
  1050. }
  1051. }
  1052. } else {
  1053. Status = NtOpenKey(OpenedHandle, DesiredAccess,
  1054. &ObjectAttributes);
  1055. }
  1056. Cleanup:
  1057. if ((SubKeyName.Buffer != NULL) && (SubKeyName.Buffer != KeyPathBuffer))
  1058. {
  1059. RtlFreeHeap(RtlProcessHeap(), 0, SubKeyName.Buffer);
  1060. }
  1061. return Status;
  1062. }
  1063. BOOL WINAPI
  1064. SaferiPopulateDefaultsInRegistry(
  1065. IN HKEY hKeyBase,
  1066. OUT BOOL *pbSetDefaults
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. Winsafer UI will use this API to populate default winsafer values
  1071. in the registry as follows:
  1072. DefaultLevel: SAFER_LEVELID_FULLYTRUSTED
  1073. ExecutableTypes: initialized to the latest list of attachment types
  1074. TransparentEnabled: 1
  1075. Policy Scope: 0 (enable policy for admins)
  1076. Level descriptions
  1077. Arguments:
  1078. hKeyBase - This should be an opened registry key handle to the
  1079. base of the policy storage that should be used for
  1080. to populate the defaults into. This handle should be
  1081. opened with a miniumum of KEY_SET_VALUE access.
  1082. pbSetDefaults - Pointer to a boolean that gets set when
  1083. default values are actually set (UI uses this).
  1084. Return Value:
  1085. returns STATUS_SUCCESS on successful completion.
  1086. --*/
  1087. {
  1088. #define SAFERP_WINDOWS L"%HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SystemRoot%"
  1089. GUID WindowsGuid = SAFERP_WINDOWS_GUID;
  1090. #define SAFERP_WINDOWS_EXE L"%HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SystemRoot%\\*.exe"
  1091. GUID WindowsExeGuid = SAFERP_WINDOWS_EXE_GUID;
  1092. #define SAFERP_SYSTEM_EXE L"%HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SystemRoot%\\System32\\*.exe"
  1093. GUID SystemExeGuid = SAFERP_SYSTEM_EXE_GUID;
  1094. #define SAFERP_PROGRAMFILES L"%HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\ProgramFilesDir%"
  1095. GUID ProgramFilesGuid = SAFERP_PROGRAMFILES_GUID;
  1096. NTSTATUS Status;
  1097. DWORD dwValueValue;
  1098. PWSTR pmszFileTypes = NULL;
  1099. UNICODE_STRING ValueName;
  1100. ULONG uResultLength = 0;
  1101. KEY_NAME_INFORMATION pKeyInformation;
  1102. UNICODE_STRING ucSubKeyName;
  1103. WCHAR szSubKeyPath[] = L"Software\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers\0";
  1104. OBJECT_ATTRIBUTES ObjectAttributes;
  1105. HKEY hKeyFinal = NULL;
  1106. HANDLE hAdvApiInst;
  1107. AUTHZIDENTSTABLERECORD LocalRecord = {0};
  1108. SAFER_PATHNAME_IDENTIFICATION PathIdent = {0};
  1109. DWORD dwLevelIndex;
  1110. BYTE QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 64];
  1111. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
  1112. DWORD dwActualSize = 0;
  1113. if (!ARGUMENT_PRESENT(hKeyBase) || !ARGUMENT_PRESENT(pbSetDefaults)) {
  1114. Status = STATUS_INVALID_PARAMETER;
  1115. goto ExitHandler;
  1116. }
  1117. *pbSetDefaults = TRUE;
  1118. RtlInitUnicodeString(&ucSubKeyName, szSubKeyPath);
  1119. InitializeObjectAttributes(&ObjectAttributes,
  1120. (PUNICODE_STRING) &ucSubKeyName,
  1121. OBJ_CASE_INSENSITIVE,
  1122. hKeyBase,
  1123. NULL
  1124. );
  1125. Status = NtOpenKey(&hKeyFinal,
  1126. KEY_WRITE | KEY_READ,
  1127. &ObjectAttributes);
  1128. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1129. Status = NtCreateKey(&hKeyFinal,
  1130. KEY_WRITE | KEY_READ,
  1131. &ObjectAttributes,
  1132. 0,
  1133. NULL,
  1134. REG_OPTION_NON_VOLATILE,
  1135. NULL);
  1136. }
  1137. if (!NT_SUCCESS(Status)) {
  1138. goto ExitHandler;
  1139. }
  1140. //
  1141. // check if any default value is absent
  1142. // if so, populate all the defaults again
  1143. // if not, do not populate any values and return
  1144. //
  1145. RtlInitUnicodeString(&ValueName, SAFER_DEFAULTOBJ_REGVALUE);
  1146. Status = NtQueryValueKey(
  1147. hKeyFinal,
  1148. (PUNICODE_STRING) &ValueName,
  1149. KeyValuePartialInformation,
  1150. pKeyValueInfo,
  1151. sizeof(QueryBuffer),
  1152. &dwActualSize
  1153. );
  1154. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  1155. goto PopulateAllDefaults;
  1156. }
  1157. RtlInitUnicodeString(&ValueName, SAFER_TRANSPARENTENABLED_REGVALUE);
  1158. Status = NtQueryValueKey(
  1159. hKeyFinal,
  1160. (PUNICODE_STRING) &ValueName,
  1161. KeyValuePartialInformation,
  1162. pKeyValueInfo,
  1163. sizeof(QueryBuffer),
  1164. &dwActualSize
  1165. );
  1166. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  1167. goto PopulateAllDefaults;
  1168. }
  1169. RtlInitUnicodeString(&ValueName, SAFER_POLICY_SCOPE);
  1170. Status = NtQueryValueKey(
  1171. hKeyFinal,
  1172. (PUNICODE_STRING) &ValueName,
  1173. KeyValuePartialInformation,
  1174. pKeyValueInfo,
  1175. sizeof(QueryBuffer),
  1176. &dwActualSize
  1177. );
  1178. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  1179. goto PopulateAllDefaults;
  1180. }
  1181. RtlInitUnicodeString(&ValueName, SAFER_EXETYPES_REGVALUE);
  1182. Status = NtQueryValueKey(
  1183. hKeyFinal,
  1184. (PUNICODE_STRING) &ValueName,
  1185. KeyValuePartialInformation,
  1186. pKeyValueInfo,
  1187. sizeof(QueryBuffer),
  1188. &dwActualSize
  1189. );
  1190. if ( Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
  1191. goto PopulateAllDefaults;
  1192. }
  1193. //
  1194. // all default values are present or there was an error
  1195. // querying one of the values no need to populate any
  1196. //
  1197. *pbSetDefaults = FALSE;
  1198. goto ExitHandler;
  1199. PopulateAllDefaults:
  1200. RtlInitUnicodeString(&ValueName, SAFER_DEFAULTOBJ_REGVALUE);
  1201. dwValueValue = SAFER_LEVELID_FULLYTRUSTED;
  1202. Status = NtSetValueKey(hKeyFinal,
  1203. &ValueName,
  1204. 0,
  1205. REG_DWORD,
  1206. &dwValueValue,
  1207. sizeof(DWORD));
  1208. if (!NT_SUCCESS(Status))
  1209. goto ExitHandler;
  1210. dwValueValue = 1;
  1211. RtlInitUnicodeString(&ValueName, SAFER_TRANSPARENTENABLED_REGVALUE);
  1212. Status = NtSetValueKey(hKeyFinal,
  1213. &ValueName,
  1214. 0,
  1215. REG_DWORD,
  1216. &dwValueValue,
  1217. sizeof(DWORD));
  1218. if (!NT_SUCCESS(Status))
  1219. goto ExitHandler;
  1220. dwValueValue = 0;
  1221. RtlInitUnicodeString(&ValueName, SAFER_POLICY_SCOPE);
  1222. Status = NtSetValueKey(hKeyFinal,
  1223. &ValueName,
  1224. 0,
  1225. REG_DWORD,
  1226. &dwValueValue,
  1227. sizeof(DWORD));
  1228. if (!NT_SUCCESS(Status))
  1229. goto ExitHandler;
  1230. //
  1231. // prepare the MULTI_SZ value to write to the registry
  1232. //
  1233. RtlInitUnicodeString(&ValueName, SAFER_EXETYPES_REGVALUE);
  1234. pmszFileTypes = RtlAllocateHeap(RtlProcessHeap(),
  1235. 0,
  1236. sizeof(SAFER_DEFAULT_EXECUTABLE_FILE_TYPES)
  1237. );
  1238. if (pmszFileTypes) {
  1239. RtlCopyMemory(pmszFileTypes,
  1240. SAFER_DEFAULT_EXECUTABLE_FILE_TYPES,
  1241. sizeof(SAFER_DEFAULT_EXECUTABLE_FILE_TYPES));
  1242. Status = NtSetValueKey(hKeyFinal,
  1243. &ValueName,
  1244. 0,
  1245. REG_MULTI_SZ,
  1246. pmszFileTypes,
  1247. sizeof(SAFER_DEFAULT_EXECUTABLE_FILE_TYPES)
  1248. );
  1249. RtlFreeHeap(RtlProcessHeap(),
  1250. 0,
  1251. pmszFileTypes
  1252. );
  1253. }
  1254. else {
  1255. Status = STATUS_NO_MEMORY;
  1256. goto ExitHandler;
  1257. }
  1258. //
  1259. // We now generate 4 rules so that the OS binaries are exempt.
  1260. // FULLY TRUSTED
  1261. // %windir%
  1262. // %windir%\*.exe
  1263. // %windir%\system32\*.exe
  1264. // %ProgramFiles%
  1265. //
  1266. LocalRecord.dwIdentityType = SaferIdentityTypeImageName;
  1267. LocalRecord.dwLevelId = SAFER_LEVELID_FULLYTRUSTED;
  1268. LocalRecord.dwScopeId = SAFER_SCOPEID_REGISTRY;
  1269. LocalRecord.ImageNameInfo.bExpandVars = TRUE;
  1270. LocalRecord.ImageNameInfo.dwSaferFlags = 0;
  1271. RtlInitUnicodeString(&LocalRecord.ImageNameInfo.ImagePath, SAFERP_WINDOWS);
  1272. LocalRecord.IdentGuid = WindowsGuid;
  1273. PathIdent.header.cbStructSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  1274. PathIdent.header.dwIdentificationType = SaferIdentityTypeImageName;
  1275. PathIdent.header.IdentificationGuid = LocalRecord.IdentGuid;
  1276. PathIdent.dwSaferFlags = 0;
  1277. PathIdent.ImageName = SAFERP_WINDOWS;
  1278. PathIdent.Description[0] = L'\0';
  1279. Status = SaferpSetSingleIdentificationPath(TRUE,
  1280. &LocalRecord,
  1281. &PathIdent,
  1282. FALSE
  1283. );
  1284. if (!NT_SUCCESS(Status))
  1285. goto ExitHandler;
  1286. RtlInitUnicodeString(&LocalRecord.ImageNameInfo.ImagePath, SAFERP_WINDOWS_EXE);
  1287. LocalRecord.IdentGuid = WindowsExeGuid;
  1288. PathIdent.header.IdentificationGuid = LocalRecord.IdentGuid;
  1289. PathIdent.ImageName = SAFERP_WINDOWS_EXE;
  1290. Status = SaferpSetSingleIdentificationPath(TRUE,
  1291. &LocalRecord,
  1292. &PathIdent,
  1293. FALSE
  1294. );
  1295. if (!NT_SUCCESS(Status))
  1296. goto ExitHandler;
  1297. RtlInitUnicodeString(&LocalRecord.ImageNameInfo.ImagePath, SAFERP_SYSTEM_EXE);
  1298. LocalRecord.IdentGuid = SystemExeGuid;
  1299. PathIdent.header.IdentificationGuid = LocalRecord.IdentGuid;
  1300. PathIdent.ImageName = SAFERP_SYSTEM_EXE;
  1301. Status = SaferpSetSingleIdentificationPath(TRUE,
  1302. &LocalRecord,
  1303. &PathIdent,
  1304. FALSE
  1305. );
  1306. if (!NT_SUCCESS(Status))
  1307. goto ExitHandler;
  1308. RtlInitUnicodeString(&LocalRecord.ImageNameInfo.ImagePath, SAFERP_PROGRAMFILES);
  1309. LocalRecord.IdentGuid = ProgramFilesGuid;
  1310. PathIdent.header.IdentificationGuid = LocalRecord.IdentGuid;
  1311. PathIdent.ImageName = SAFERP_PROGRAMFILES;
  1312. Status = SaferpSetSingleIdentificationPath(TRUE,
  1313. &LocalRecord,
  1314. &PathIdent,
  1315. FALSE
  1316. );
  1317. if (!NT_SUCCESS(Status))
  1318. goto ExitHandler;
  1319. ExitHandler:
  1320. if (hKeyFinal) {
  1321. NtClose(hKeyFinal);
  1322. }
  1323. if (NT_SUCCESS(Status)) {
  1324. return TRUE;
  1325. } else {
  1326. BaseSetLastNTError(Status);
  1327. return FALSE;
  1328. }
  1329. }