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.

1353 lines
39 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. safepolr.c (SAFER Code Authorization Policy)
  5. Abstract:
  6. This module implements the WinSAFER APIs that query and set the
  7. persisted and cached policy definitions.
  8. Author:
  9. Jeffrey Lawson (JLawson) - Apr 1999
  10. Environment:
  11. User mode only.
  12. Exported Functions:
  13. Revision History:
  14. Created - Apr 1999
  15. --*/
  16. #include "pch.h"
  17. #pragma hdrstop
  18. #include <winsafer.h>
  19. #include <winsaferp.h>
  20. #include "saferp.h"
  21. NTSTATUS NTAPI
  22. CodeAuthzPol_GetInfoCached_LevelListRaw(
  23. IN DWORD dwScopeId,
  24. IN DWORD InfoBufferSize OPTIONAL,
  25. OUT PVOID InfoBuffer OPTIONAL,
  26. OUT PDWORD InfoBufferRetSize OPTIONAL
  27. )
  28. /*++
  29. Routine Description:
  30. Asks the system to query for the list of available
  31. WinSafer Levels for the currently loaded policy scope.
  32. Arguments:
  33. dwScopeId - specifies the registry scope that will be examined.
  34. If the currently cached scope included a registry handle
  35. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  36. this must be SAFER_SCOPEID_MACHINE.
  37. InfoBufferSize - optionally specifies the size of input buffer
  38. supplied by the caller to receive the results. If this argument
  39. is supplied, then InfoBuffer must also be supplied.
  40. InfoBuffer - optionally specifies the input buffer that was
  41. supplied by the caller to receive the results. If this argument
  42. is supplied, then InfoBufferSize must also be supplied.
  43. InfoBufferRetSize - optionally specifies a pointer that will receive
  44. the size of the results actually written to the InfoBuffer.
  45. Return Value:
  46. Returns STATUS_SUCCESS on successful return. Otherwise a status
  47. code such as STATUS_BUFFER_TOO_SMALL or STATUS_NOT_FOUND.
  48. --*/
  49. {
  50. NTSTATUS Status;
  51. PVOID RestartKey;
  52. PAUTHZLEVELTABLERECORD authzobj;
  53. DWORD dwSizeNeeded;
  54. LPVOID lpNextPtr, lpEndBuffer;
  55. //
  56. // Load the list of all of the available objects.
  57. //
  58. if (!g_bInitializedFirstTime) {
  59. Status = STATUS_UNSUCCESSFUL;
  60. goto ExitHandler;
  61. }
  62. RtlEnterCriticalSection(&g_TableCritSec);
  63. if (g_hKeyCustomRoot != NULL) {
  64. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  65. Status = STATUS_INVALID_PARAMETER_MIX;
  66. goto ExitHandler2;
  67. }
  68. } else {
  69. if (dwScopeId != SAFER_SCOPEID_MACHINE &&
  70. dwScopeId != SAFER_SCOPEID_USER) {
  71. Status = STATUS_INVALID_PARAMETER_MIX;
  72. goto ExitHandler2;
  73. }
  74. }
  75. if (g_bNeedCacheReload) {
  76. Status = CodeAuthzpImmediateReloadCacheTables();
  77. if (!NT_SUCCESS(Status)) {
  78. goto ExitHandler2;
  79. }
  80. }
  81. if (RtlIsGenericTableEmpty(&g_CodeLevelObjTable)) {
  82. Status = STATUS_NOT_FOUND;
  83. goto ExitHandler2;
  84. }
  85. //
  86. // Determine the necessary size needed to store a DWORD array
  87. // of all of the Levels that were found in this scope.
  88. //
  89. dwSizeNeeded = 0;
  90. RestartKey = NULL;
  91. for (authzobj = (PAUTHZLEVELTABLERECORD)
  92. RtlEnumerateGenericTableWithoutSplaying(
  93. &g_CodeLevelObjTable, &RestartKey);
  94. authzobj != NULL;
  95. authzobj = (PAUTHZLEVELTABLERECORD)
  96. RtlEnumerateGenericTableWithoutSplaying(
  97. &g_CodeLevelObjTable, &RestartKey))
  98. {
  99. if (authzobj->isEnumerable) { //only allow enumeration if the level is enumerable
  100. dwSizeNeeded += sizeof(DWORD);
  101. }
  102. }
  103. if (!ARGUMENT_PRESENT(InfoBuffer) ||
  104. !InfoBufferSize ||
  105. InfoBufferSize < dwSizeNeeded)
  106. {
  107. if (ARGUMENT_PRESENT(InfoBufferRetSize))
  108. *InfoBufferRetSize = dwSizeNeeded;
  109. Status = STATUS_BUFFER_TOO_SMALL;
  110. goto ExitHandler2;
  111. }
  112. //
  113. // Fill the buffer with the resulting data.
  114. //
  115. lpNextPtr = (LPVOID) InfoBuffer;
  116. lpEndBuffer = (LPVOID) ( ((LPBYTE) InfoBuffer) + InfoBufferSize);
  117. RestartKey = NULL;
  118. for (authzobj = (PAUTHZLEVELTABLERECORD)
  119. RtlEnumerateGenericTableWithoutSplaying(
  120. &g_CodeLevelObjTable, &RestartKey);
  121. authzobj != NULL;
  122. authzobj = (PAUTHZLEVELTABLERECORD)
  123. RtlEnumerateGenericTableWithoutSplaying(
  124. &g_CodeLevelObjTable, &RestartKey))
  125. {
  126. if (authzobj->isEnumerable) { //only allow enumeration if the level is enumerable
  127. *((PDWORD)lpNextPtr) = authzobj->dwLevelId;
  128. lpNextPtr = (LPVOID) ( ((PBYTE) lpNextPtr) + sizeof(DWORD));
  129. }
  130. }
  131. ASSERT(lpNextPtr <= lpEndBuffer);
  132. //
  133. // Return the final buffer size and result code.
  134. //
  135. if (ARGUMENT_PRESENT(InfoBufferRetSize))
  136. *InfoBufferRetSize = (DWORD) ((PBYTE) lpNextPtr - (PBYTE) InfoBuffer);
  137. Status = STATUS_SUCCESS;
  138. ExitHandler2:
  139. RtlLeaveCriticalSection(&g_TableCritSec);
  140. ExitHandler:
  141. return Status;
  142. }
  143. NTSTATUS NTAPI
  144. SaferpPol_GetInfoCommon_DefaultLevel(
  145. IN DWORD dwScopeId,
  146. IN DWORD InfoBufferSize OPTIONAL,
  147. OUT PVOID InfoBuffer OPTIONAL,
  148. OUT PDWORD InfoBufferRetSize OPTIONAL,
  149. IN BOOLEAN bUseCached
  150. )
  151. /*++
  152. Routine Description:
  153. Queries the current WinSafer Level that has been configured to be
  154. the default policy level.
  155. Note that this query always accepts a constant-sized buffer that
  156. is only a single DWORD in length.
  157. Although this API directly queries the registry scope indicated,
  158. the pre-cached list of available Levels is used to validate the
  159. specified Level.
  160. Arguments:
  161. dwScopeId - specifies the registry scope that will be examined.
  162. If the currently cached scope included a registry handle
  163. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  164. this can be SAFER_SCOPEID_MACHINE or SAFER_SCOPEID_USER.
  165. InfoBufferSize - optionally specifies the size of input buffer
  166. supplied by the caller to receive the results. If this argument
  167. is supplied, then InfoBuffer must also be supplied.
  168. InfoBuffer - optionally specifies the input buffer that was
  169. supplied by the caller to receive the results. If this argument
  170. is supplied, then InfoBufferSize must also be supplied.
  171. InfoBufferRetSize - optionally specifies a pointer that will receive
  172. the size of the results actually written to the InfoBuffer.
  173. Return Value:
  174. Returns STATUS_SUCCESS on a successful query result. InfoBuffer will
  175. be filled with a single DWORD of the level that has been configured
  176. to be the default level for this scope. InfoBufferRetSize will
  177. contain the length of the result (a single DWORD).
  178. Returns STATUS_NOT_FOUND if no default level has been configured
  179. for the given scope (or the level defined does not exist).
  180. Returns STATUS_BUFFER_TOO_SMALL if there was a defined default level
  181. but a buffer was not supplied, or the buffer supplied was too
  182. small to accomodate the results.
  183. --*/
  184. {
  185. NTSTATUS Status;
  186. DWORD dwNewLevelId = (DWORD) -1;
  187. //
  188. // Open up the regkey to the base of the policies.
  189. //
  190. if (!g_bInitializedFirstTime) {
  191. Status = STATUS_UNSUCCESSFUL;
  192. goto ExitHandler;
  193. }
  194. RtlEnterCriticalSection(&g_TableCritSec);
  195. if (g_hKeyCustomRoot != NULL) {
  196. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  197. Status = STATUS_INVALID_PARAMETER_MIX;
  198. goto ExitHandler2;
  199. }
  200. } else {
  201. if (dwScopeId != SAFER_SCOPEID_MACHINE &&
  202. dwScopeId != SAFER_SCOPEID_USER) {
  203. Status = STATUS_INVALID_PARAMETER_MIX;
  204. goto ExitHandler2;
  205. }
  206. }
  207. if (g_bNeedCacheReload) {
  208. Status = CodeAuthzpImmediateReloadCacheTables();
  209. if (!NT_SUCCESS(Status)) {
  210. goto ExitHandler2;
  211. }
  212. }
  213. if (RtlIsGenericTableEmpty(&g_CodeLevelObjTable)) {
  214. Status = STATUS_NOT_FOUND;
  215. goto ExitHandler2;
  216. }
  217. //
  218. // Query the current value setting.
  219. //
  220. if (!bUseCached)
  221. {
  222. HANDLE hKeyBase;
  223. ULONG ActualSize;
  224. UNICODE_STRING ValueName;
  225. WCHAR KeyPathBuffer[ MAXIMUM_FILENAME_LENGTH+6 ];
  226. PKEY_VALUE_FULL_INFORMATION ValueBuffer =
  227. (PKEY_VALUE_FULL_INFORMATION) KeyPathBuffer;
  228. Status = CodeAuthzpOpenPolicyRootKey(
  229. dwScopeId,
  230. g_hKeyCustomRoot,
  231. L"\\" SAFER_CODEIDS_REGSUBKEY,
  232. KEY_READ, FALSE, &hKeyBase);
  233. if (NT_SUCCESS(Status))
  234. {
  235. RtlInitUnicodeString(&ValueName, SAFER_DEFAULTOBJ_REGVALUE);
  236. Status = NtQueryValueKey(hKeyBase,
  237. &ValueName,
  238. KeyValueFullInformation,
  239. ValueBuffer, // ptr to KeyPathBuffer
  240. sizeof(KeyPathBuffer),
  241. &ActualSize);
  242. if (NT_SUCCESS(Status)) {
  243. if (ValueBuffer->Type != REG_DWORD ||
  244. ValueBuffer->DataLength != sizeof(DWORD)) {
  245. Status = STATUS_NOT_FOUND;
  246. } else {
  247. dwNewLevelId = * (PDWORD) ((PBYTE) ValueBuffer +
  248. ValueBuffer->DataOffset);
  249. }
  250. }
  251. NtClose(hKeyBase);
  252. }
  253. if (!NT_SUCCESS(Status)) {
  254. goto ExitHandler2;
  255. }
  256. }
  257. else
  258. {
  259. if (dwScopeId == SAFER_SCOPEID_USER) {
  260. if (!g_DefaultCodeLevelUser) {
  261. dwNewLevelId = SAFER_LEVELID_FULLYTRUSTED;
  262. } else {
  263. dwNewLevelId = g_DefaultCodeLevelUser->dwLevelId;
  264. }
  265. } else {
  266. if (!g_DefaultCodeLevelMachine) {
  267. dwNewLevelId = SAFER_LEVELID_FULLYTRUSTED;
  268. } else {
  269. dwNewLevelId = g_DefaultCodeLevelMachine->dwLevelId;
  270. }
  271. }
  272. }
  273. //
  274. // Make sure the level we found is actually
  275. // valid (still in our level table).
  276. //
  277. if (!CodeAuthzLevelObjpLookupByLevelId(
  278. &g_CodeLevelObjTable, dwNewLevelId)) {
  279. Status = STATUS_NOT_FOUND;
  280. goto ExitHandler2;
  281. }
  282. //
  283. // Make sure the target buffer is large
  284. // enough and copy the levelid into it.
  285. //
  286. if (!ARGUMENT_PRESENT(InfoBuffer) ||
  287. InfoBufferSize < sizeof(DWORD)) {
  288. Status = STATUS_BUFFER_TOO_SMALL;
  289. } else {
  290. RtlCopyMemory(InfoBuffer, &dwNewLevelId, sizeof(DWORD));
  291. Status = STATUS_SUCCESS;
  292. }
  293. if (ARGUMENT_PRESENT(InfoBufferRetSize))
  294. *InfoBufferRetSize = sizeof(DWORD);
  295. ExitHandler2:
  296. RtlLeaveCriticalSection(&g_TableCritSec);
  297. ExitHandler:
  298. return Status;
  299. }
  300. NTSTATUS NTAPI
  301. CodeAuthzPol_GetInfoCached_DefaultLevel(
  302. IN DWORD dwScopeId,
  303. IN DWORD InfoBufferSize OPTIONAL,
  304. OUT PVOID InfoBuffer OPTIONAL,
  305. OUT PDWORD InfoBufferRetSize OPTIONAL
  306. )
  307. {
  308. return SaferpPol_GetInfoCommon_DefaultLevel(
  309. dwScopeId,
  310. InfoBufferSize,
  311. InfoBuffer,
  312. InfoBufferRetSize,
  313. TRUE);
  314. }
  315. NTSTATUS NTAPI
  316. CodeAuthzPol_GetInfoRegistry_DefaultLevel(
  317. IN DWORD dwScopeId,
  318. IN DWORD InfoBufferSize OPTIONAL,
  319. OUT PVOID InfoBuffer OPTIONAL,
  320. OUT PDWORD InfoBufferRetSize OPTIONAL
  321. )
  322. {
  323. return SaferpPol_GetInfoCommon_DefaultLevel(
  324. dwScopeId,
  325. InfoBufferSize,
  326. InfoBuffer,
  327. InfoBufferRetSize,
  328. FALSE);
  329. }
  330. NTSTATUS NTAPI
  331. CodeAuthzPol_SetInfoDual_DefaultLevel(
  332. IN DWORD dwScopeId,
  333. IN DWORD InfoBufferSize,
  334. OUT PVOID InfoBuffer
  335. )
  336. /*++
  337. Routine Description:
  338. Modifies the current WinSafer Level that has been configured to be
  339. the default policy level.
  340. Note that this query always accepts a constant-sized buffer that
  341. is only a single DWORD in length.
  342. Arguments:
  343. dwScopeId - specifies the registry scope that will be examined.
  344. If the currently cached scope included a registry handle
  345. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  346. this can be SAFER_SCOPEID_MACHINE or SAFER_SCOPEID_USER.
  347. InfoBufferSize - specifies the size of input buffer
  348. supplied by the caller to receive the results.
  349. InfoBuffer - specifies the input buffer that was
  350. supplied by the caller to receive the results.
  351. Return Value:
  352. Returns STATUS_SUCCESS on a successful query result. InfoBuffer will
  353. be filled with a single DWORD of the level that has been configured
  354. to be the default level for this scope. InfoBufferRetSize will
  355. contain the length of the result (a single DWORD).
  356. Returns STATUS_NOT_FOUND if no default level has been configured
  357. for the given scope (or the level defined does not exist).
  358. Returns STATUS_BUFFER_TOO_SMALL if there was a defined default level
  359. but a buffer was not supplied, or the buffer supplied was too
  360. small to accomodate the results.
  361. --*/
  362. {
  363. NTSTATUS Status;
  364. HANDLE hKeyBase;
  365. DWORD dwNewLevelId;
  366. UNICODE_STRING ValueName;
  367. PAUTHZLEVELTABLERECORD pLevelRecord;
  368. //
  369. // Open up the regkey to the base of the policies.
  370. //
  371. if (!g_bInitializedFirstTime) {
  372. Status = STATUS_UNSUCCESSFUL;
  373. goto ExitHandler;
  374. }
  375. RtlEnterCriticalSection(&g_TableCritSec);
  376. if (g_hKeyCustomRoot != NULL) {
  377. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  378. Status = STATUS_INVALID_PARAMETER_MIX;
  379. goto ExitHandler2;
  380. }
  381. } else {
  382. if (dwScopeId != SAFER_SCOPEID_MACHINE &&
  383. dwScopeId != SAFER_SCOPEID_USER) {
  384. Status = STATUS_INVALID_PARAMETER_MIX;
  385. goto ExitHandler2;
  386. }
  387. }
  388. if (g_bNeedCacheReload) {
  389. Status = CodeAuthzpImmediateReloadCacheTables();
  390. if (!NT_SUCCESS(Status)) {
  391. goto ExitHandler2;
  392. }
  393. }
  394. Status = CodeAuthzpOpenPolicyRootKey(
  395. dwScopeId,
  396. g_hKeyCustomRoot,
  397. L"\\" SAFER_CODEIDS_REGSUBKEY,
  398. KEY_READ | KEY_SET_VALUE,
  399. TRUE, &hKeyBase);
  400. if (!NT_SUCCESS(Status)) {
  401. goto ExitHandler2;
  402. }
  403. //
  404. // Load the list of all of the available objects.
  405. //
  406. if (RtlIsGenericTableEmpty(&g_CodeLevelObjTable)) {
  407. Status = STATUS_NOT_FOUND;
  408. goto ExitHandler3;
  409. }
  410. //
  411. // If we are going to set a new default object,
  412. // make sure it is a valid one.
  413. //
  414. if (InfoBufferSize < sizeof(DWORD) ||
  415. !ARGUMENT_PRESENT(InfoBuffer))
  416. {
  417. // Caller wants to clear the default object.
  418. InfoBuffer = NULL;
  419. pLevelRecord = NULL;
  420. }
  421. else
  422. {
  423. dwNewLevelId = *(PDWORD) InfoBuffer;
  424. pLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  425. &g_CodeLevelObjTable, dwNewLevelId);
  426. if (!pLevelRecord)
  427. {
  428. // Caller was trying to set the default to an
  429. // authorization object that does not exist.
  430. Status = STATUS_NOT_FOUND;
  431. goto ExitHandler3;
  432. }
  433. }
  434. //
  435. // Write the name of the default object that is specified.
  436. //
  437. RtlInitUnicodeString(&ValueName, SAFER_DEFAULTOBJ_REGVALUE);
  438. Status = NtSetValueKey(hKeyBase,
  439. &ValueName,
  440. 0,
  441. REG_DWORD,
  442. &dwNewLevelId,
  443. sizeof(DWORD));
  444. if (NT_SUCCESS(Status)) {
  445. if (dwScopeId == SAFER_SCOPEID_USER) {
  446. g_DefaultCodeLevelUser = pLevelRecord;
  447. } else {
  448. g_DefaultCodeLevelMachine = pLevelRecord;
  449. }
  450. //
  451. // Compute the effective Default Level (take the least privileged).
  452. //
  453. CodeAuthzpRecomputeEffectiveDefaultLevel();
  454. }
  455. ExitHandler3:
  456. NtClose(hKeyBase);
  457. ExitHandler2:
  458. RtlLeaveCriticalSection(&g_TableCritSec);
  459. ExitHandler:
  460. return Status;
  461. }
  462. NTSTATUS NTAPI
  463. SaferpPol_GetInfoCommon_HonorUserIdentities(
  464. IN DWORD dwScopeId,
  465. IN DWORD InfoBufferSize OPTIONAL,
  466. OUT PVOID InfoBuffer OPTIONAL,
  467. OUT PDWORD InfoBufferRetSize OPTIONAL,
  468. IN BOOLEAN bUseCached
  469. )
  470. /*++
  471. Routine Description:
  472. Queries the current WinSafer policy to determine if Code Identities
  473. defined within the User's registry scope should be considered.
  474. Note that this query always accepts a constant-sized buffer that is
  475. only a single DWORD in length.
  476. Arguments:
  477. dwScopeId - specifies the registry scope that will be examined.
  478. If the currently cached scope included a registry handle
  479. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  480. this must be SAFER_SCOPEID_MACHINE.
  481. InfoBufferSize - optionally specifies the size of input buffer
  482. supplied by the caller to receive the results. If this argument
  483. is supplied, then InfoBuffer must also be supplied.
  484. InfoBuffer - optionally specifies the input buffer that was
  485. supplied by the caller to receive the results. If this argument
  486. is supplied, then InfoBufferSize must also be supplied.
  487. InfoBufferRetSize - optionally specifies a pointer that will receive
  488. the size of the results actually written to the InfoBuffer.
  489. Return Value:
  490. Returns STATUS_SUCCESS on a successful query result.
  491. InfoBuffer will be filled with a single DWORD containing
  492. either a TRUE or FALSE value that indicates whether the option
  493. is enabled. InfoBufferRetSize will contain the length of the
  494. result (a single DWORD).
  495. Returns STATUS_BUFFER_TOO_SMALL if the buffer was not supplied, or
  496. the buffer supplied was too small to accomodate the result.
  497. --*/
  498. {
  499. NTSTATUS Status;
  500. DWORD dwValueState = (DWORD) -1;
  501. //
  502. // Open up the regkey to the base of the policies.
  503. //
  504. if (!g_bInitializedFirstTime) {
  505. Status = STATUS_UNSUCCESSFUL;
  506. goto ExitHandler;
  507. }
  508. RtlEnterCriticalSection(&g_TableCritSec);
  509. if (g_hKeyCustomRoot != NULL) {
  510. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  511. Status = STATUS_INVALID_PARAMETER_MIX;
  512. goto ExitHandler2;
  513. }
  514. } else {
  515. if (dwScopeId != SAFER_SCOPEID_MACHINE) {
  516. Status = STATUS_INVALID_PARAMETER_MIX;
  517. goto ExitHandler2;
  518. }
  519. }
  520. if (g_bNeedCacheReload) {
  521. Status = CodeAuthzpImmediateReloadCacheTables();
  522. if (!NT_SUCCESS(Status)) {
  523. goto ExitHandler2;
  524. }
  525. }
  526. //
  527. // Read or write the name of the policy value that is specified.
  528. //
  529. if (!bUseCached)
  530. {
  531. HANDLE hKeyBase;
  532. ULONG ActualSize;
  533. UNICODE_STRING ValueName;
  534. WCHAR KeyPathBuffer[ MAXIMUM_FILENAME_LENGTH+6 ];
  535. PKEY_VALUE_FULL_INFORMATION ValueBuffer =
  536. (PKEY_VALUE_FULL_INFORMATION) KeyPathBuffer;
  537. Status = CodeAuthzpOpenPolicyRootKey(
  538. dwScopeId,
  539. g_hKeyCustomRoot,
  540. L"\\" SAFER_CODEIDS_REGSUBKEY,
  541. KEY_READ, FALSE, &hKeyBase);
  542. if (NT_SUCCESS(Status))
  543. {
  544. RtlInitUnicodeString(&ValueName,
  545. SAFER_HONORUSER_REGVALUE);
  546. Status = NtQueryValueKey(hKeyBase,
  547. &ValueName,
  548. KeyValueFullInformation,
  549. ValueBuffer, // ptr to KeyPathBuffer
  550. sizeof(KeyPathBuffer),
  551. &ActualSize);
  552. if (NT_SUCCESS(Status)) {
  553. if (ValueBuffer->Type != REG_DWORD ||
  554. ValueBuffer->DataLength != sizeof(DWORD)) {
  555. Status = STATUS_NOT_FOUND;
  556. } else {
  557. dwValueState = * (PDWORD) ((PBYTE) ValueBuffer +
  558. ValueBuffer->DataOffset);
  559. }
  560. }
  561. NtClose(hKeyBase);
  562. }
  563. if (!NT_SUCCESS(Status)) {
  564. goto ExitHandler2;
  565. }
  566. }
  567. else
  568. {
  569. dwValueState = (g_bHonorScopeUser ? TRUE : FALSE);
  570. }
  571. //
  572. // Make sure the target buffer is large
  573. // enough and copy the object name into it.
  574. //
  575. if (!ARGUMENT_PRESENT(InfoBuffer) ||
  576. InfoBufferSize < sizeof(DWORD)) {
  577. Status = STATUS_BUFFER_TOO_SMALL;
  578. } else {
  579. RtlCopyMemory(InfoBuffer, &dwValueState, sizeof(DWORD));
  580. Status = STATUS_SUCCESS;
  581. }
  582. if (ARGUMENT_PRESENT(InfoBufferRetSize))
  583. *InfoBufferRetSize = sizeof(DWORD);
  584. ExitHandler2:
  585. RtlLeaveCriticalSection(&g_TableCritSec);
  586. ExitHandler:
  587. return Status;
  588. }
  589. NTSTATUS NTAPI
  590. CodeAuthzPol_GetInfoCached_HonorUserIdentities(
  591. IN DWORD dwScopeId,
  592. IN DWORD InfoBufferSize OPTIONAL,
  593. OUT PVOID InfoBuffer OPTIONAL,
  594. OUT PDWORD InfoBufferRetSize OPTIONAL
  595. )
  596. {
  597. return SaferpPol_GetInfoCommon_HonorUserIdentities(
  598. dwScopeId, InfoBufferSize,
  599. InfoBuffer, InfoBufferRetSize, TRUE);
  600. }
  601. NTSTATUS NTAPI
  602. CodeAuthzPol_GetInfoRegistry_HonorUserIdentities(
  603. IN DWORD dwScopeId,
  604. IN DWORD InfoBufferSize OPTIONAL,
  605. OUT PVOID InfoBuffer OPTIONAL,
  606. OUT PDWORD InfoBufferRetSize OPTIONAL
  607. )
  608. {
  609. return SaferpPol_GetInfoCommon_HonorUserIdentities(
  610. dwScopeId, InfoBufferSize,
  611. InfoBuffer, InfoBufferRetSize, FALSE);
  612. }
  613. NTSTATUS NTAPI
  614. CodeAuthzPol_SetInfoDual_HonorUserIdentities(
  615. IN DWORD dwScopeId,
  616. IN DWORD InfoBufferSize,
  617. IN PVOID InfoBuffer
  618. )
  619. /*++
  620. Routine Description:
  621. Queries the current WinSafer policy to determine if Code Identities
  622. defined within the User's registry scope should be considered.
  623. Note that this API always accepts a constant-sized buffer that is
  624. only a single DWORD in length.
  625. Arguments:
  626. dwScopeId - specifies the registry scope that will be examined.
  627. If the currently cached scope included a registry handle
  628. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  629. this must be SAFER_SCOPEID_MACHINE.
  630. InfoBufferSize - specifies the size of input buffer
  631. supplied by the caller to receive the results. If this argument
  632. is supplied, then InfoBuffer must also be supplied.
  633. InfoBuffer - specifies the input buffer that was
  634. supplied by the caller to receive the results. If this argument
  635. is supplied, then InfoBufferSize must also be supplied.
  636. Return Value:
  637. Returns STATUS_SUCCESS on a successful query result. InfoBuffer will
  638. be filled with a single DWORD of the level that has been configured
  639. to be the default level for this scope. InfoBufferRetSize will
  640. contain the length of the result (a single DWORD).
  641. Returns STATUS_NOT_FOUND if no default level has been configured
  642. for the given scope (or the level defined does not exist).
  643. Returns STATUS_BUFFER_TOO_SMALL if there was a defined default level
  644. but a buffer was not supplied, or the buffer supplied was too
  645. small to accomodate the results.
  646. --*/
  647. {
  648. HANDLE hKeyBase;
  649. NTSTATUS Status;
  650. UNICODE_STRING ValueName;
  651. //
  652. // Open up the regkey to the base of the policies.
  653. //
  654. if (!g_bInitializedFirstTime) {
  655. Status = STATUS_UNSUCCESSFUL;
  656. goto ExitHandler;
  657. }
  658. RtlEnterCriticalSection(&g_TableCritSec);
  659. if (g_hKeyCustomRoot != NULL) {
  660. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  661. Status = STATUS_INVALID_PARAMETER_MIX;
  662. goto ExitHandler2;
  663. }
  664. } else {
  665. if (dwScopeId != SAFER_SCOPEID_MACHINE) {
  666. Status = STATUS_INVALID_PARAMETER_MIX;
  667. goto ExitHandler2;
  668. }
  669. }
  670. if (g_bNeedCacheReload) {
  671. Status = CodeAuthzpImmediateReloadCacheTables();
  672. if (!NT_SUCCESS(Status)) {
  673. goto ExitHandler2;
  674. }
  675. }
  676. Status = CodeAuthzpOpenPolicyRootKey(
  677. dwScopeId,
  678. g_hKeyCustomRoot,
  679. L"\\" SAFER_CODEIDS_REGSUBKEY,
  680. (KEY_READ | KEY_SET_VALUE),
  681. TRUE, &hKeyBase);
  682. if (!NT_SUCCESS(Status)) {
  683. goto ExitHandler2;
  684. }
  685. //
  686. // Make sure the input buffer is large enough.
  687. //
  688. if (InfoBufferSize < sizeof(DWORD) ||
  689. !ARGUMENT_PRESENT(InfoBuffer)) {
  690. Status = STATUS_BUFFER_TOO_SMALL;
  691. goto ExitHandler3;
  692. }
  693. //
  694. // Write the policy value that is specified.
  695. //
  696. RtlInitUnicodeString(&ValueName, SAFER_HONORUSER_REGVALUE);
  697. Status = NtSetValueKey(hKeyBase,
  698. &ValueName,
  699. 0,
  700. REG_DWORD,
  701. InfoBuffer,
  702. sizeof(DWORD));
  703. if (NT_SUCCESS(Status)) {
  704. BOOLEAN bNewHonorScopeUser = (*((PDWORD)InfoBuffer) != 0 ? TRUE : FALSE);
  705. if (g_bHonorScopeUser != bNewHonorScopeUser)
  706. {
  707. g_bHonorScopeUser = bNewHonorScopeUser;
  708. //
  709. // If the actual value is different from what we had then we
  710. // need to purge the identities table and reload the only the
  711. // parts that we should consider.
  712. //
  713. if (g_hKeyCustomRoot == NULL)
  714. {
  715. CodeAuthzGuidIdentsEntireTableFree(&g_CodeIdentitiesTable);
  716. CodeAuthzGuidIdentsLoadTableAll(
  717. &g_CodeLevelObjTable,
  718. &g_CodeIdentitiesTable,
  719. SAFER_SCOPEID_MACHINE,
  720. NULL);
  721. if (g_bHonorScopeUser) {
  722. CodeAuthzGuidIdentsLoadTableAll(
  723. &g_CodeLevelObjTable,
  724. &g_CodeIdentitiesTable,
  725. SAFER_SCOPEID_USER,
  726. NULL);
  727. }
  728. }
  729. }
  730. }
  731. ExitHandler3:
  732. NtClose(hKeyBase);
  733. ExitHandler2:
  734. RtlLeaveCriticalSection(&g_TableCritSec);
  735. ExitHandler:
  736. return Status;
  737. }
  738. NTSTATUS NTAPI
  739. CodeAuthzPol_GetInfoRegistry_TransparentEnabled(
  740. IN DWORD dwScopeId,
  741. IN DWORD InfoBufferSize OPTIONAL,
  742. OUT PVOID InfoBuffer OPTIONAL,
  743. OUT PDWORD InfoBufferRetSize OPTIONAL
  744. )
  745. /*++
  746. Routine Description:
  747. Queries the current "transparent enforcement" setting. This is a
  748. global setting that can be used to enable or disable automatic
  749. WinSafer token reductions.
  750. Arguments:
  751. dwScopeId - specifies the registry scope that will be examined.
  752. If the currently cached scope included a registry handle
  753. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  754. this must be SAFER_SCOPEID_MACHINE.
  755. InfoBufferSize - optionally specifies the size of input buffer
  756. supplied by the caller to receive the results. If this argument
  757. is supplied, then InfoBuffer must also be supplied.
  758. InfoBuffer - optionally specifies the input buffer that was
  759. supplied by the caller to receive the results. If this argument
  760. is supplied, then InfoBufferSize must also be supplied.
  761. InfoBufferRetSize - optionally specifies a pointer that will receive
  762. the size of the results actually written to the InfoBuffer.
  763. Return Value:
  764. Returns STATUS_SUCCESS on a successful query result. If the
  765. operation is not successful, then the contents of 'pdwEnabled'
  766. are left untouched.
  767. --*/
  768. {
  769. NTSTATUS Status;
  770. DWORD dwValueState = (DWORD) -1;
  771. //
  772. // Open up the regkey to the base of the policies.
  773. //
  774. if (!g_bInitializedFirstTime) {
  775. Status = STATUS_UNSUCCESSFUL;
  776. goto ExitHandler;
  777. }
  778. RtlEnterCriticalSection(&g_TableCritSec);
  779. if (g_hKeyCustomRoot != NULL) {
  780. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  781. Status = STATUS_INVALID_PARAMETER_MIX;
  782. goto ExitHandler2;
  783. }
  784. } else {
  785. if (dwScopeId != SAFER_SCOPEID_MACHINE) {
  786. Status = STATUS_INVALID_PARAMETER_MIX;
  787. goto ExitHandler2;
  788. }
  789. }
  790. //
  791. // Query the current value setting.
  792. //
  793. {
  794. HANDLE hKeyBase;
  795. DWORD ActualSize;
  796. UNICODE_STRING ValueName;
  797. WCHAR KeyPathBuffer[ MAXIMUM_FILENAME_LENGTH+6 ];
  798. PKEY_VALUE_FULL_INFORMATION ValueBuffer =
  799. (PKEY_VALUE_FULL_INFORMATION) KeyPathBuffer;
  800. Status = CodeAuthzpOpenPolicyRootKey(
  801. dwScopeId,
  802. g_hKeyCustomRoot,
  803. L"\\" SAFER_CODEIDS_REGSUBKEY,
  804. KEY_READ, FALSE, &hKeyBase);
  805. if (NT_SUCCESS(Status)) {
  806. RtlInitUnicodeString(&ValueName,
  807. SAFER_TRANSPARENTENABLED_REGVALUE);
  808. Status = NtQueryValueKey(hKeyBase,
  809. &ValueName,
  810. KeyValueFullInformation,
  811. ValueBuffer, // ptr to KeyPathBuffer
  812. sizeof(KeyPathBuffer),
  813. &ActualSize);
  814. if (NT_SUCCESS(Status)) {
  815. if (ValueBuffer->Type != REG_DWORD ||
  816. ValueBuffer->DataLength != sizeof(DWORD)) {
  817. Status = STATUS_NOT_FOUND;
  818. } else {
  819. dwValueState = * (PDWORD) ((PBYTE) ValueBuffer +
  820. ValueBuffer->DataOffset);
  821. }
  822. }
  823. NtClose(hKeyBase);
  824. }
  825. if (!NT_SUCCESS(Status)) {
  826. // On failure, just ignore it and pretend it was FALSE.
  827. dwValueState = FALSE;
  828. }
  829. }
  830. //
  831. // Make sure the target buffer is large
  832. // enough and copy the object name into it.
  833. //
  834. if (!ARGUMENT_PRESENT(InfoBuffer) ||
  835. InfoBufferSize < sizeof(DWORD)) {
  836. Status = STATUS_BUFFER_TOO_SMALL;
  837. } else {
  838. RtlCopyMemory(InfoBuffer, &dwValueState, sizeof(DWORD));
  839. Status = STATUS_SUCCESS;
  840. }
  841. if (ARGUMENT_PRESENT(InfoBufferRetSize))
  842. *InfoBufferRetSize = sizeof(DWORD);
  843. ExitHandler2:
  844. RtlLeaveCriticalSection(&g_TableCritSec);
  845. ExitHandler:
  846. return Status;
  847. }
  848. NTSTATUS NTAPI
  849. CodeAuthzPol_SetInfoRegistry_TransparentEnabled(
  850. IN DWORD dwScopeId,
  851. IN DWORD InfoBufferSize,
  852. IN PVOID InfoBuffer
  853. )
  854. /*++
  855. Routine Description:
  856. Modifies the current "transparent enforcement" setting. This is a
  857. global setting that can be used to enable or disable automatic
  858. WinSafer token reductions.
  859. Note that this API always accepts a constant-sized buffer that is
  860. only a single DWORD in length.
  861. Arguments:
  862. dwScopeId - specifies the registry scope that will be examined.
  863. If the currently cached scope included a registry handle
  864. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  865. this must be SAFER_SCOPEID_MACHINE.
  866. InfoBufferSize - specifies the size of input buffer
  867. supplied by the caller to receive the results. If this argument
  868. is supplied, then InfoBuffer must also be supplied.
  869. InfoBuffer - specifies the input buffer that was
  870. supplied by the caller to receive the results. If this argument
  871. is supplied, then InfoBufferSize must also be supplied.
  872. Return Value:
  873. Returns STATUS_SUCCESS on a successful result.
  874. --*/
  875. {
  876. HANDLE hKeyBase;
  877. NTSTATUS Status;
  878. UNICODE_STRING ValueName;
  879. //
  880. // Open up the regkey to the base of the policies.
  881. //
  882. if (!g_bInitializedFirstTime) {
  883. Status = STATUS_UNSUCCESSFUL;
  884. goto ExitHandler;
  885. }
  886. RtlEnterCriticalSection(&g_TableCritSec);
  887. if (g_hKeyCustomRoot != NULL) {
  888. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  889. Status = STATUS_INVALID_PARAMETER_MIX;
  890. goto ExitHandler2;
  891. }
  892. } else {
  893. if (dwScopeId != SAFER_SCOPEID_MACHINE) {
  894. Status = STATUS_INVALID_PARAMETER_MIX;
  895. goto ExitHandler2;
  896. }
  897. }
  898. Status = CodeAuthzpOpenPolicyRootKey(
  899. dwScopeId, g_hKeyCustomRoot,
  900. L"\\" SAFER_CODEIDS_REGSUBKEY,
  901. KEY_READ | KEY_SET_VALUE,
  902. TRUE, &hKeyBase);
  903. if (!NT_SUCCESS(Status)) {
  904. goto ExitHandler2;
  905. }
  906. //
  907. // Make sure the input buffer is large enough.
  908. //
  909. if (InfoBufferSize < sizeof(DWORD) ||
  910. !ARGUMENT_PRESENT(InfoBuffer)) {
  911. Status = STATUS_BUFFER_TOO_SMALL;
  912. goto ExitHandler3;
  913. }
  914. //
  915. // Write the policy value that is specified.
  916. //
  917. RtlInitUnicodeString(&ValueName,
  918. SAFER_TRANSPARENTENABLED_REGVALUE);
  919. Status = NtSetValueKey(hKeyBase,
  920. &ValueName,
  921. 0,
  922. REG_DWORD,
  923. InfoBuffer,
  924. sizeof(DWORD));
  925. ExitHandler3:
  926. NtClose(hKeyBase);
  927. ExitHandler2:
  928. RtlLeaveCriticalSection(&g_TableCritSec);
  929. ExitHandler:
  930. return Status;
  931. }
  932. NTSTATUS NTAPI
  933. CodeAuthzPol_GetInfoRegistry_ScopeFlags(
  934. IN DWORD dwScopeId,
  935. IN DWORD InfoBufferSize OPTIONAL,
  936. OUT PVOID InfoBuffer OPTIONAL,
  937. OUT PDWORD InfoBufferRetSize OPTIONAL
  938. )
  939. /*++
  940. Routine Description:
  941. Queries the current "scope flags" setting.
  942. Arguments:
  943. dwScopeId - specifies the registry scope that will be examined.
  944. If the currently cached scope included a registry handle
  945. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  946. this must be SAFER_SCOPEID_MACHINE.
  947. InfoBufferSize - optionally specifies the size of input buffer
  948. supplied by the caller to receive the results. If this argument
  949. is supplied, then InfoBuffer must also be supplied.
  950. InfoBuffer - optionally specifies the input buffer that was
  951. supplied by the caller to receive the results. If this argument
  952. is supplied, then InfoBufferSize must also be supplied.
  953. InfoBufferRetSize - optionally specifies a pointer that will receive
  954. the size of the results actually written to the InfoBuffer.
  955. Return Value:
  956. Returns STATUS_SUCCESS on a successful query result. If the
  957. operation is not successful, then the contents of 'pdwEnabled'
  958. are left untouched.
  959. --*/
  960. {
  961. NTSTATUS Status;
  962. DWORD dwValueState = (DWORD) 0;
  963. //
  964. // Open up the regkey to the base of the policies.
  965. //
  966. if (!g_bInitializedFirstTime) {
  967. Status = STATUS_UNSUCCESSFUL;
  968. goto ExitHandler;
  969. }
  970. RtlEnterCriticalSection(&g_TableCritSec);
  971. if (g_hKeyCustomRoot != NULL) {
  972. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  973. Status = STATUS_INVALID_PARAMETER_MIX;
  974. goto ExitHandler2;
  975. }
  976. } else {
  977. if (dwScopeId != SAFER_SCOPEID_MACHINE) {
  978. Status = STATUS_INVALID_PARAMETER_MIX;
  979. goto ExitHandler2;
  980. }
  981. }
  982. //
  983. // Query the current value setting.
  984. //
  985. {
  986. HANDLE hKeyBase;
  987. DWORD ActualSize;
  988. UNICODE_STRING ValueName;
  989. WCHAR KeyPathBuffer[ MAXIMUM_FILENAME_LENGTH+6 ];
  990. PKEY_VALUE_FULL_INFORMATION ValueBuffer =
  991. (PKEY_VALUE_FULL_INFORMATION) KeyPathBuffer;
  992. Status = CodeAuthzpOpenPolicyRootKey(
  993. dwScopeId,
  994. g_hKeyCustomRoot,
  995. L"\\" SAFER_CODEIDS_REGSUBKEY,
  996. KEY_READ, FALSE, &hKeyBase);
  997. if (NT_SUCCESS(Status)) {
  998. RtlInitUnicodeString(&ValueName,
  999. SAFER_POLICY_SCOPE);
  1000. Status = NtQueryValueKey(hKeyBase,
  1001. &ValueName,
  1002. KeyValueFullInformation,
  1003. ValueBuffer, // ptr to KeyPathBuffer
  1004. sizeof(KeyPathBuffer),
  1005. &ActualSize);
  1006. if (NT_SUCCESS(Status)) {
  1007. if (ValueBuffer->Type != REG_DWORD ||
  1008. ValueBuffer->DataLength != sizeof(DWORD)) {
  1009. Status = STATUS_NOT_FOUND;
  1010. } else {
  1011. dwValueState = * (PDWORD) ((PBYTE) ValueBuffer +
  1012. ValueBuffer->DataOffset);
  1013. }
  1014. }
  1015. NtClose(hKeyBase);
  1016. }
  1017. if (!NT_SUCCESS(Status)) {
  1018. // On failure, just ignore it and pretend it was FALSE.
  1019. dwValueState = 0;
  1020. }
  1021. }
  1022. //
  1023. // Make sure the target buffer is large
  1024. // enough and copy the object name into it.
  1025. //
  1026. if (!ARGUMENT_PRESENT(InfoBuffer) ||
  1027. InfoBufferSize < sizeof(DWORD)) {
  1028. Status = STATUS_BUFFER_TOO_SMALL;
  1029. } else {
  1030. RtlCopyMemory(InfoBuffer, &dwValueState, sizeof(DWORD));
  1031. Status = STATUS_SUCCESS;
  1032. }
  1033. if (ARGUMENT_PRESENT(InfoBufferRetSize))
  1034. *InfoBufferRetSize = sizeof(DWORD);
  1035. ExitHandler2:
  1036. RtlLeaveCriticalSection(&g_TableCritSec);
  1037. ExitHandler:
  1038. return Status;
  1039. }
  1040. NTSTATUS NTAPI
  1041. CodeAuthzPol_SetInfoRegistry_ScopeFlags(
  1042. IN DWORD dwScopeId,
  1043. IN DWORD InfoBufferSize,
  1044. IN PVOID InfoBuffer
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Modifies the current "scope flags" setting.
  1049. Note that this API always accepts a constant-sized buffer that is
  1050. only a single DWORD in length.
  1051. Arguments:
  1052. dwScopeId - specifies the registry scope that will be examined.
  1053. If the currently cached scope included a registry handle
  1054. then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
  1055. this must be SAFER_SCOPEID_MACHINE.
  1056. InfoBufferSize - specifies the size of input buffer
  1057. supplied by the caller to receive the results. If this argument
  1058. is supplied, then InfoBuffer must also be supplied.
  1059. InfoBuffer - specifies the input buffer that was
  1060. supplied by the caller to receive the results. If this argument
  1061. is supplied, then InfoBufferSize must also be supplied.
  1062. Return Value:
  1063. Returns STATUS_SUCCESS on a successful result.
  1064. --*/
  1065. {
  1066. HANDLE hKeyBase;
  1067. NTSTATUS Status;
  1068. UNICODE_STRING ValueName;
  1069. //
  1070. // Open up the regkey to the base of the policies.
  1071. //
  1072. if (!g_bInitializedFirstTime) {
  1073. Status = STATUS_UNSUCCESSFUL;
  1074. goto ExitHandler;
  1075. }
  1076. RtlEnterCriticalSection(&g_TableCritSec);
  1077. if (g_hKeyCustomRoot != NULL) {
  1078. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  1079. Status = STATUS_INVALID_PARAMETER_MIX;
  1080. goto ExitHandler2;
  1081. }
  1082. } else {
  1083. if (dwScopeId != SAFER_SCOPEID_MACHINE) {
  1084. Status = STATUS_INVALID_PARAMETER_MIX;
  1085. goto ExitHandler2;
  1086. }
  1087. }
  1088. Status = CodeAuthzpOpenPolicyRootKey(
  1089. dwScopeId, g_hKeyCustomRoot,
  1090. L"\\" SAFER_CODEIDS_REGSUBKEY,
  1091. KEY_READ | KEY_SET_VALUE,
  1092. TRUE, &hKeyBase);
  1093. if (!NT_SUCCESS(Status)) {
  1094. goto ExitHandler2;
  1095. }
  1096. //
  1097. // Make sure the input buffer is large enough.
  1098. //
  1099. if (InfoBufferSize < sizeof(DWORD) ||
  1100. !ARGUMENT_PRESENT(InfoBuffer)) {
  1101. Status = STATUS_BUFFER_TOO_SMALL;
  1102. goto ExitHandler3;
  1103. }
  1104. //
  1105. // Write the policy value that is specified.
  1106. //
  1107. RtlInitUnicodeString(&ValueName,
  1108. SAFER_POLICY_SCOPE);
  1109. Status = NtSetValueKey(hKeyBase,
  1110. &ValueName,
  1111. 0,
  1112. REG_DWORD,
  1113. InfoBuffer,
  1114. sizeof(DWORD));
  1115. ExitHandler3:
  1116. NtClose(hKeyBase);
  1117. ExitHandler2:
  1118. RtlLeaveCriticalSection(&g_TableCritSec);
  1119. ExitHandler:
  1120. return Status;
  1121. }