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.

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