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.

1972 lines
61 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. safeset.c (WinSAFER SetInformation)
  5. Abstract:
  6. This module implements the WinSAFER APIs to set attributes and
  7. information relating to the Code Authorization Levels.
  8. Author:
  9. Jeffrey Lawson (JLawson) - May 2000
  10. Environment:
  11. User mode only.
  12. Exported Functions:
  13. SaferSetLevelInformation
  14. Revision History:
  15. Created - Nov 1999
  16. --*/
  17. #include "pch.h"
  18. #pragma hdrstop
  19. #include <sddl.h>
  20. #include <accctrl.h>
  21. #include <aclapi.h>
  22. #include <winsafer.h>
  23. #include <winsaferp.h>
  24. #include "saferp.h"
  25. #include "safewild.h"
  26. NTSTATUS NTAPI
  27. SaferpCreateSecondLevelKey(
  28. IN HANDLE hObjectKeyBase,
  29. IN LPCWSTR szFirstLevel,
  30. IN LPCWSTR szSecondLevel OPTIONAL,
  31. OUT PHANDLE phOutKey
  32. )
  33. /*++
  34. Routine Description:
  35. Opens a subkey under a specified registry key handle, creating that
  36. subkey if necessary. Up to two subkeys (ie: two levels deep) can
  37. be specified by specifying both the szFirstLevel and szSecondLevel
  38. arguments.
  39. Arguments:
  40. hObjectKeyBase - specifies a pre-opened registry handle to the
  41. base registry key under which the specified szFirstLevel subkey
  42. will be opened/created. This registry handle must be opened
  43. for write access, or else subkey creation will fail.
  44. szFirstLevel - specifies the first level subkey to open/create.
  45. szSecondLevel - optionally specifies the second subkey to open/create.
  46. phOutKey - pointer that will receive the opened registry key handle
  47. on successful execution of this function. This handle must be
  48. closed by the caller when its use is no longer required.
  49. Return Value:
  50. Returns STATUS_SUCCESS on successful opening of the requested key.
  51. Otherwise returns a status code indicating the nature of the failure.
  52. --*/
  53. {
  54. NTSTATUS Status;
  55. UNICODE_STRING SubkeyName;
  56. OBJECT_ATTRIBUTES ObjectAttributes;
  57. HANDLE hKeyFirstLevel, hKeySecondLevel;
  58. ASSERT(phOutKey != NULL && szFirstLevel != NULL);
  59. //
  60. // Open a handle to the "szFirstLevel" subkey,
  61. // creating it if needed.
  62. //
  63. RtlInitUnicodeString(&SubkeyName, szFirstLevel);
  64. InitializeObjectAttributes(&ObjectAttributes,
  65. &SubkeyName,
  66. OBJ_CASE_INSENSITIVE,
  67. hObjectKeyBase,
  68. NULL
  69. );
  70. Status = NtCreateKey(&hKeyFirstLevel, KEY_WRITE,
  71. &ObjectAttributes, 0, NULL,
  72. g_dwKeyOptions, NULL);
  73. if (!NT_SUCCESS(Status)) return Status;
  74. //
  75. // Open a handle to the "szFirstLevel\szSecondLevel"
  76. // subkey, creating it if needed.
  77. //
  78. if (ARGUMENT_PRESENT(szSecondLevel)) {
  79. RtlInitUnicodeString(&SubkeyName, szSecondLevel);
  80. InitializeObjectAttributes(&ObjectAttributes,
  81. &SubkeyName,
  82. OBJ_CASE_INSENSITIVE,
  83. hKeyFirstLevel,
  84. NULL
  85. );
  86. Status = NtCreateKey(&hKeySecondLevel,
  87. (KEY_WRITE & ~KEY_CREATE_SUB_KEY),
  88. &ObjectAttributes, 0,
  89. NULL, g_dwKeyOptions, NULL);
  90. NtClose(hKeyFirstLevel);
  91. if (!NT_SUCCESS(Status)) return Status;
  92. }
  93. else {
  94. hKeySecondLevel = hKeyFirstLevel;
  95. }
  96. *phOutKey = hKeySecondLevel;
  97. return STATUS_SUCCESS;
  98. }
  99. NTSTATUS NTAPI
  100. SaferpSetRegistryHelper(
  101. IN HANDLE hObjectKeyBase,
  102. IN LPCWSTR szFirstLevel,
  103. IN LPCWSTR szSecondLevel OPTIONAL,
  104. IN LPCWSTR szValueName,
  105. IN DWORD dwRegType,
  106. IN LPVOID lpDataBuffer,
  107. IN DWORD dwDataBufferSize
  108. )
  109. /*++
  110. Routine Description:
  111. Arguments:
  112. Return Value:
  113. --*/
  114. {
  115. NTSTATUS Status;
  116. HKEY hKeySecondLevel;
  117. UNICODE_STRING ValueName;
  118. //
  119. // Open a handle to the correct subkey.
  120. //
  121. Status = SaferpCreateSecondLevelKey(
  122. hObjectKeyBase,
  123. szFirstLevel,
  124. szSecondLevel,
  125. &hKeySecondLevel
  126. );
  127. if (!NT_SUCCESS(Status)) return Status;
  128. //
  129. // Write the new value to "szValueName"
  130. //
  131. RtlInitUnicodeString(&ValueName, szValueName);
  132. Status = NtSetValueKey(hKeySecondLevel,
  133. &ValueName, 0, dwRegType,
  134. (LPBYTE) lpDataBuffer, dwDataBufferSize);
  135. NtClose(hKeySecondLevel);
  136. return Status;
  137. }
  138. #ifdef ALLOW_FULL_WINSAFER
  139. NTSTATUS NTAPI
  140. SaferpClearRegistryListHelper(
  141. IN HANDLE hObjectKeyBase,
  142. IN LPCWSTR szValueCountName,
  143. IN LPCWSTR szPrefixName
  144. )
  145. /*++
  146. Routine Description:
  147. Arguments:
  148. Return Value:
  149. --*/
  150. {
  151. NTSTATUS Status;
  152. BOOLEAN bCompletePass;
  153. BYTE LocalBuffer[256];
  154. ULONG ulKeyInfoSize = sizeof(LocalBuffer);
  155. PKEY_VALUE_BASIC_INFORMATION pKeyInfo =
  156. (PKEY_VALUE_BASIC_INFORMATION) LocalBuffer;
  157. ULONG ulKeyIndex, ulSizeUsed;
  158. //
  159. // Start iterating through all of the values under this subkey and
  160. // see if there are any values that match the prefix that we are
  161. // supposed to delete. If we find something we should delete, then
  162. // we do that, but we continue iterating with the expectation that
  163. // the enumeration values might possibly change when we deleted.
  164. // So we will keep looping until we are able to enumerate completely
  165. // through without finding something to delete.
  166. //
  167. ulKeyIndex = 0;
  168. bCompletePass = TRUE;
  169. for (;;)
  170. {
  171. //
  172. // Determine the next value name under this key.
  173. //
  174. Status = NtEnumerateValueKey(hObjectKeyBase,
  175. ulKeyIndex,
  176. KeyValueBasicInformation,
  177. pKeyInfo,
  178. ulKeyInfoSize,
  179. &ulSizeUsed);
  180. if (!NT_SUCCESS(Status))
  181. {
  182. if (Status == STATUS_BUFFER_TOO_SMALL) {
  183. // Buffer is too small, so we need to enlarge.
  184. ASSERT(ulSizeUsed > ulKeyInfoSize);
  185. if (pKeyInfo != (PKEY_VALUE_BASIC_INFORMATION) LocalBuffer) {
  186. RtlFreeHeap(RtlProcessHeap(), 0, pKeyInfo);
  187. }
  188. ulKeyInfoSize = ulSizeUsed;
  189. pKeyInfo = (PKEY_VALUE_BASIC_INFORMATION )
  190. RtlAllocateHeap(RtlProcessHeap(), 0, ulKeyInfoSize);
  191. if (!pKeyInfo) {
  192. Status = STATUS_NO_MEMORY;
  193. goto ExitHandler;
  194. }
  195. continue;
  196. }
  197. else if (Status == STATUS_NO_MORE_ENTRIES) {
  198. // All done enumerating.
  199. if (bCompletePass) {
  200. // We just finished a complete pass through without any
  201. // deletions so we really know that we're done now.
  202. break;
  203. } else {
  204. // We haven't yet completed a full pass without hitting
  205. // any deletions so we must try again, since the value
  206. // enumerations might have changed at least once.
  207. bCompletePass = TRUE;
  208. ulKeyIndex = 0;
  209. continue;
  210. }
  211. }
  212. else {
  213. // All other errors get literally returned.
  214. // This is especially yucky if this error occurred partially
  215. // through our attempt to delete everything.
  216. goto ExitHandler;
  217. }
  218. }
  219. //
  220. // If this value is something that we need to delete,
  221. // then delete it now and then restart the enumeration.
  222. //
  223. if (_wcsnicmp(pKeyInfo->Name, szPrefixName,
  224. wcslen(szPrefixName)) == 0 ||
  225. _wcsicmp(pKeyInfo->Name, szValueCountName) == 0)
  226. {
  227. UNICODE_STRING ValueName;
  228. bCompletePass = FALSE;
  229. ValueName.Buffer = pKeyInfo->Name;
  230. ValueName.MaximumLength = ValueName.Length =
  231. pKeyInfo->NameLength;
  232. ASSERT(ValueName.Length == sizeof(WCHAR) * wcslen(ValueName.Buffer));
  233. Status = NtDeleteValueKey(hObjectKeyBase, &ValueName);
  234. if (!NT_SUCCESS(Status)) {
  235. // Oh yuck, we got an error deleting. This is especially
  236. // yucky if this error occurred partially through our
  237. // attempt to delete everything.
  238. goto ExitHandler;
  239. }
  240. continue;
  241. }
  242. ulKeyIndex++;
  243. }
  244. Status = STATUS_SUCCESS;
  245. ExitHandler:
  246. if (pKeyInfo != (PKEY_VALUE_BASIC_INFORMATION) LocalBuffer) {
  247. RtlFreeHeap(RtlProcessHeap(), 0, pKeyInfo);
  248. }
  249. return Status;
  250. }
  251. #endif // ALLOW_FULL_WINSAFER
  252. #ifdef ALLOW_FULL_WINSAFER
  253. NTSTATUS NTAPI
  254. SaferpSetListOfSids(
  255. IN HKEY hKeyBase,
  256. IN LPCWSTR szFirstLevel,
  257. IN LPCWSTR szSecondLevel OPTIONAL,
  258. IN LPCWSTR szValueCountName,
  259. IN LPCWSTR szPrefixName,
  260. IN PTOKEN_GROUPS pTokenGroups,
  261. IN BOOLEAN bAllowWildcardSids
  262. )
  263. /*++
  264. Routine Description:
  265. Arguments:
  266. Return Value:
  267. --*/
  268. //BLACKCOMB TODO: This really needs to take a dwInBufferSize argument so that
  269. // the size of the pTokenGroups structure can be verified.
  270. {
  271. NTSTATUS Status;
  272. HKEY hSidsToDisable;
  273. UNICODE_STRING ValueName;
  274. DWORD Index;
  275. //
  276. // First verify the SIDs and that the Attributes field
  277. // of all of the SIDs are zero.
  278. //
  279. for (Index = 0; Index < pTokenGroups->GroupCount; Index++)
  280. {
  281. if (!RtlValidSid(pTokenGroups->Groups[Index].Sid))
  282. return STATUS_INVALID_SID;
  283. if (pTokenGroups->Groups[Index].Attributes != 0)
  284. {
  285. if (bAllowWildcardSids) {
  286. //BLACKCOMB TODO: handle wildcard sids differently?
  287. if ((pTokenGroups->Groups[Index].Attributes >> 24) != '*' &&
  288. (pTokenGroups->Groups[Index].Attributes & 0x0000FFFF) >
  289. ((PISID)pTokenGroups->Groups[Index].Sid)->SubAuthorityCount)
  290. return STATUS_INVALID_SID;
  291. }
  292. else
  293. return STATUS_INVALID_SID;
  294. }
  295. }
  296. //
  297. // Open a handle to the correct subkey.
  298. //
  299. Status = SaferpCreateSecondLevelKey(
  300. hKeyBase,
  301. szFirstLevel,
  302. szSecondLevel,
  303. &hSidsToDisable);
  304. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  305. //
  306. // Clear out all old values under the subkey.
  307. //
  308. Status = SaferpClearRegistryListHelper(
  309. hSidsToDisable,
  310. szValueCountName,
  311. szPrefixName);
  312. if (!NT_SUCCESS(Status)) {
  313. // Bad luck! Possibly left in incomplete state!
  314. NtClose(hSidsToDisable);
  315. goto ExitHandler2;
  316. }
  317. //
  318. // Now add all of the new ones we're supposed to add.
  319. //
  320. RtlInitUnicodeString(&ValueName, szValueCountName);
  321. Status = NtSetValueKey(hSidsToDisable,
  322. &ValueName, 0, REG_DWORD,
  323. (LPBYTE) pTokenGroups->GroupCount, sizeof(DWORD));
  324. if (!NT_SUCCESS(Status)) {
  325. // Bad luck! Possibly left in incomplete state!
  326. NtClose(hSidsToDisable);
  327. goto ExitHandler2;
  328. }
  329. for (Index = 0; Index < pTokenGroups->GroupCount; Index++)
  330. {
  331. WCHAR ValueNameBuffer[20];
  332. UNICODE_STRING UnicodeStringSid;
  333. wsprintfW(ValueNameBuffer, L"%S%d", szPrefixName, Index);
  334. RtlInitUnicodeString(&ValueName, ValueNameBuffer);
  335. //BLACKCOMB TODO: wildcard sids not yet supported
  336. if (bAllowWildcardSids)
  337. Status = xxxxx;
  338. else
  339. Status = RtlConvertSidToUnicodeString( &UnicodeStringSid,
  340. pTokenGroups->Groups[Index].Sid, TRUE );
  341. if (!NT_SUCCESS(Status))
  342. {
  343. // Bad luck! Possibly left in incomplete state!
  344. NtClose(hSidsToDisable);
  345. goto ExitHandler2;
  346. }
  347. Status = NtSetValueKey(hSidsToDisable,
  348. &ValueName, 0, REG_SZ,
  349. (LPBYTE) UnicodeStringSid.Buffer,
  350. UnicodeStringSid.Length + sizeof(UNICODE_NULL));
  351. RtlFreeUnicodeString( &UnicodeStringSid );
  352. if (!NT_SUCCESS(Status)) {
  353. // Bad luck! Possibly left in incomplete state!
  354. NtClose(hSidsToDisable);
  355. goto ExitHandler2;
  356. }
  357. }
  358. NtClose(hSidsToDisable);
  359. return STATUS_SUCCESS;
  360. ExitHandler2:
  361. return Status;
  362. }
  363. #endif // ALLOW_FULL_WINSAFER
  364. NTSTATUS NTAPI
  365. SaferpDeleteSingleIdentificationGuid(
  366. IN PAUTHZLEVELTABLERECORD pLevelRecord,
  367. IN PAUTHZIDENTSTABLERECORD pIdentRecord)
  368. /*++
  369. Routine Description:
  370. This API allows the caller to delete an existing Code Identifier.
  371. If the GUID exists it will be deleted from both the persisted
  372. registry store and the in-process identity cache.
  373. Arguments:
  374. pLevelRecord - the level to which the identity belongs.
  375. pIdentRecord - points to the identifier record to delete.
  376. Return Value:
  377. Returns STATUS_SUCCESS on successful operation.
  378. --*/
  379. {
  380. NTSTATUS Status;
  381. WCHAR szPathBuffer[MAX_PATH];
  382. UNICODE_STRING UnicodePath;
  383. HANDLE hKeyIdentity;
  384. LPCWSTR szIdentityType;
  385. //
  386. // Verify our input arguments.
  387. //
  388. if (!ARGUMENT_PRESENT(pIdentRecord) ||
  389. !ARGUMENT_PRESENT(pLevelRecord)) {
  390. // Specified a NULL buffer pointer.
  391. Status = STATUS_ACCESS_VIOLATION;
  392. goto ExitHandler;
  393. }
  394. //
  395. // Ensure that all of the GUIDs supplied by the user represent
  396. // Code Identities that exist within this Safer Level.
  397. //
  398. if (pIdentRecord->dwLevelId != pLevelRecord->dwLevelId) {
  399. // One of the Identifier GUIDs specified does
  400. // not actually exist.
  401. Status = STATUS_NOT_FOUND;
  402. goto ExitHandler;
  403. }
  404. //
  405. // Delete the Code Identity from the registry first.
  406. //
  407. switch (pIdentRecord->dwIdentityType) {
  408. case SaferIdentityTypeImageName:
  409. szIdentityType = SAFER_PATHS_REGSUBKEY;
  410. break;
  411. case SaferIdentityTypeImageHash:
  412. szIdentityType = SAFER_HASHMD5_REGSUBKEY;
  413. break;
  414. case SaferIdentityTypeUrlZone:
  415. szIdentityType = SAFER_SOURCEURL_REGSUBKEY;
  416. break;
  417. default:
  418. Status = STATUS_NOT_FOUND;
  419. goto ExitHandler;
  420. }
  421. RtlInitEmptyUnicodeString(
  422. &UnicodePath, szPathBuffer, sizeof(szPathBuffer));
  423. Status = CodeAuthzpFormatIdentityKeyPath(
  424. pIdentRecord->dwLevelId,
  425. szIdentityType,
  426. &pIdentRecord->IdentGuid,
  427. &UnicodePath);
  428. if (!NT_SUCCESS(Status)) {
  429. goto ExitHandler;
  430. }
  431. Status = CodeAuthzpOpenPolicyRootKey(
  432. pIdentRecord->dwScopeId,
  433. g_hKeyCustomRoot,
  434. szPathBuffer,
  435. KEY_READ | DELETE,
  436. FALSE, &hKeyIdentity);
  437. if (!NT_SUCCESS(Status)) {
  438. goto ExitHandler;
  439. }
  440. Status = CodeAuthzpDeleteKeyRecursively(hKeyIdentity, NULL);
  441. NtClose(hKeyIdentity);
  442. if (!NT_SUCCESS(Status)) {
  443. goto ExitHandler;
  444. }
  445. //
  446. // Delete the record from the cached table.
  447. //
  448. RtlDeleteElementGenericTable(
  449. &g_CodeIdentitiesTable,
  450. pIdentRecord);
  451. Status = STATUS_SUCCESS;
  452. ExitHandler:
  453. return Status;
  454. }
  455. NTSTATUS NTAPI
  456. SaferpSetSingleIdentificationPath(
  457. IN BOOLEAN bAllowCreation,
  458. IN OUT PAUTHZIDENTSTABLERECORD pIdentRecord,
  459. IN PSAFER_PATHNAME_IDENTIFICATION pIdentChanges,
  460. IN BOOL UpdateCache
  461. )
  462. /*++
  463. Routine Description:
  464. Updates the registry and the local Identification table cache
  465. with new properties about a ImagePath Code Identifier.
  466. Arguments:
  467. bAllowCreation - indicates if the modification of this record has
  468. the potential of being the initial creation of this record.
  469. If this is false and the corresponding key location within the
  470. registry does not already exist, then this function call
  471. will fail.
  472. pIdentRecord - the cached code identity record that should be
  473. updated with new values. This argument must always be supplied,
  474. even if the Code Identity is being created for the first time
  475. (in which case, this argument should be the new record that
  476. the caller has just inserted into the cached idents table).
  477. pIdentChanges - the input structure containing the new modifications
  478. that should be made to the specified Code Identity.
  479. UpdateCache - When FALSE, this is a default rule being created and does
  480. not need cache updation.
  481. Return Value:
  482. Return STATUS_SUCCESS on success completion, or another error
  483. status code indicating the nature of the failure.
  484. --*/
  485. {
  486. const static UNICODE_STRING UnicodeLastModified =
  487. RTL_CONSTANT_STRING(SAFER_IDS_LASTMODIFIED_REGVALUE);
  488. const static UNICODE_STRING UnicodeDescription =
  489. RTL_CONSTANT_STRING(SAFER_IDS_DESCRIPTION_REGVALUE);
  490. const static UNICODE_STRING UnicodeSaferFlags =
  491. RTL_CONSTANT_STRING(SAFER_IDS_SAFERFLAGS_REGVALUE);
  492. const static UNICODE_STRING UnicodeItemData =
  493. RTL_CONSTANT_STRING(SAFER_IDS_ITEMDATA_REGVALUE);
  494. NTSTATUS Status;
  495. HANDLE hKeyIdentity = NULL;
  496. UNICODE_STRING UnicodeTemp;
  497. UNICODE_STRING UnicodeNewDescription;
  498. UNICODE_STRING UnicodeNewImagePath;
  499. WCHAR szPathBuffer[MAX_PATH];
  500. DWORD dwSaferFlags;
  501. FILETIME CurrentTime;
  502. BOOLEAN bExpandVars;
  503. //
  504. // Verify our arguments. These things should have been ensured
  505. // by our caller already, so we only assert them here.
  506. //
  507. ASSERT(ARGUMENT_PRESENT(pIdentRecord) &&
  508. ARGUMENT_PRESENT(pIdentChanges) &&
  509. pIdentChanges->header.dwIdentificationType == SaferIdentityTypeImageName &&
  510. IsEqualGUID(&pIdentChanges->header.IdentificationGuid, &pIdentRecord->IdentGuid));
  511. //
  512. // Verify that the existing type matches the new type.
  513. // Cannot change identity type once it has been created.
  514. //
  515. if (pIdentRecord->dwIdentityType != SaferIdentityTypeImageName) {
  516. Status = STATUS_INVALID_PARAMETER;
  517. goto ExitHandler;
  518. }
  519. //
  520. // Verify that the string arguments are properly terminated.
  521. // We require that they fit entirely within the input buffer
  522. // and also have an explicit null terminator.
  523. //
  524. RtlInitUnicodeString(&UnicodeNewImagePath, pIdentChanges->ImageName);
  525. RtlInitUnicodeString(&UnicodeNewDescription, pIdentChanges->Description);
  526. if (UnicodeNewDescription.Length >=
  527. SAFER_MAX_DESCRIPTION_SIZE * sizeof(WCHAR) ||
  528. UnicodeNewImagePath.Length >= MAX_PATH * sizeof(WCHAR) ||
  529. UnicodeNewImagePath.Length == 0) {
  530. // One of these buffers was not NULL terminated.
  531. Status = STATUS_INVALID_PARAMETER;
  532. goto ExitHandler;
  533. }
  534. //
  535. // Open a registry handle to the Code Identity.
  536. //
  537. RtlInitEmptyUnicodeString(
  538. &UnicodeTemp, szPathBuffer, sizeof(szPathBuffer));
  539. Status = CodeAuthzpFormatIdentityKeyPath(
  540. pIdentRecord->dwLevelId,
  541. SAFER_PATHS_REGSUBKEY,
  542. &pIdentRecord->IdentGuid,
  543. &UnicodeTemp);
  544. if (!NT_SUCCESS(Status)) {
  545. goto ExitHandler;
  546. }
  547. Status = CodeAuthzpOpenPolicyRootKey(
  548. pIdentRecord->dwScopeId,
  549. g_hKeyCustomRoot,
  550. szPathBuffer,
  551. KEY_READ | KEY_WRITE,
  552. bAllowCreation,
  553. &hKeyIdentity);
  554. if (!NT_SUCCESS(Status)) {
  555. goto ExitHandler;
  556. }
  557. //
  558. // Set the "Last Modified" attribute in the registry.
  559. //
  560. GetSystemTimeAsFileTime(&CurrentTime);
  561. ASSERT(sizeof(DWORD) * 2 == sizeof(FILETIME));
  562. Status = NtSetValueKey(
  563. hKeyIdentity,
  564. (PUNICODE_STRING) &UnicodeLastModified,
  565. 0, REG_QWORD, (LPBYTE) &CurrentTime,
  566. sizeof(DWORD) * 2);
  567. if (!NT_SUCCESS(Status)) {
  568. goto ExitHandler2;
  569. }
  570. //
  571. // Set the "Description" attribute in the registry.
  572. //
  573. Status = NtSetValueKey(
  574. hKeyIdentity,
  575. (PUNICODE_STRING) &UnicodeDescription,
  576. 0, REG_SZ, (LPBYTE) UnicodeNewDescription.Buffer,
  577. UnicodeNewDescription.MaximumLength);
  578. if (!NT_SUCCESS(Status)) {
  579. goto ExitHandler2;
  580. }
  581. //
  582. // Set the "SaferFlags" attribute in the registry (and in our cache).
  583. //
  584. dwSaferFlags = pIdentChanges->dwSaferFlags;
  585. Status = NtSetValueKey(
  586. hKeyIdentity,
  587. (PUNICODE_STRING) &UnicodeSaferFlags,
  588. 0, REG_DWORD, (LPBYTE) &dwSaferFlags, sizeof(DWORD));
  589. if (!NT_SUCCESS(Status)) {
  590. goto ExitHandler2;
  591. }
  592. //
  593. // Set the "image pathname" attribute in the registry (and our cache).
  594. //
  595. bExpandVars = (wcschr(pIdentChanges->ImageName, L'%') != NULL ? TRUE : FALSE);
  596. Status = NtSetValueKey(
  597. hKeyIdentity,
  598. (PUNICODE_STRING) &UnicodeItemData,
  599. 0, (bExpandVars ? REG_EXPAND_SZ : REG_SZ),
  600. (LPBYTE) UnicodeNewImagePath.Buffer,
  601. UnicodeNewImagePath.MaximumLength );
  602. if (!NT_SUCCESS(Status)) {
  603. goto ExitHandler2;
  604. }
  605. if (UpdateCache) {
  606. RtlFreeUnicodeString(&pIdentRecord->ImageNameInfo.ImagePath);
  607. Status = RtlDuplicateUnicodeString(
  608. RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
  609. &UnicodeNewImagePath,
  610. &pIdentRecord->ImageNameInfo.ImagePath);
  611. if (!NT_SUCCESS(Status)) {
  612. goto ExitHandler2;
  613. }
  614. pIdentRecord->ImageNameInfo.bExpandVars = bExpandVars;
  615. pIdentRecord->ImageNameInfo.dwSaferFlags = dwSaferFlags;
  616. }
  617. Status = STATUS_SUCCESS;
  618. ExitHandler2:
  619. NtClose(hKeyIdentity);
  620. ExitHandler:
  621. return Status;
  622. }
  623. NTSTATUS NTAPI
  624. SaferpSetSingleIdentificationHash(
  625. IN BOOLEAN bAllowCreation,
  626. IN OUT PAUTHZIDENTSTABLERECORD pIdentRecord,
  627. IN PSAFER_HASH_IDENTIFICATION pIdentChanges
  628. )
  629. /*++
  630. Routine Description:
  631. Updates the registry and the local Identification table cache
  632. with new properties about a hash Code Identifier.
  633. Arguments:
  634. bAllowCreation - indicates if the modification of this record has
  635. the potential of being the initial creation of this record.
  636. If this is false and the corresponding key location within the
  637. registry does not already exist, then this function call
  638. will fail.
  639. pIdentRecord - the cached code identity record that should be
  640. updated with new values. This argument must always be supplied,
  641. even if the Code Identity is being created for the first time
  642. (in which case, this argument should be the new record that
  643. the caller has just inserted into the cached idents table).
  644. pIdentChanges - the input structure containing the new modifications
  645. that should be made to the specified Code Identity.
  646. Return Value:
  647. Return STATUS_SUCCESS on success completion, or another error
  648. status code indicating the nature of the failure.
  649. --*/
  650. {
  651. const static UNICODE_STRING UnicodeLastModified =
  652. RTL_CONSTANT_STRING(SAFER_IDS_LASTMODIFIED_REGVALUE);
  653. const static UNICODE_STRING UnicodeDescription =
  654. RTL_CONSTANT_STRING(SAFER_IDS_DESCRIPTION_REGVALUE);
  655. const static UNICODE_STRING UnicodeSaferFlags =
  656. RTL_CONSTANT_STRING(SAFER_IDS_SAFERFLAGS_REGVALUE);
  657. const static UNICODE_STRING UnicodeItemData =
  658. RTL_CONSTANT_STRING(SAFER_IDS_ITEMDATA_REGVALUE);
  659. const static UNICODE_STRING UnicodeFriendlyName =
  660. RTL_CONSTANT_STRING(SAFER_IDS_FRIENDLYNAME_REGVALUE);
  661. const static UNICODE_STRING UnicodeItemSize =
  662. RTL_CONSTANT_STRING(SAFER_IDS_ITEMSIZE_REGVALUE);
  663. const static UNICODE_STRING UnicodeHashAlgorithm =
  664. RTL_CONSTANT_STRING(SAFER_IDS_HASHALG_REGVALUE);
  665. NTSTATUS Status;
  666. HANDLE hKeyIdentity = NULL;
  667. UNICODE_STRING UnicodeTemp;
  668. UNICODE_STRING UnicodeNewFriendlyName;
  669. UNICODE_STRING UnicodeNewDescription;
  670. WCHAR szPathBuffer[MAX_PATH];
  671. DWORD dwSaferFlags;
  672. FILETIME CurrentTime;
  673. //
  674. // Verify our arguments. These things should have been ensured
  675. // by our caller already, so we only assert them here.
  676. //
  677. ASSERT(ARGUMENT_PRESENT(pIdentRecord) &&
  678. ARGUMENT_PRESENT(pIdentChanges) &&
  679. pIdentChanges->header.dwIdentificationType == SaferIdentityTypeImageHash &&
  680. pIdentChanges->header.cbStructSize == sizeof(SAFER_HASH_IDENTIFICATION) &&
  681. IsEqualGUID(&pIdentChanges->header.IdentificationGuid, &pIdentRecord->IdentGuid));
  682. //
  683. // Verify that the existing type matches the new type.
  684. // Cannot change identity type once it has been created.
  685. //
  686. if (pIdentRecord->dwIdentityType != SaferIdentityTypeImageHash) {
  687. Status = STATUS_INVALID_PARAMETER;
  688. goto ExitHandler;
  689. }
  690. //
  691. // Verify that the string arguments are properly terminated.
  692. // We require that they fit entirely within the input buffer
  693. // and also have an explicit null terminator.
  694. //
  695. RtlInitUnicodeString(&UnicodeNewDescription, pIdentChanges->Description);
  696. RtlInitUnicodeString(&UnicodeNewFriendlyName, pIdentChanges->FriendlyName);
  697. if (UnicodeNewDescription.Length >=
  698. SAFER_MAX_DESCRIPTION_SIZE * sizeof(WCHAR) ||
  699. UnicodeNewFriendlyName.Length >=
  700. SAFER_MAX_FRIENDLYNAME_SIZE * sizeof(WCHAR) ||
  701. pIdentChanges->HashSize > SAFER_MAX_HASH_SIZE)
  702. {
  703. // One of these buffers was not NULL terminated or
  704. // the hash size specified was invalid.
  705. Status = STATUS_INVALID_PARAMETER;
  706. goto ExitHandler;
  707. }
  708. if ((pIdentChanges->HashAlgorithm & ALG_CLASS_ALL) != ALG_CLASS_HASH ||
  709. pIdentChanges->HashSize < 1) {
  710. // The hash algorithm method was an invalid type, or
  711. // a zero-length hash was supplied.
  712. Status = STATUS_INVALID_PARAMETER;
  713. goto ExitHandler;
  714. }
  715. //
  716. // Open a registry handle to the Code Identity.
  717. //
  718. RtlInitEmptyUnicodeString(
  719. &UnicodeTemp, szPathBuffer, sizeof(szPathBuffer));
  720. Status = CodeAuthzpFormatIdentityKeyPath(
  721. pIdentRecord->dwLevelId,
  722. SAFER_HASHMD5_REGSUBKEY,
  723. &pIdentRecord->IdentGuid,
  724. &UnicodeTemp);
  725. if (!NT_SUCCESS(Status)) {
  726. goto ExitHandler;
  727. }
  728. Status = CodeAuthzpOpenPolicyRootKey(
  729. pIdentRecord->dwScopeId,
  730. g_hKeyCustomRoot,
  731. szPathBuffer,
  732. KEY_READ | KEY_WRITE,
  733. bAllowCreation,
  734. &hKeyIdentity);
  735. if (!NT_SUCCESS(Status)) {
  736. goto ExitHandler;
  737. }
  738. //
  739. // Set the "Last Modified" attribute in the registry.
  740. //
  741. GetSystemTimeAsFileTime(&CurrentTime);
  742. ASSERT(sizeof(DWORD) * 2 == sizeof(FILETIME));
  743. Status = NtSetValueKey(
  744. hKeyIdentity,
  745. (PUNICODE_STRING) &UnicodeLastModified, 0,
  746. REG_QWORD, (LPBYTE) &CurrentTime,
  747. sizeof(DWORD) * 2);
  748. if (!NT_SUCCESS(Status)) {
  749. goto ExitHandler2;
  750. }
  751. //
  752. // Set the "Description" attribute in the registry.
  753. //
  754. Status = NtSetValueKey(
  755. hKeyIdentity,
  756. (PUNICODE_STRING) &UnicodeDescription,
  757. 0, REG_SZ, (LPBYTE) UnicodeNewDescription.Buffer,
  758. UnicodeNewDescription.MaximumLength);
  759. if (!NT_SUCCESS(Status)) {
  760. goto ExitHandler2;
  761. }
  762. //
  763. // Set the "FriendlyName" attribute in the registry.
  764. //
  765. Status = NtSetValueKey(
  766. hKeyIdentity,
  767. (PUNICODE_STRING) &UnicodeFriendlyName,
  768. 0, REG_SZ, (LPBYTE) UnicodeNewFriendlyName.Buffer,
  769. UnicodeNewFriendlyName.MaximumLength);
  770. if (!NT_SUCCESS(Status)) {
  771. goto ExitHandler2;
  772. }
  773. //
  774. // Set the "SaferFlags" attribute in the registry (and in our cache).
  775. //
  776. #ifdef SAFER_SAFERFLAGS_ONLY_EXES
  777. dwSaferFlags = (pIdentChanges->dwSaferFlags &
  778. ~SAFER_SAFERFLAGS_ONLY_EXES);
  779. #else
  780. dwSaferFlags = pIdentChanges->dwSaferFlags;
  781. #endif
  782. Status = NtSetValueKey(
  783. hKeyIdentity,
  784. (PUNICODE_STRING) &UnicodeSaferFlags,
  785. 0, REG_DWORD, (LPBYTE) &dwSaferFlags, sizeof(DWORD));
  786. if (!NT_SUCCESS(Status)) {
  787. goto ExitHandler2;
  788. }
  789. pIdentRecord->ImageNameInfo.dwSaferFlags = dwSaferFlags;
  790. //
  791. // Set the "image size" attribute in the registry (and our cache).
  792. //
  793. Status = NtSetValueKey(
  794. hKeyIdentity,
  795. (PUNICODE_STRING) &UnicodeItemSize,
  796. 0, REG_QWORD, (LPBYTE) &pIdentChanges->ImageSize.QuadPart,
  797. sizeof(DWORD) * 2);
  798. if (!NT_SUCCESS(Status)) {
  799. goto ExitHandler2;
  800. }
  801. pIdentRecord->ImageHashInfo.ImageSize.QuadPart =
  802. pIdentChanges->ImageSize.QuadPart;
  803. //
  804. // Set the "image hash" attribute in the registry (and our cache).
  805. //
  806. Status = NtSetValueKey(
  807. hKeyIdentity,
  808. (PUNICODE_STRING) &UnicodeItemData,
  809. 0, REG_BINARY, (LPBYTE) pIdentChanges->ImageHash,
  810. pIdentChanges->HashSize);
  811. if (!NT_SUCCESS(Status)) {
  812. goto ExitHandler2;
  813. }
  814. pIdentRecord->ImageHashInfo.HashSize =
  815. pIdentChanges->HashSize;
  816. RtlCopyMemory(&pIdentRecord->ImageHashInfo.ImageHash[0],
  817. &pIdentChanges->ImageHash[0],
  818. pIdentChanges->HashSize);
  819. //
  820. // Set the "hash algorithm" attribute in the registry (and our cache).
  821. //
  822. Status = NtSetValueKey(
  823. hKeyIdentity,
  824. (PUNICODE_STRING) &UnicodeHashAlgorithm,
  825. 0, REG_DWORD, (LPBYTE) &pIdentChanges->HashAlgorithm,
  826. sizeof(DWORD));
  827. if (!NT_SUCCESS(Status)) {
  828. goto ExitHandler2;
  829. }
  830. pIdentRecord->ImageHashInfo.HashAlgorithm =
  831. pIdentChanges->HashAlgorithm;
  832. Status = STATUS_SUCCESS;
  833. ExitHandler2:
  834. NtClose(hKeyIdentity);
  835. ExitHandler:
  836. return Status;
  837. }
  838. NTSTATUS NTAPI
  839. SaferpSetSingleIdentificationZone(
  840. IN BOOLEAN bAllowCreation,
  841. IN OUT PAUTHZIDENTSTABLERECORD pIdentRecord,
  842. IN PSAFER_URLZONE_IDENTIFICATION pIdentChanges
  843. )
  844. /*++
  845. Routine Description:
  846. Updates the registry and the local Identification table cache
  847. with new properties about a URL Zone Code Identifier.
  848. Arguments:
  849. bAllowCreation - indicates if the modification of this record has
  850. the potential of being the initial creation of this record.
  851. If this is false and the corresponding key location within the
  852. registry does not already exist, then this function call
  853. will fail.
  854. pIdentRecord - the cached code identity record that should be
  855. updated with new values. This argument must always be supplied,
  856. even if the Code Identity is being created for the first time
  857. (in which case, this argument should be the new record that
  858. the caller has just inserted into the cached idents table).
  859. pIdentChanges - the input structure containing the new modifications
  860. that should be made to the specified Code Identity.
  861. Return Value:
  862. Return STATUS_SUCCESS on success completion, or another error
  863. status code indicating the nature of the failure.
  864. --*/
  865. {
  866. const static UNICODE_STRING UnicodeLastModified =
  867. RTL_CONSTANT_STRING(SAFER_IDS_LASTMODIFIED_REGVALUE);
  868. const static UNICODE_STRING UnicodeSaferFlags =
  869. RTL_CONSTANT_STRING(SAFER_IDS_SAFERFLAGS_REGVALUE);
  870. const static UNICODE_STRING UnicodeItemData =
  871. RTL_CONSTANT_STRING(SAFER_IDS_ITEMDATA_REGVALUE);
  872. NTSTATUS Status;
  873. HANDLE hKeyIdentity = NULL;
  874. UNICODE_STRING UnicodeTemp;
  875. WCHAR szPathBuffer[MAX_PATH];
  876. DWORD dwSaferFlags;
  877. FILETIME CurrentTime;
  878. //
  879. // Verify our arguments. These things should have been ensured
  880. // by our caller already, so we only assert them here.
  881. //
  882. ASSERT(ARGUMENT_PRESENT(pIdentRecord) &&
  883. ARGUMENT_PRESENT(pIdentChanges) &&
  884. pIdentChanges->header.dwIdentificationType == SaferIdentityTypeUrlZone &&
  885. pIdentChanges->header.cbStructSize == sizeof(SAFER_URLZONE_IDENTIFICATION) &&
  886. IsEqualGUID(&pIdentChanges->header.IdentificationGuid, &pIdentRecord->IdentGuid));
  887. //
  888. // Verify that the existing type matches the new type.
  889. // Cannot change identity type once it has been created.
  890. //
  891. if (pIdentRecord->dwIdentityType != SaferIdentityTypeUrlZone) {
  892. Status = STATUS_INVALID_PARAMETER;
  893. goto ExitHandler;
  894. }
  895. //
  896. // Open a registry handle to the Code Identity.
  897. //
  898. RtlInitEmptyUnicodeString(
  899. &UnicodeTemp, szPathBuffer, sizeof(szPathBuffer));
  900. Status = CodeAuthzpFormatIdentityKeyPath(
  901. pIdentRecord->dwLevelId,
  902. SAFER_SOURCEURL_REGSUBKEY,
  903. &pIdentRecord->IdentGuid,
  904. &UnicodeTemp);
  905. if (!NT_SUCCESS(Status)) {
  906. goto ExitHandler;
  907. }
  908. Status = CodeAuthzpOpenPolicyRootKey(
  909. pIdentRecord->dwScopeId,
  910. g_hKeyCustomRoot,
  911. szPathBuffer,
  912. KEY_READ | KEY_WRITE,
  913. bAllowCreation,
  914. &hKeyIdentity);
  915. if (!NT_SUCCESS(Status)) {
  916. goto ExitHandler;
  917. }
  918. //
  919. // Set the "Last Modified" attribute in the registry.
  920. //
  921. GetSystemTimeAsFileTime(&CurrentTime);
  922. ASSERT(sizeof(DWORD) * 2 == sizeof(FILETIME));
  923. Status = NtSetValueKey(
  924. hKeyIdentity,
  925. (PUNICODE_STRING) &UnicodeLastModified,
  926. 0, REG_QWORD, (LPBYTE) &CurrentTime,
  927. sizeof(DWORD) * 2);
  928. if (!NT_SUCCESS(Status)) {
  929. goto ExitHandler2;
  930. }
  931. //
  932. // Set the "SaferFlags" attribute in the registry (and in our cache).
  933. //
  934. #ifdef SAFER_SAFERFLAGS_ONLY_EXES
  935. dwSaferFlags = (pIdentChanges->dwSaferFlags &
  936. ~SAFER_SAFERFLAGS_ONLY_EXES);
  937. #else
  938. dwSaferFlags = pIdentChanges->dwSaferFlags;
  939. #endif
  940. Status = NtSetValueKey(
  941. hKeyIdentity,
  942. (PUNICODE_STRING) &UnicodeSaferFlags,
  943. 0, REG_DWORD, (LPBYTE) &dwSaferFlags, sizeof(DWORD));
  944. if (!NT_SUCCESS(Status)) {
  945. goto ExitHandler2;
  946. }
  947. pIdentRecord->ImageNameInfo.dwSaferFlags = dwSaferFlags;
  948. //
  949. // Set the "ZoneId" attribute in the registry (and our cache).
  950. //
  951. Status = NtSetValueKey(
  952. hKeyIdentity,
  953. (PUNICODE_STRING) &UnicodeItemData,
  954. 0, REG_DWORD, (LPBYTE) &pIdentChanges->UrlZoneId,
  955. sizeof(DWORD));
  956. if (!NT_SUCCESS(Status)) {
  957. goto ExitHandler2;
  958. }
  959. pIdentRecord->ImageZone.UrlZoneId = pIdentChanges->UrlZoneId;
  960. Status = STATUS_SUCCESS;
  961. ExitHandler2:
  962. NtClose(hKeyIdentity);
  963. ExitHandler:
  964. return Status;
  965. }
  966. NTSTATUS NTAPI
  967. SaferpSetExistingSingleIdentification(
  968. IN OUT PAUTHZIDENTSTABLERECORD pIdentRecord,
  969. IN PSAFER_IDENTIFICATION_HEADER pCommon
  970. )
  971. /*++
  972. Routine Description:
  973. Arguments:
  974. Return Value:
  975. --*/
  976. {
  977. NTSTATUS Status;
  978. //
  979. // Verify our arguments. These things should have been ensured
  980. // by our caller already, so we only assert them here.
  981. //
  982. ASSERT(ARGUMENT_PRESENT(pIdentRecord) &&
  983. ARGUMENT_PRESENT(pCommon) &&
  984. pCommon->cbStructSize >= sizeof(SAFER_IDENTIFICATION_HEADER) &&
  985. IsEqualGUID(&pCommon->IdentificationGuid, &pIdentRecord->IdentGuid) );
  986. //
  987. // Perform the appropriate action depending on the identification
  988. // data type, including verifying that the structure size matches
  989. // the size that we are expecting.
  990. //
  991. switch (pCommon->dwIdentificationType)
  992. {
  993. case SaferIdentityTypeImageName:
  994. Status = SaferpSetSingleIdentificationPath(
  995. FALSE, pIdentRecord,
  996. (PSAFER_PATHNAME_IDENTIFICATION) pCommon, TRUE);
  997. break;
  998. // --------------------
  999. case SaferIdentityTypeImageHash:
  1000. if (pCommon->cbStructSize ==
  1001. sizeof(SAFER_HASH_IDENTIFICATION)) {
  1002. // Request to change and a Unicode structure was given.
  1003. Status = SaferpSetSingleIdentificationHash(
  1004. FALSE, pIdentRecord,
  1005. (PSAFER_HASH_IDENTIFICATION) pCommon);
  1006. } else {
  1007. Status = STATUS_INFO_LENGTH_MISMATCH;
  1008. }
  1009. break;
  1010. // --------------------
  1011. case SaferIdentityTypeUrlZone:
  1012. if (pCommon->cbStructSize ==
  1013. sizeof(SAFER_URLZONE_IDENTIFICATION)) {
  1014. Status = SaferpSetSingleIdentificationZone(
  1015. FALSE, pIdentRecord,
  1016. (PSAFER_URLZONE_IDENTIFICATION) pCommon);
  1017. } else {
  1018. Status = STATUS_INFO_LENGTH_MISMATCH;
  1019. }
  1020. break;
  1021. // --------------------
  1022. default:
  1023. Status = STATUS_INVALID_INFO_CLASS;
  1024. }
  1025. return Status;
  1026. }
  1027. NTSTATUS NTAPI
  1028. SaferpCreateNewSingleIdentification(
  1029. IN DWORD dwScopeId,
  1030. IN PAUTHZLEVELTABLERECORD pLevelRecord,
  1031. IN PSAFER_IDENTIFICATION_HEADER pCommon
  1032. )
  1033. /*++
  1034. Routine Description:
  1035. Arguments:
  1036. Return Value:
  1037. --*/
  1038. {
  1039. NTSTATUS Status;
  1040. AUTHZIDENTSTABLERECORD NewIdentRecord;
  1041. PAUTHZIDENTSTABLERECORD pIdentRecord;
  1042. //
  1043. // Verify our arguments. These things should have been ensured
  1044. // by our caller already, so we only assert them here.
  1045. //
  1046. ASSERT(ARGUMENT_PRESENT(pLevelRecord) &&
  1047. ARGUMENT_PRESENT(pCommon) &&
  1048. pCommon->cbStructSize >= sizeof(SAFER_IDENTIFICATION_HEADER) &&
  1049. !CodeAuthzIdentsLookupByGuid(&g_CodeIdentitiesTable,
  1050. &pCommon->IdentificationGuid) );
  1051. if (g_hKeyCustomRoot != NULL) {
  1052. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  1053. Status = STATUS_INVALID_PARAMETER_MIX;
  1054. goto ExitHandler;
  1055. }
  1056. } else {
  1057. if (dwScopeId != SAFER_SCOPEID_MACHINE &&
  1058. dwScopeId != SAFER_SCOPEID_USER) {
  1059. Status = STATUS_INVALID_PARAMETER_MIX;
  1060. goto ExitHandler;
  1061. }
  1062. if (dwScopeId == SAFER_SCOPEID_USER && !g_bHonorScopeUser) {
  1063. Status = STATUS_INVALID_PARAMETER_MIX;
  1064. goto ExitHandler;
  1065. }
  1066. }
  1067. //
  1068. // Prepare a new Code Identity structure since we will likely
  1069. // need to insert a new record for the entry that will be created.
  1070. //
  1071. RtlZeroMemory(&NewIdentRecord, sizeof(AUTHZIDENTSTABLERECORD));
  1072. NewIdentRecord.dwIdentityType = pCommon->dwIdentificationType;
  1073. NewIdentRecord.dwLevelId = pLevelRecord->dwLevelId;
  1074. NewIdentRecord.dwScopeId = dwScopeId;
  1075. RtlCopyMemory(&NewIdentRecord.IdentGuid,
  1076. &pCommon->IdentificationGuid,
  1077. sizeof(GUID));
  1078. if (IsZeroGUID(&NewIdentRecord.IdentGuid)) {
  1079. Status = STATUS_INVALID_PARAMETER;
  1080. goto ExitHandler;
  1081. }
  1082. //
  1083. // Perform the appropriate action depending on the identification
  1084. // data type, including verifying that the structure size matches
  1085. // the size that we are expecting.
  1086. //
  1087. switch (pCommon->dwIdentificationType)
  1088. {
  1089. // --------------------
  1090. case SaferIdentityTypeImageName:
  1091. RtlInsertElementGenericTable(
  1092. &g_CodeIdentitiesTable,
  1093. (PVOID) &NewIdentRecord,
  1094. sizeof(AUTHZIDENTSTABLERECORD),
  1095. NULL);
  1096. pIdentRecord = CodeAuthzIdentsLookupByGuid(
  1097. &g_CodeIdentitiesTable,
  1098. &pCommon->IdentificationGuid);
  1099. if (!pIdentRecord) {
  1100. Status = STATUS_UNSUCCESSFUL;
  1101. break;
  1102. }
  1103. Status = SaferpSetSingleIdentificationPath(
  1104. TRUE, pIdentRecord,
  1105. (PSAFER_PATHNAME_IDENTIFICATION) pCommon, TRUE);
  1106. if (!NT_SUCCESS(Status)) {
  1107. RtlDeleteElementGenericTable(
  1108. &g_CodeIdentitiesTable,
  1109. (PVOID) &NewIdentRecord);
  1110. }
  1111. break;
  1112. // --------------------
  1113. case SaferIdentityTypeImageHash:
  1114. if (pCommon->cbStructSize ==
  1115. sizeof(SAFER_HASH_IDENTIFICATION)) {
  1116. RtlInsertElementGenericTable(
  1117. &g_CodeIdentitiesTable,
  1118. (PVOID) &NewIdentRecord,
  1119. sizeof(AUTHZIDENTSTABLERECORD),
  1120. NULL);
  1121. pIdentRecord = CodeAuthzIdentsLookupByGuid(
  1122. &g_CodeIdentitiesTable,
  1123. &pCommon->IdentificationGuid);
  1124. if (!pIdentRecord) {
  1125. Status = STATUS_UNSUCCESSFUL;
  1126. break;
  1127. }
  1128. Status = SaferpSetSingleIdentificationHash(
  1129. TRUE, pIdentRecord,
  1130. (PSAFER_HASH_IDENTIFICATION) pCommon);
  1131. if (!NT_SUCCESS(Status)) {
  1132. RtlDeleteElementGenericTable(
  1133. &g_CodeIdentitiesTable,
  1134. (PVOID) &NewIdentRecord);
  1135. }
  1136. } else {
  1137. Status = STATUS_INFO_LENGTH_MISMATCH;
  1138. }
  1139. break;
  1140. // --------------------
  1141. case SaferIdentityTypeUrlZone:
  1142. if (pCommon->cbStructSize ==
  1143. sizeof(SAFER_URLZONE_IDENTIFICATION)) {
  1144. RtlInsertElementGenericTable(
  1145. &g_CodeIdentitiesTable,
  1146. (PVOID) &NewIdentRecord,
  1147. sizeof(AUTHZIDENTSTABLERECORD),
  1148. NULL);
  1149. pIdentRecord = CodeAuthzIdentsLookupByGuid(
  1150. &g_CodeIdentitiesTable,
  1151. &pCommon->IdentificationGuid);
  1152. if (!pIdentRecord) {
  1153. Status = STATUS_UNSUCCESSFUL;
  1154. break;
  1155. }
  1156. Status = SaferpSetSingleIdentificationZone(
  1157. TRUE, pIdentRecord,
  1158. (PSAFER_URLZONE_IDENTIFICATION) pCommon);
  1159. if (!NT_SUCCESS(Status)) {
  1160. RtlDeleteElementGenericTable(
  1161. &g_CodeIdentitiesTable,
  1162. (PVOID) &NewIdentRecord);
  1163. }
  1164. } else {
  1165. Status = STATUS_INFO_LENGTH_MISMATCH;
  1166. }
  1167. break;
  1168. // --------------------
  1169. default:
  1170. Status = STATUS_INVALID_INFO_CLASS;
  1171. break;
  1172. }
  1173. ExitHandler:
  1174. return Status;
  1175. }
  1176. NTSTATUS NTAPI
  1177. CodeAuthzpSetAuthzLevelInfo(
  1178. IN SAFER_LEVEL_HANDLE LevelHandle,
  1179. IN SAFER_OBJECT_INFO_CLASS dwInfoType,
  1180. IN LPVOID lpQueryBuffer,
  1181. IN DWORD dwInBufferSize
  1182. )
  1183. /*++
  1184. Routine Description:
  1185. Allows the user to modify various pieces of information about a
  1186. given WinSafer Level.
  1187. Arguments:
  1188. LevelHandle - the handle to the authorization object to evaluate.
  1189. dwInfoType - specifies the type of information being modified.
  1190. lpQueryBuffer - pointer to a user-supplied memory buffer that
  1191. contains the new data for the item being modified.
  1192. dwInBufferSize - specifies the size of the user's memory block.
  1193. For string arguments, this size includes the terminating null.
  1194. Return Value:
  1195. Returns STATUS_SUCCESS on success.
  1196. --*/
  1197. {
  1198. NTSTATUS Status;
  1199. PAUTHZLEVELHANDLESTRUCT pLevelStruct;
  1200. PAUTHZLEVELTABLERECORD pLevelRecord;
  1201. DWORD dwHandleScopeId;
  1202. BOOLEAN bNeedLevelRegKey;
  1203. UNICODE_STRING ValueName, UnicodeRegistrySuffix;
  1204. HANDLE hRegLevelBase;
  1205. //
  1206. // Obtain a pointer to the authorization object structure
  1207. //
  1208. Status = CodeAuthzHandleToLevelStruct(LevelHandle, &pLevelStruct);
  1209. if (!NT_SUCCESS(Status)) {
  1210. goto ExitHandler;
  1211. }
  1212. ASSERT(pLevelStruct != NULL);
  1213. pLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  1214. &g_CodeLevelObjTable, pLevelStruct->dwLevelId);
  1215. if (!pLevelRecord) {
  1216. Status = STATUS_INVALID_HANDLE;
  1217. goto ExitHandler;
  1218. }
  1219. dwHandleScopeId = pLevelStruct->dwScopeId;
  1220. //
  1221. // Determine if we need to open a registry handle to the Level key.
  1222. //
  1223. bNeedLevelRegKey = FALSE;
  1224. switch (dwInfoType)
  1225. {
  1226. case SaferObjectLevelId: // DWORD
  1227. case SaferObjectScopeId: // DWORD
  1228. case SaferObjectBuiltin: // DWORD boolean
  1229. // These information classes cannot be altered with this API.
  1230. Status = STATUS_INVALID_INFO_CLASS;
  1231. goto ExitHandler;
  1232. case SaferObjectFriendlyName: // LPCTSTR
  1233. case SaferObjectDescription: // LPCTSTR
  1234. if (pLevelRecord->Builtin) {
  1235. // Don't allow built-in Levels to be modified at all.
  1236. Status = STATUS_ACCESS_DENIED;
  1237. goto ExitHandler;
  1238. }
  1239. // All of these classes need to access the Level key.
  1240. bNeedLevelRegKey = TRUE;
  1241. break;
  1242. #ifdef ALLOW_FULL_WINSAFER
  1243. case SaferObjectDisallowed: // DWORD boolean
  1244. case SaferObjectDisableMaxPrivilege: // DWORD boolean
  1245. case SaferObjectInvertDeletedPrivileges: // DWORD boolean
  1246. case SaferObjectDefaultOwner: // TOKEN_OWNER
  1247. case SaferObjectDeletedPrivileges: // TOKEN_PRIVILEGES
  1248. case SaferObjectSidsToDisable: // TOKEN_GROUPS
  1249. case SaferObjectRestrictedSidsInverted: // TOKEN_GROUPS
  1250. case SaferObjectRestrictedSidsAdded: // TOKEN_GROUPS
  1251. if (pLevelRecord->Builtin) {
  1252. // Don't allow built-in Levels to be modified at all.
  1253. Status = STATUS_ACCESS_DENIED;
  1254. goto ExitHandler;
  1255. }
  1256. // All of these classes need to access the Level key.
  1257. bNeedLevelRegKey = TRUE;
  1258. break;
  1259. #endif
  1260. case SaferObjectAllIdentificationGuids:
  1261. Status = STATUS_INVALID_INFO_CLASS;
  1262. goto ExitHandler;
  1263. case SaferObjectSingleIdentification:
  1264. // These only modify Code Identity keys.
  1265. break;
  1266. default:
  1267. Status = STATUS_INVALID_INFO_CLASS;
  1268. goto ExitHandler;
  1269. }
  1270. //
  1271. // Open the registry handle to where this Level is stored.
  1272. //
  1273. if (bNeedLevelRegKey) {
  1274. WCHAR szRegistrySuffix[MAX_PATH];
  1275. RtlInitEmptyUnicodeString(
  1276. &UnicodeRegistrySuffix,
  1277. szRegistrySuffix,
  1278. sizeof(szRegistrySuffix));
  1279. Status = CodeAuthzpFormatLevelKeyPath(
  1280. pLevelRecord->dwLevelId,
  1281. &UnicodeRegistrySuffix);
  1282. if (!NT_SUCCESS(Status)) {
  1283. goto ExitHandler;
  1284. }
  1285. Status = CodeAuthzpOpenPolicyRootKey(
  1286. g_hKeyCustomRoot != NULL ?
  1287. SAFER_SCOPEID_REGISTRY : SAFER_SCOPEID_MACHINE,
  1288. g_hKeyCustomRoot, szRegistrySuffix,
  1289. KEY_WRITE, TRUE, &hRegLevelBase);
  1290. if (!NT_SUCCESS(Status)) {
  1291. goto ExitHandler;
  1292. }
  1293. } else {
  1294. hRegLevelBase = NULL;
  1295. }
  1296. //
  1297. // Otherwise perform the actual "Set" operation.
  1298. //
  1299. switch (dwInfoType)
  1300. {
  1301. case SaferObjectFriendlyName: // LPCTSTR
  1302. ASSERT(hRegLevelBase != NULL);
  1303. RtlInitUnicodeString(&ValueName,
  1304. SAFER_OBJFRIENDLYNAME_REGVALUEW);
  1305. Status = NtSetValueKey(hRegLevelBase,
  1306. &ValueName, 0, REG_SZ,
  1307. (LPBYTE) lpQueryBuffer, dwInBufferSize);
  1308. if (NT_SUCCESS(Status)) {
  1309. if (pLevelRecord->UnicodeFriendlyName.Buffer != NULL) {
  1310. RtlFreeUnicodeString(&pLevelRecord->UnicodeFriendlyName);
  1311. }
  1312. Status = RtlCreateUnicodeString(
  1313. &pLevelRecord->UnicodeFriendlyName,
  1314. (LPWSTR) lpQueryBuffer);
  1315. if (!NT_SUCCESS(Status)) {
  1316. pLevelRecord->UnicodeFriendlyName.Buffer = NULL;
  1317. }
  1318. }
  1319. goto ExitHandler2;
  1320. case SaferObjectDescription: // LPCTSTR
  1321. ASSERT(hRegLevelBase != NULL);
  1322. RtlInitUnicodeString(&ValueName,
  1323. SAFER_OBJDESCRIPTION_REGVALUEW);
  1324. Status = NtSetValueKey(hRegLevelBase,
  1325. &ValueName, 0, REG_SZ,
  1326. (LPBYTE) lpQueryBuffer, dwInBufferSize);
  1327. if (NT_SUCCESS(Status)) {
  1328. if (pLevelRecord->UnicodeDescription.Buffer != NULL) {
  1329. RtlFreeUnicodeString(&pLevelRecord->UnicodeDescription);
  1330. }
  1331. Status = RtlCreateUnicodeString(
  1332. &pLevelRecord->UnicodeDescription,
  1333. (LPWSTR) lpQueryBuffer);
  1334. if (!NT_SUCCESS(Status)) {
  1335. pLevelRecord->UnicodeDescription.Buffer = NULL;
  1336. }
  1337. }
  1338. goto ExitHandler2;
  1339. #ifdef ALLOW_FULL_WINSAFER
  1340. case SaferObjectDisallowed: // DWORD boolean
  1341. ASSERT(hRegLevelBase != NULL);
  1342. if (!ARGUMENT_PRESENT(lpQueryBuffer) ||
  1343. dwInBufferSize != sizeof(DWORD)) {
  1344. Status = STATUS_INVALID_PARAMETER;
  1345. goto ExitHandler2;
  1346. }
  1347. RtlInitUnicodeString(&ValueName, SAFER_OBJDISALLOW_REGVALUE);
  1348. Status = NtSetValueKey(hRegLevelBase,
  1349. &ValueName, 0, REG_DWORD,
  1350. (LPBYTE) lpQueryBuffer, dwInBufferSize);
  1351. if (NT_SUCCESS(Status)) {
  1352. goto ExitHandler2;
  1353. } else {
  1354. pLevelRecord->DisallowExecution =
  1355. ( *((LPDWORD) lpQueryBuffer) != 0 ? TRUE : FALSE );
  1356. }
  1357. //BLACKCOMB TODO: update cached pLevelRecord on success
  1358. break;
  1359. case SaferObjectDisableMaxPrivilege: // DWORD boolean
  1360. ASSERT(hRegLevelBase != NULL);
  1361. // Make sure the argument is the correct size.
  1362. if (!ARGUMENT_PRESENT(lpQueryBuffer) ||
  1363. dwInBufferSize != sizeof(DWORD)) {
  1364. Status = STATUS_INVALID_PARAMETER;
  1365. goto ExitHandler2;
  1366. }
  1367. // Actually write the value to the correct place.
  1368. Status = SaferpSetRegistryHelper(
  1369. hRegLevelBase,
  1370. L"Restrictions",
  1371. L"PrivsToRemove",
  1372. L"DisableMaxPrivilege",
  1373. REG_DWORD,
  1374. lpQueryBuffer,
  1375. dwInBufferSize);
  1376. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1377. //BLACKCOMB TODO: update cached pLevelRecord on success
  1378. break;
  1379. case SaferObjectInvertDeletedPrivileges: // DWORD boolean
  1380. ASSERT(hRegLevelBase != NULL);
  1381. // Make sure the argument is the correct size.
  1382. if (!ARGUMENT_PRESENT(lpQueryBuffer) ||
  1383. dwInBufferSize != sizeof(DWORD)) {
  1384. Status = STATUS_INVALID_PARAMETER;
  1385. goto ExitHandler2;
  1386. }
  1387. // Actually write the value to the correct place.
  1388. Status = SaferpSetRegistryHelper(
  1389. hRegLevelBase,
  1390. L"Restrictions",
  1391. L"PrivsToRemove",
  1392. L"InvertPrivs",
  1393. REG_DWORD,
  1394. lpQueryBuffer,
  1395. dwInBufferSize);
  1396. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1397. //BLACKCOMB TODO: update cached pLevelRecord on success
  1398. break;
  1399. case SaferObjectDefaultOwner: // TOKEN_OWNER
  1400. {
  1401. BOOLEAN AllocatedStringSid = FALSE;
  1402. UNICODE_STRING UnicodeStringSid;
  1403. PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) lpQueryBuffer;
  1404. ASSERT(hRegLevelBase != NULL);
  1405. if (pTokenOwner->Owner == NULL) {
  1406. RtlInitUnicodeString(&UnicodeStringSid, L"");
  1407. }
  1408. else {
  1409. Status = RtlConvertSidToUnicodeString( &UnicodeStringSid,
  1410. pTokenOwner->Owner, TRUE );
  1411. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1412. AllocatedStringSid = TRUE;
  1413. }
  1414. Status = SaferpSetRegistryHelper(
  1415. hRegLevelBase,
  1416. L"Restrictions",
  1417. NULL,
  1418. L"DefaultOwner",
  1419. REG_SZ,
  1420. lpQueryBuffer,
  1421. dwInBufferSize);
  1422. if (AllocatedStringSid)
  1423. RtlFreeUnicodeString(&UnicodeStringSid);
  1424. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1425. //BLACKCOMB TODO: update cached pLevelRecord on success
  1426. break;
  1427. }
  1428. case SaferObjectDeletedPrivileges: // TOKEN_PRIVILEGES
  1429. {
  1430. HKEY hKeyPrivsToRemove;
  1431. UNICODE_STRING ValueName;
  1432. PTOKEN_PRIVILEGES pTokenPrivs =
  1433. (PTOKEN_PRIVILEGES) lpQueryBuffer;
  1434. // Open a handle to the correct subkey.
  1435. ASSERT(hRegLevelBase != NULL);
  1436. Status = SaferpCreateSecondLevelKey(
  1437. hRegLevelBase,
  1438. L"Restrictions",
  1439. L"PrivsToRemove",
  1440. &hKeyPrivsToRemove);
  1441. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1442. // Clear out all old values under the subkey.
  1443. Status = SaferpClearRegistryListHelper(
  1444. hKeyPrivsToRemove,
  1445. L"Count",
  1446. L"Priv");
  1447. if (!NT_SUCCESS(Status)) {
  1448. // Bad luck! Possibly left in incomplete state!
  1449. NtClose(hKeyPrivsToRemove);
  1450. goto ExitHandler2;
  1451. }
  1452. // Now add all of the new ones we're supposed to add.
  1453. RtlInitUnicodeString(&ValueName, L"Count");
  1454. Status = NtSetValueKey(hKeyPrivsToRemove,
  1455. &ValueName, 0, REG_DWORD,
  1456. (LPBYTE) pTokenPrivs->PrivilegeCount, sizeof(DWORD));
  1457. if (!NT_SUCCESS(Status)) {
  1458. // Bad luck! Possibly left in incomplete state!
  1459. NtClose(hKeyPrivsToRemove);
  1460. goto ExitHandler2;
  1461. }
  1462. for (Index = 0; Index < pTokenPrivs->PrivilegeCount; Index++)
  1463. {
  1464. WCHAR ValueNameBuffer[20];
  1465. WCHAR PrivilegeNameBuffer[64];
  1466. DWORD dwPrivilegeNameLen;
  1467. wsprintfW(ValueNameBuffer, L"Priv%d", Index);
  1468. RtlInitUnicodeString(&ValueName, ValueNameBuffer);
  1469. dwPrivilegeNameLen = sizeof(PrivilegeNameBuffer) / sizeof(WCHAR);
  1470. if (!LookupPrivilegeNameW(NULL,
  1471. &pTokenPrivs->Privileges[Index].Luid,
  1472. PrivilegeNameBuffer,
  1473. &dwPrivilegeNameLen))
  1474. {
  1475. // Bad luck! Possibly left in incomplete state!
  1476. Status = STATUS_NO_SUCH_PRIVILEGE;
  1477. NtClose(hKeyPrivsToRemove);
  1478. goto ExitHandler2;
  1479. }
  1480. Status = NtSetValueKey(hKeyPrivsToRemove,
  1481. &ValueName, 0, REG_SZ,
  1482. (LPBYTE) PrivilegeNameBuffer,
  1483. (wcslen(PrivilegeNameBuffer) + 1) * sizeof(WCHAR));
  1484. if (!NT_SUCCESS(Status)) {
  1485. // Bad luck! Possibly left in incomplete state!
  1486. NtClose(hKeyPrivsToRemove);
  1487. goto ExitHandler2;
  1488. }
  1489. }
  1490. NtClose(hKeyPrivsToRemove);
  1491. //BLACKCOMB TODO: update cached pLevelRecord on success
  1492. break;
  1493. }
  1494. case SaferObjectSidsToDisable: // TOKEN_GROUPS
  1495. //BLACKCOMB TODO: allow wildcard sids to be specified.
  1496. ASSERT(hRegLevelBase != NULL);
  1497. Status = SaferpSetListOfSids(
  1498. hRegLevelBase,
  1499. L"Restrictions",
  1500. L"SidsToDisable",
  1501. L"Count",
  1502. L"Group",
  1503. (PTOKEN_GROUPS) lpQueryBuffer);
  1504. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1505. //BLACKCOMB TODO: update cached pLevelRecord on success
  1506. break;
  1507. case SaferObjectRestrictedSidsInverted: // TOKEN_GROUPS
  1508. //BLACKCOMB TODO: allow wildcard sids to be specified.
  1509. ASSERT(hRegLevelBase != NULL);
  1510. Status = SaferpSetListOfSids(
  1511. hRegLevelBase,
  1512. L"Restrictions",
  1513. L"RestrictingSidsInverted",
  1514. L"Count",
  1515. L"Group",
  1516. (PTOKEN_GROUPS) lpQueryBuffer);
  1517. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1518. //BLACKCOMB TODO: update cached pLevelRecord on success
  1519. break;
  1520. case SaferObjectRestrictedSidsAdded: // TOKEN_GROUPS
  1521. ASSERT(hRegLevelBase != NULL);
  1522. Status = SaferpSetListOfSids(
  1523. hRegLevelBase,
  1524. L"Restrictions",
  1525. L"RestrictingSidsAdded",
  1526. L"Count",
  1527. L"Group",
  1528. (PTOKEN_GROUPS) lpQueryBuffer);
  1529. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1530. //BLACKCOMB TODO: update cached pLevelRecord on success
  1531. break;
  1532. #endif
  1533. case SaferObjectSingleIdentification:
  1534. {
  1535. PAUTHZIDENTSTABLERECORD pIdentRecord;
  1536. PSAFER_IDENTIFICATION_HEADER pCommon =
  1537. (PSAFER_IDENTIFICATION_HEADER) lpQueryBuffer;
  1538. if (!ARGUMENT_PRESENT(pCommon)) {
  1539. Status = STATUS_ACCESS_VIOLATION;
  1540. goto ExitHandler2;
  1541. }
  1542. if (dwInBufferSize < sizeof(SAFER_IDENTIFICATION_HEADER) ||
  1543. dwInBufferSize < pCommon->cbStructSize) {
  1544. Status = STATUS_INFO_LENGTH_MISMATCH;
  1545. goto ExitHandler2;
  1546. }
  1547. pIdentRecord = CodeAuthzIdentsLookupByGuid(
  1548. &g_CodeIdentitiesTable,
  1549. &pCommon->IdentificationGuid);
  1550. if (!pIdentRecord)
  1551. {
  1552. // Request to create a new Code Identifier.
  1553. Status = SaferpCreateNewSingleIdentification(
  1554. dwHandleScopeId, pLevelRecord, pCommon);
  1555. }
  1556. else if (pCommon->dwIdentificationType == 0)
  1557. {
  1558. // Request to delete an existing Code Identifier.
  1559. if (pIdentRecord->dwLevelId != pLevelRecord->dwLevelId ||
  1560. pIdentRecord->dwScopeId != dwHandleScopeId) {
  1561. Status = STATUS_NOT_FOUND;
  1562. } else {
  1563. Status = SaferpDeleteSingleIdentificationGuid(
  1564. pLevelRecord, pIdentRecord);
  1565. }
  1566. }
  1567. else
  1568. {
  1569. // Request to modify an existing Code Identifier.
  1570. if (pIdentRecord->dwLevelId != pLevelRecord->dwLevelId ||
  1571. pIdentRecord->dwScopeId != dwHandleScopeId)
  1572. {
  1573. // This was likely a request to create a new Code
  1574. // Identifier, but with a GUID that already exists.
  1575. Status = STATUS_OBJECT_NAME_COLLISION;
  1576. } else {
  1577. Status = SaferpSetExistingSingleIdentification(
  1578. pIdentRecord, pCommon);
  1579. }
  1580. }
  1581. goto ExitHandler2;
  1582. }
  1583. default:
  1584. ASSERTMSG("invalid info class unhandled earlier", 0);
  1585. Status = STATUS_INVALID_INFO_CLASS;
  1586. goto ExitHandler2;
  1587. }
  1588. Status = STATUS_SUCCESS;
  1589. //
  1590. // Cleanup and epilogue code.
  1591. //
  1592. ExitHandler2:
  1593. if (hRegLevelBase != NULL) {
  1594. NtClose(hRegLevelBase);
  1595. }
  1596. ExitHandler:
  1597. return Status;
  1598. }
  1599. BOOL WINAPI
  1600. SaferSetLevelInformation(
  1601. IN SAFER_LEVEL_HANDLE LevelHandle,
  1602. IN SAFER_OBJECT_INFO_CLASS dwInfoType,
  1603. IN LPVOID lpQueryBuffer,
  1604. IN DWORD dwInBufferSize
  1605. )
  1606. /*++
  1607. Routine Description:
  1608. Allows the user to modify various pieces of information about a
  1609. given WinSafer Level.
  1610. Arguments:
  1611. LevelHandle - the handle to the WinSafer Level to evaluate.
  1612. dwInfoType - specifies the type of information being modified.
  1613. lpQueryBuffer - pointer to a user-supplied memory buffer that
  1614. contains the new data for the item being modified.
  1615. dwInBufferSize - specifies the size of the user's memory block.
  1616. For string arguments, this size includes the terminating null.
  1617. Return Value:
  1618. Returns FALSE on error, otherwise success.
  1619. --*/
  1620. {
  1621. NTSTATUS Status;
  1622. if (!g_bInitializedFirstTime) {
  1623. Status = STATUS_UNSUCCESSFUL;
  1624. goto ExitHandler;
  1625. }
  1626. RtlEnterCriticalSection(&g_TableCritSec);
  1627. Status = CodeAuthzpSetAuthzLevelInfo(
  1628. LevelHandle, dwInfoType,
  1629. lpQueryBuffer, dwInBufferSize);
  1630. RtlLeaveCriticalSection(&g_TableCritSec);
  1631. if (NT_SUCCESS(Status))
  1632. return TRUE;
  1633. ExitHandler:
  1634. if (Status == STATUS_OBJECT_NAME_COLLISION) {
  1635. SetLastError(ERROR_OBJECT_ALREADY_EXISTS);
  1636. } else {
  1637. BaseSetLastNTError(Status);
  1638. }
  1639. return FALSE;
  1640. }