Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1949 lines
62 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 == 0) {
  529. // One of these buffers was not NULL terminated.
  530. Status = STATUS_INVALID_PARAMETER;
  531. goto ExitHandler;
  532. }
  533. //
  534. // Open a registry handle to the Code Identity.
  535. //
  536. RtlInitEmptyUnicodeString(
  537. &UnicodeTemp, szPathBuffer, sizeof(szPathBuffer));
  538. Status = CodeAuthzpFormatIdentityKeyPath(
  539. pIdentRecord->dwLevelId,
  540. SAFER_PATHS_REGSUBKEY,
  541. &pIdentRecord->IdentGuid,
  542. &UnicodeTemp);
  543. if (!NT_SUCCESS(Status)) {
  544. goto ExitHandler;
  545. }
  546. Status = CodeAuthzpOpenPolicyRootKey(
  547. pIdentRecord->dwScopeId,
  548. g_hKeyCustomRoot,
  549. szPathBuffer,
  550. KEY_READ | KEY_WRITE,
  551. bAllowCreation,
  552. &hKeyIdentity);
  553. if (!NT_SUCCESS(Status)) {
  554. goto ExitHandler;
  555. }
  556. //
  557. // Set the "Last Modified" attribute in the registry.
  558. //
  559. GetSystemTimeAsFileTime(&CurrentTime);
  560. ASSERT(sizeof(DWORD) * 2 == sizeof(FILETIME));
  561. Status = NtSetValueKey(
  562. hKeyIdentity,
  563. (PUNICODE_STRING) &UnicodeLastModified,
  564. 0, REG_QWORD, (LPBYTE) &CurrentTime,
  565. sizeof(DWORD) * 2);
  566. if (!NT_SUCCESS(Status)) {
  567. goto ExitHandler2;
  568. }
  569. //
  570. // Set the "Description" attribute in the registry.
  571. //
  572. Status = NtSetValueKey(
  573. hKeyIdentity,
  574. (PUNICODE_STRING) &UnicodeDescription,
  575. 0, REG_SZ, (LPBYTE) UnicodeNewDescription.Buffer,
  576. UnicodeNewDescription.MaximumLength);
  577. if (!NT_SUCCESS(Status)) {
  578. goto ExitHandler2;
  579. }
  580. //
  581. // Set the "SaferFlags" attribute in the registry (and in our cache).
  582. //
  583. dwSaferFlags = pIdentChanges->dwSaferFlags;
  584. Status = NtSetValueKey(
  585. hKeyIdentity,
  586. (PUNICODE_STRING) &UnicodeSaferFlags,
  587. 0, REG_DWORD, (LPBYTE) &dwSaferFlags, sizeof(DWORD));
  588. if (!NT_SUCCESS(Status)) {
  589. goto ExitHandler2;
  590. }
  591. //
  592. // Set the "image pathname" attribute in the registry (and our cache).
  593. //
  594. bExpandVars = (wcschr(pIdentChanges->ImageName, L'%') != NULL ? TRUE : FALSE);
  595. Status = NtSetValueKey(
  596. hKeyIdentity,
  597. (PUNICODE_STRING) &UnicodeItemData,
  598. 0, (bExpandVars ? REG_EXPAND_SZ : REG_SZ),
  599. (LPBYTE) UnicodeNewImagePath.Buffer,
  600. UnicodeNewImagePath.MaximumLength );
  601. if (!NT_SUCCESS(Status)) {
  602. goto ExitHandler2;
  603. }
  604. if (UpdateCache) {
  605. RtlFreeUnicodeString(&pIdentRecord->ImageNameInfo.ImagePath);
  606. Status = RtlDuplicateUnicodeString(
  607. RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
  608. &UnicodeNewImagePath,
  609. &pIdentRecord->ImageNameInfo.ImagePath);
  610. if (!NT_SUCCESS(Status)) {
  611. goto ExitHandler2;
  612. }
  613. pIdentRecord->ImageNameInfo.bExpandVars = bExpandVars;
  614. pIdentRecord->ImageNameInfo.dwSaferFlags = dwSaferFlags;
  615. }
  616. Status = STATUS_SUCCESS;
  617. ExitHandler2:
  618. NtClose(hKeyIdentity);
  619. ExitHandler:
  620. return Status;
  621. }
  622. NTSTATUS NTAPI
  623. SaferpSetSingleIdentificationHash(
  624. IN BOOLEAN bAllowCreation,
  625. IN OUT PAUTHZIDENTSTABLERECORD pIdentRecord,
  626. IN PSAFER_HASH_IDENTIFICATION pIdentChanges
  627. )
  628. /*++
  629. Routine Description:
  630. Updates the registry and the local Identification table cache
  631. with new properties about a hash Code Identifier.
  632. Arguments:
  633. bAllowCreation - indicates if the modification of this record has
  634. the potential of being the initial creation of this record.
  635. If this is false and the corresponding key location within the
  636. registry does not already exist, then this function call
  637. will fail.
  638. pIdentRecord - the cached code identity record that should be
  639. updated with new values. This argument must always be supplied,
  640. even if the Code Identity is being created for the first time
  641. (in which case, this argument should be the new record that
  642. the caller has just inserted into the cached idents table).
  643. pIdentChanges - the input structure containing the new modifications
  644. that should be made to the specified Code Identity.
  645. Return Value:
  646. Return STATUS_SUCCESS on success completion, or another error
  647. status code indicating the nature of the failure.
  648. --*/
  649. {
  650. const static UNICODE_STRING UnicodeLastModified =
  651. RTL_CONSTANT_STRING(SAFER_IDS_LASTMODIFIED_REGVALUE);
  652. const static UNICODE_STRING UnicodeDescription =
  653. RTL_CONSTANT_STRING(SAFER_IDS_DESCRIPTION_REGVALUE);
  654. const static UNICODE_STRING UnicodeSaferFlags =
  655. RTL_CONSTANT_STRING(SAFER_IDS_SAFERFLAGS_REGVALUE);
  656. const static UNICODE_STRING UnicodeItemData =
  657. RTL_CONSTANT_STRING(SAFER_IDS_ITEMDATA_REGVALUE);
  658. const static UNICODE_STRING UnicodeFriendlyName =
  659. RTL_CONSTANT_STRING(SAFER_IDS_FRIENDLYNAME_REGVALUE);
  660. const static UNICODE_STRING UnicodeItemSize =
  661. RTL_CONSTANT_STRING(SAFER_IDS_ITEMSIZE_REGVALUE);
  662. const static UNICODE_STRING UnicodeHashAlgorithm =
  663. RTL_CONSTANT_STRING(SAFER_IDS_HASHALG_REGVALUE);
  664. NTSTATUS Status;
  665. HANDLE hKeyIdentity = NULL;
  666. UNICODE_STRING UnicodeTemp;
  667. UNICODE_STRING UnicodeNewFriendlyName;
  668. UNICODE_STRING UnicodeNewDescription;
  669. WCHAR szPathBuffer[MAX_PATH];
  670. DWORD dwSaferFlags;
  671. FILETIME CurrentTime;
  672. //
  673. // Verify our arguments. These things should have been ensured
  674. // by our caller already, so we only assert them here.
  675. //
  676. ASSERT(ARGUMENT_PRESENT(pIdentRecord) &&
  677. ARGUMENT_PRESENT(pIdentChanges) &&
  678. pIdentChanges->header.dwIdentificationType == SaferIdentityTypeImageHash &&
  679. pIdentChanges->header.cbStructSize == sizeof(SAFER_HASH_IDENTIFICATION) &&
  680. IsEqualGUID(&pIdentChanges->header.IdentificationGuid, &pIdentRecord->IdentGuid));
  681. //
  682. // Verify that the existing type matches the new type.
  683. // Cannot change identity type once it has been created.
  684. //
  685. if (pIdentRecord->dwIdentityType != SaferIdentityTypeImageHash) {
  686. Status = STATUS_INVALID_PARAMETER;
  687. goto ExitHandler;
  688. }
  689. //
  690. // Verify that the string arguments are properly terminated.
  691. // We require that they fit entirely within the input buffer
  692. // and also have an explicit null terminator.
  693. //
  694. RtlInitUnicodeString(&UnicodeNewDescription, pIdentChanges->Description);
  695. RtlInitUnicodeString(&UnicodeNewFriendlyName, pIdentChanges->FriendlyName);
  696. if (UnicodeNewDescription.Length >=
  697. SAFER_MAX_DESCRIPTION_SIZE * sizeof(WCHAR) ||
  698. UnicodeNewFriendlyName.Length >=
  699. SAFER_MAX_FRIENDLYNAME_SIZE * sizeof(WCHAR) ||
  700. pIdentChanges->HashSize > SAFER_MAX_HASH_SIZE)
  701. {
  702. // One of these buffers was not NULL terminated or
  703. // the hash size specified was invalid.
  704. Status = STATUS_INVALID_PARAMETER;
  705. goto ExitHandler;
  706. }
  707. if ((pIdentChanges->HashAlgorithm & ALG_CLASS_ALL) != ALG_CLASS_HASH ||
  708. pIdentChanges->HashSize < 1) {
  709. // The hash algorithm method was an invalid type, or
  710. // a zero-length hash was supplied.
  711. Status = STATUS_INVALID_PARAMETER;
  712. goto ExitHandler;
  713. }
  714. //
  715. // Open a registry handle to the Code Identity.
  716. //
  717. RtlInitEmptyUnicodeString(
  718. &UnicodeTemp, szPathBuffer, sizeof(szPathBuffer));
  719. Status = CodeAuthzpFormatIdentityKeyPath(
  720. pIdentRecord->dwLevelId,
  721. SAFER_HASHMD5_REGSUBKEY,
  722. &pIdentRecord->IdentGuid,
  723. &UnicodeTemp);
  724. if (!NT_SUCCESS(Status)) {
  725. goto ExitHandler;
  726. }
  727. Status = CodeAuthzpOpenPolicyRootKey(
  728. pIdentRecord->dwScopeId,
  729. g_hKeyCustomRoot,
  730. szPathBuffer,
  731. KEY_READ | KEY_WRITE,
  732. bAllowCreation,
  733. &hKeyIdentity);
  734. if (!NT_SUCCESS(Status)) {
  735. goto ExitHandler;
  736. }
  737. //
  738. // Set the "Last Modified" attribute in the registry.
  739. //
  740. GetSystemTimeAsFileTime(&CurrentTime);
  741. ASSERT(sizeof(DWORD) * 2 == sizeof(FILETIME));
  742. Status = NtSetValueKey(
  743. hKeyIdentity,
  744. (PUNICODE_STRING) &UnicodeLastModified, 0,
  745. REG_QWORD, (LPBYTE) &CurrentTime,
  746. sizeof(DWORD) * 2);
  747. if (!NT_SUCCESS(Status)) {
  748. goto ExitHandler2;
  749. }
  750. //
  751. // Set the "Description" attribute in the registry.
  752. //
  753. Status = NtSetValueKey(
  754. hKeyIdentity,
  755. (PUNICODE_STRING) &UnicodeDescription,
  756. 0, REG_SZ, (LPBYTE) UnicodeNewDescription.Buffer,
  757. UnicodeNewDescription.MaximumLength);
  758. if (!NT_SUCCESS(Status)) {
  759. goto ExitHandler2;
  760. }
  761. //
  762. // Set the "FriendlyName" attribute in the registry.
  763. //
  764. Status = NtSetValueKey(
  765. hKeyIdentity,
  766. (PUNICODE_STRING) &UnicodeFriendlyName,
  767. 0, REG_SZ, (LPBYTE) UnicodeNewFriendlyName.Buffer,
  768. UnicodeNewFriendlyName.MaximumLength);
  769. if (!NT_SUCCESS(Status)) {
  770. goto ExitHandler2;
  771. }
  772. //
  773. // Set the "SaferFlags" attribute in the registry (and in our cache).
  774. //
  775. #ifdef SAFER_SAFERFLAGS_ONLY_EXES
  776. dwSaferFlags = (pIdentChanges->dwSaferFlags &
  777. ~SAFER_SAFERFLAGS_ONLY_EXES);
  778. #else
  779. dwSaferFlags = pIdentChanges->dwSaferFlags;
  780. #endif
  781. Status = NtSetValueKey(
  782. hKeyIdentity,
  783. (PUNICODE_STRING) &UnicodeSaferFlags,
  784. 0, REG_DWORD, (LPBYTE) &dwSaferFlags, sizeof(DWORD));
  785. if (!NT_SUCCESS(Status)) {
  786. goto ExitHandler2;
  787. }
  788. pIdentRecord->ImageNameInfo.dwSaferFlags = dwSaferFlags;
  789. //
  790. // Set the "image size" attribute in the registry (and our cache).
  791. //
  792. Status = NtSetValueKey(
  793. hKeyIdentity,
  794. (PUNICODE_STRING) &UnicodeItemSize,
  795. 0, REG_QWORD, (LPBYTE) &pIdentChanges->ImageSize.QuadPart,
  796. sizeof(DWORD) * 2);
  797. if (!NT_SUCCESS(Status)) {
  798. goto ExitHandler2;
  799. }
  800. pIdentRecord->ImageHashInfo.ImageSize.QuadPart =
  801. pIdentChanges->ImageSize.QuadPart;
  802. //
  803. // Set the "image hash" attribute in the registry (and our cache).
  804. //
  805. Status = NtSetValueKey(
  806. hKeyIdentity,
  807. (PUNICODE_STRING) &UnicodeItemData,
  808. 0, REG_BINARY, (LPBYTE) pIdentChanges->ImageHash,
  809. pIdentChanges->HashSize);
  810. if (!NT_SUCCESS(Status)) {
  811. goto ExitHandler2;
  812. }
  813. pIdentRecord->ImageHashInfo.HashSize =
  814. pIdentChanges->HashSize;
  815. RtlCopyMemory(&pIdentRecord->ImageHashInfo.ImageHash[0],
  816. &pIdentChanges->ImageHash[0],
  817. pIdentChanges->HashSize);
  818. //
  819. // Set the "hash algorithm" attribute in the registry (and our cache).
  820. //
  821. Status = NtSetValueKey(
  822. hKeyIdentity,
  823. (PUNICODE_STRING) &UnicodeHashAlgorithm,
  824. 0, REG_DWORD, (LPBYTE) &pIdentChanges->HashAlgorithm,
  825. sizeof(DWORD));
  826. if (!NT_SUCCESS(Status)) {
  827. goto ExitHandler2;
  828. }
  829. pIdentRecord->ImageHashInfo.HashAlgorithm =
  830. pIdentChanges->HashAlgorithm;
  831. Status = STATUS_SUCCESS;
  832. ExitHandler2:
  833. NtClose(hKeyIdentity);
  834. ExitHandler:
  835. return Status;
  836. }
  837. NTSTATUS NTAPI
  838. SaferpSetSingleIdentificationZone(
  839. IN BOOLEAN bAllowCreation,
  840. IN OUT PAUTHZIDENTSTABLERECORD pIdentRecord,
  841. IN PSAFER_URLZONE_IDENTIFICATION pIdentChanges
  842. )
  843. /*++
  844. Routine Description:
  845. Updates the registry and the local Identification table cache
  846. with new properties about a URL Zone Code Identifier.
  847. Arguments:
  848. bAllowCreation - indicates if the modification of this record has
  849. the potential of being the initial creation of this record.
  850. If this is false and the corresponding key location within the
  851. registry does not already exist, then this function call
  852. will fail.
  853. pIdentRecord - the cached code identity record that should be
  854. updated with new values. This argument must always be supplied,
  855. even if the Code Identity is being created for the first time
  856. (in which case, this argument should be the new record that
  857. the caller has just inserted into the cached idents table).
  858. pIdentChanges - the input structure containing the new modifications
  859. that should be made to the specified Code Identity.
  860. Return Value:
  861. Return STATUS_SUCCESS on success completion, or another error
  862. status code indicating the nature of the failure.
  863. --*/
  864. {
  865. const static UNICODE_STRING UnicodeLastModified =
  866. RTL_CONSTANT_STRING(SAFER_IDS_LASTMODIFIED_REGVALUE);
  867. const static UNICODE_STRING UnicodeSaferFlags =
  868. RTL_CONSTANT_STRING(SAFER_IDS_SAFERFLAGS_REGVALUE);
  869. const static UNICODE_STRING UnicodeItemData =
  870. RTL_CONSTANT_STRING(SAFER_IDS_ITEMDATA_REGVALUE);
  871. NTSTATUS Status;
  872. HANDLE hKeyIdentity = NULL;
  873. UNICODE_STRING UnicodeTemp;
  874. WCHAR szPathBuffer[MAX_PATH];
  875. DWORD dwSaferFlags;
  876. FILETIME CurrentTime;
  877. //
  878. // Verify our arguments. These things should have been ensured
  879. // by our caller already, so we only assert them here.
  880. //
  881. ASSERT(ARGUMENT_PRESENT(pIdentRecord) &&
  882. ARGUMENT_PRESENT(pIdentChanges) &&
  883. pIdentChanges->header.dwIdentificationType == SaferIdentityTypeUrlZone &&
  884. pIdentChanges->header.cbStructSize == sizeof(SAFER_URLZONE_IDENTIFICATION) &&
  885. IsEqualGUID(&pIdentChanges->header.IdentificationGuid, &pIdentRecord->IdentGuid));
  886. //
  887. // Verify that the existing type matches the new type.
  888. // Cannot change identity type once it has been created.
  889. //
  890. if (pIdentRecord->dwIdentityType != SaferIdentityTypeUrlZone) {
  891. Status = STATUS_INVALID_PARAMETER;
  892. goto ExitHandler;
  893. }
  894. //
  895. // Open a registry handle to the Code Identity.
  896. //
  897. RtlInitEmptyUnicodeString(
  898. &UnicodeTemp, szPathBuffer, sizeof(szPathBuffer));
  899. Status = CodeAuthzpFormatIdentityKeyPath(
  900. pIdentRecord->dwLevelId,
  901. SAFER_SOURCEURL_REGSUBKEY,
  902. &pIdentRecord->IdentGuid,
  903. &UnicodeTemp);
  904. if (!NT_SUCCESS(Status)) {
  905. goto ExitHandler;
  906. }
  907. Status = CodeAuthzpOpenPolicyRootKey(
  908. pIdentRecord->dwScopeId,
  909. g_hKeyCustomRoot,
  910. szPathBuffer,
  911. KEY_READ | KEY_WRITE,
  912. bAllowCreation,
  913. &hKeyIdentity);
  914. if (!NT_SUCCESS(Status)) {
  915. goto ExitHandler;
  916. }
  917. //
  918. // Set the "Last Modified" attribute in the registry.
  919. //
  920. GetSystemTimeAsFileTime(&CurrentTime);
  921. ASSERT(sizeof(DWORD) * 2 == sizeof(FILETIME));
  922. Status = NtSetValueKey(
  923. hKeyIdentity,
  924. (PUNICODE_STRING) &UnicodeLastModified,
  925. 0, REG_QWORD, (LPBYTE) &CurrentTime,
  926. sizeof(DWORD) * 2);
  927. if (!NT_SUCCESS(Status)) {
  928. goto ExitHandler2;
  929. }
  930. //
  931. // Set the "SaferFlags" attribute in the registry (and in our cache).
  932. //
  933. #ifdef SAFER_SAFERFLAGS_ONLY_EXES
  934. dwSaferFlags = (pIdentChanges->dwSaferFlags &
  935. ~SAFER_SAFERFLAGS_ONLY_EXES);
  936. #else
  937. dwSaferFlags = pIdentChanges->dwSaferFlags;
  938. #endif
  939. Status = NtSetValueKey(
  940. hKeyIdentity,
  941. (PUNICODE_STRING) &UnicodeSaferFlags,
  942. 0, REG_DWORD, (LPBYTE) &dwSaferFlags, sizeof(DWORD));
  943. if (!NT_SUCCESS(Status)) {
  944. goto ExitHandler2;
  945. }
  946. pIdentRecord->ImageNameInfo.dwSaferFlags = dwSaferFlags;
  947. //
  948. // Set the "ZoneId" attribute in the registry (and our cache).
  949. //
  950. Status = NtSetValueKey(
  951. hKeyIdentity,
  952. (PUNICODE_STRING) &UnicodeItemData,
  953. 0, REG_DWORD, (LPBYTE) &pIdentChanges->UrlZoneId,
  954. sizeof(DWORD));
  955. if (!NT_SUCCESS(Status)) {
  956. goto ExitHandler2;
  957. }
  958. pIdentRecord->ImageZone.UrlZoneId = pIdentChanges->UrlZoneId;
  959. Status = STATUS_SUCCESS;
  960. ExitHandler2:
  961. NtClose(hKeyIdentity);
  962. ExitHandler:
  963. return Status;
  964. }
  965. NTSTATUS NTAPI
  966. SaferpSetExistingSingleIdentification(
  967. IN OUT PAUTHZIDENTSTABLERECORD pIdentRecord,
  968. IN PSAFER_IDENTIFICATION_HEADER pCommon
  969. )
  970. /*++
  971. Routine Description:
  972. Arguments:
  973. Return Value:
  974. --*/
  975. {
  976. NTSTATUS Status;
  977. //
  978. // Verify our arguments. These things should have been ensured
  979. // by our caller already, so we only assert them here.
  980. //
  981. ASSERT(ARGUMENT_PRESENT(pIdentRecord) &&
  982. ARGUMENT_PRESENT(pCommon) &&
  983. pCommon->cbStructSize >= sizeof(SAFER_IDENTIFICATION_HEADER) &&
  984. IsEqualGUID(&pCommon->IdentificationGuid, &pIdentRecord->IdentGuid) );
  985. //
  986. // Perform the appropriate action depending on the identification
  987. // data type, including verifying that the structure size matches
  988. // the size that we are expecting.
  989. //
  990. switch (pCommon->dwIdentificationType)
  991. {
  992. case SaferIdentityTypeImageName:
  993. Status = SaferpSetSingleIdentificationPath(
  994. FALSE, pIdentRecord,
  995. (PSAFER_PATHNAME_IDENTIFICATION) pCommon, TRUE);
  996. break;
  997. // --------------------
  998. case SaferIdentityTypeImageHash:
  999. if (pCommon->cbStructSize ==
  1000. sizeof(SAFER_HASH_IDENTIFICATION)) {
  1001. // Request to change and a Unicode structure was given.
  1002. Status = SaferpSetSingleIdentificationHash(
  1003. FALSE, pIdentRecord,
  1004. (PSAFER_HASH_IDENTIFICATION) pCommon);
  1005. } else {
  1006. Status = STATUS_INFO_LENGTH_MISMATCH;
  1007. }
  1008. break;
  1009. // --------------------
  1010. case SaferIdentityTypeUrlZone:
  1011. if (pCommon->cbStructSize ==
  1012. sizeof(SAFER_URLZONE_IDENTIFICATION)) {
  1013. Status = SaferpSetSingleIdentificationZone(
  1014. FALSE, pIdentRecord,
  1015. (PSAFER_URLZONE_IDENTIFICATION) pCommon);
  1016. } else {
  1017. Status = STATUS_INFO_LENGTH_MISMATCH;
  1018. }
  1019. break;
  1020. // --------------------
  1021. default:
  1022. Status = STATUS_INVALID_INFO_CLASS;
  1023. }
  1024. return Status;
  1025. }
  1026. NTSTATUS NTAPI
  1027. SaferpCreateNewSingleIdentification(
  1028. IN DWORD dwScopeId,
  1029. IN PAUTHZLEVELTABLERECORD pLevelRecord,
  1030. IN PSAFER_IDENTIFICATION_HEADER pCommon
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. Arguments:
  1035. Return Value:
  1036. --*/
  1037. {
  1038. NTSTATUS Status;
  1039. AUTHZIDENTSTABLERECORD NewIdentRecord;
  1040. PAUTHZIDENTSTABLERECORD pIdentRecord;
  1041. //
  1042. // Verify our arguments. These things should have been ensured
  1043. // by our caller already, so we only assert them here.
  1044. //
  1045. ASSERT(ARGUMENT_PRESENT(pLevelRecord) &&
  1046. ARGUMENT_PRESENT(pCommon) &&
  1047. pCommon->cbStructSize >= sizeof(SAFER_IDENTIFICATION_HEADER) &&
  1048. !CodeAuthzIdentsLookupByGuid(&g_CodeIdentitiesTable,
  1049. &pCommon->IdentificationGuid) );
  1050. if (g_hKeyCustomRoot != NULL) {
  1051. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  1052. Status = STATUS_INVALID_PARAMETER_MIX;
  1053. goto ExitHandler;
  1054. }
  1055. } else {
  1056. if (dwScopeId != SAFER_SCOPEID_MACHINE &&
  1057. dwScopeId != SAFER_SCOPEID_USER) {
  1058. Status = STATUS_INVALID_PARAMETER_MIX;
  1059. goto ExitHandler;
  1060. }
  1061. if (dwScopeId == SAFER_SCOPEID_USER && !g_bHonorScopeUser) {
  1062. Status = STATUS_INVALID_PARAMETER_MIX;
  1063. goto ExitHandler;
  1064. }
  1065. }
  1066. //
  1067. // Prepare a new Code Identity structure since we will likely
  1068. // need to insert a new record for the entry that will be created.
  1069. //
  1070. RtlZeroMemory(&NewIdentRecord, sizeof(AUTHZIDENTSTABLERECORD));
  1071. NewIdentRecord.dwIdentityType = pCommon->dwIdentificationType;
  1072. NewIdentRecord.dwLevelId = pLevelRecord->dwLevelId;
  1073. NewIdentRecord.dwScopeId = dwScopeId;
  1074. RtlCopyMemory(&NewIdentRecord.IdentGuid,
  1075. &pCommon->IdentificationGuid,
  1076. sizeof(GUID));
  1077. if (IsZeroGUID(&NewIdentRecord.IdentGuid)) {
  1078. Status = STATUS_INVALID_PARAMETER;
  1079. goto ExitHandler;
  1080. }
  1081. //
  1082. // Perform the appropriate action depending on the identification
  1083. // data type, including verifying that the structure size matches
  1084. // the size that we are expecting.
  1085. //
  1086. switch (pCommon->dwIdentificationType)
  1087. {
  1088. // --------------------
  1089. case SaferIdentityTypeImageName:
  1090. RtlInsertElementGenericTable(
  1091. &g_CodeIdentitiesTable,
  1092. (PVOID) &NewIdentRecord,
  1093. sizeof(AUTHZIDENTSTABLERECORD),
  1094. NULL);
  1095. pIdentRecord = CodeAuthzIdentsLookupByGuid(
  1096. &g_CodeIdentitiesTable,
  1097. &pCommon->IdentificationGuid);
  1098. if (!pIdentRecord) {
  1099. Status = STATUS_UNSUCCESSFUL;
  1100. break;
  1101. }
  1102. Status = SaferpSetSingleIdentificationPath(
  1103. TRUE, pIdentRecord,
  1104. (PSAFER_PATHNAME_IDENTIFICATION) pCommon, TRUE);
  1105. if (!NT_SUCCESS(Status)) {
  1106. RtlDeleteElementGenericTable(
  1107. &g_CodeIdentitiesTable,
  1108. (PVOID) &NewIdentRecord);
  1109. }
  1110. break;
  1111. // --------------------
  1112. case SaferIdentityTypeImageHash:
  1113. if (pCommon->cbStructSize ==
  1114. sizeof(SAFER_HASH_IDENTIFICATION)) {
  1115. RtlInsertElementGenericTable(
  1116. &g_CodeIdentitiesTable,
  1117. (PVOID) &NewIdentRecord,
  1118. sizeof(AUTHZIDENTSTABLERECORD),
  1119. NULL);
  1120. pIdentRecord = CodeAuthzIdentsLookupByGuid(
  1121. &g_CodeIdentitiesTable,
  1122. &pCommon->IdentificationGuid);
  1123. if (!pIdentRecord) {
  1124. Status = STATUS_UNSUCCESSFUL;
  1125. break;
  1126. }
  1127. Status = SaferpSetSingleIdentificationHash(
  1128. TRUE, pIdentRecord,
  1129. (PSAFER_HASH_IDENTIFICATION) pCommon);
  1130. if (!NT_SUCCESS(Status)) {
  1131. RtlDeleteElementGenericTable(
  1132. &g_CodeIdentitiesTable,
  1133. (PVOID) &NewIdentRecord);
  1134. }
  1135. } else {
  1136. Status = STATUS_INFO_LENGTH_MISMATCH;
  1137. }
  1138. break;
  1139. // --------------------
  1140. case SaferIdentityTypeUrlZone:
  1141. if (pCommon->cbStructSize ==
  1142. sizeof(SAFER_URLZONE_IDENTIFICATION)) {
  1143. RtlInsertElementGenericTable(
  1144. &g_CodeIdentitiesTable,
  1145. (PVOID) &NewIdentRecord,
  1146. sizeof(AUTHZIDENTSTABLERECORD),
  1147. NULL);
  1148. pIdentRecord = CodeAuthzIdentsLookupByGuid(
  1149. &g_CodeIdentitiesTable,
  1150. &pCommon->IdentificationGuid);
  1151. if (!pIdentRecord) {
  1152. Status = STATUS_UNSUCCESSFUL;
  1153. break;
  1154. }
  1155. Status = SaferpSetSingleIdentificationZone(
  1156. TRUE, pIdentRecord,
  1157. (PSAFER_URLZONE_IDENTIFICATION) pCommon);
  1158. if (!NT_SUCCESS(Status)) {
  1159. RtlDeleteElementGenericTable(
  1160. &g_CodeIdentitiesTable,
  1161. (PVOID) &NewIdentRecord);
  1162. }
  1163. } else {
  1164. Status = STATUS_INFO_LENGTH_MISMATCH;
  1165. }
  1166. break;
  1167. // --------------------
  1168. default:
  1169. Status = STATUS_INVALID_INFO_CLASS;
  1170. break;
  1171. }
  1172. ExitHandler:
  1173. return Status;
  1174. }
  1175. NTSTATUS NTAPI
  1176. CodeAuthzpSetAuthzLevelInfo(
  1177. IN SAFER_LEVEL_HANDLE LevelHandle,
  1178. IN SAFER_OBJECT_INFO_CLASS dwInfoType,
  1179. IN LPVOID lpQueryBuffer,
  1180. IN DWORD dwInBufferSize
  1181. )
  1182. /*++
  1183. Routine Description:
  1184. Allows the user to modify various pieces of information about a
  1185. given WinSafer Level.
  1186. Arguments:
  1187. LevelHandle - the handle to the authorization object to evaluate.
  1188. dwInfoType - specifies the type of information being modified.
  1189. lpQueryBuffer - pointer to a user-supplied memory buffer that
  1190. contains the new data for the item being modified.
  1191. dwInBufferSize - specifies the size of the user's memory block.
  1192. For string arguments, this size includes the terminating null.
  1193. Return Value:
  1194. Returns STATUS_SUCCESS on success.
  1195. --*/
  1196. {
  1197. NTSTATUS Status;
  1198. PAUTHZLEVELHANDLESTRUCT pLevelStruct;
  1199. PAUTHZLEVELTABLERECORD pLevelRecord;
  1200. DWORD dwHandleScopeId;
  1201. BOOLEAN bNeedLevelRegKey;
  1202. UNICODE_STRING ValueName, UnicodeRegistrySuffix;
  1203. HANDLE hRegLevelBase;
  1204. //
  1205. // Obtain a pointer to the authorization object structure
  1206. //
  1207. Status = CodeAuthzHandleToLevelStruct(LevelHandle, &pLevelStruct);
  1208. if (!NT_SUCCESS(Status)) {
  1209. goto ExitHandler;
  1210. }
  1211. ASSERT(pLevelStruct != NULL);
  1212. pLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  1213. &g_CodeLevelObjTable, pLevelStruct->dwLevelId);
  1214. if (!pLevelRecord) {
  1215. Status = STATUS_INVALID_HANDLE;
  1216. goto ExitHandler;
  1217. }
  1218. dwHandleScopeId = pLevelStruct->dwScopeId;
  1219. //
  1220. // Determine if we need to open a registry handle to the Level key.
  1221. //
  1222. bNeedLevelRegKey = FALSE;
  1223. switch (dwInfoType)
  1224. {
  1225. case SaferObjectLevelId: // DWORD
  1226. case SaferObjectScopeId: // DWORD
  1227. case SaferObjectBuiltin: // DWORD boolean
  1228. // These information classes cannot be altered with this API.
  1229. Status = STATUS_INVALID_INFO_CLASS;
  1230. goto ExitHandler;
  1231. case SaferObjectFriendlyName: // LPCTSTR
  1232. case SaferObjectDescription: // LPCTSTR
  1233. if (pLevelRecord->Builtin) {
  1234. // Don't allow built-in Levels to be modified at all.
  1235. Status = STATUS_ACCESS_DENIED;
  1236. goto ExitHandler;
  1237. }
  1238. // All of these classes need to access the Level key.
  1239. bNeedLevelRegKey = TRUE;
  1240. break;
  1241. #ifdef ALLOW_FULL_WINSAFER
  1242. case SaferObjectDisallowed: // DWORD boolean
  1243. case SaferObjectDisableMaxPrivilege: // DWORD boolean
  1244. case SaferObjectInvertDeletedPrivileges: // DWORD boolean
  1245. case SaferObjectDefaultOwner: // TOKEN_OWNER
  1246. case SaferObjectDeletedPrivileges: // TOKEN_PRIVILEGES
  1247. case SaferObjectSidsToDisable: // TOKEN_GROUPS
  1248. case SaferObjectRestrictedSidsInverted: // TOKEN_GROUPS
  1249. case SaferObjectRestrictedSidsAdded: // TOKEN_GROUPS
  1250. if (pLevelRecord->Builtin) {
  1251. // Don't allow built-in Levels to be modified at all.
  1252. Status = STATUS_ACCESS_DENIED;
  1253. goto ExitHandler;
  1254. }
  1255. // All of these classes need to access the Level key.
  1256. bNeedLevelRegKey = TRUE;
  1257. break;
  1258. #endif
  1259. case SaferObjectAllIdentificationGuids:
  1260. Status = STATUS_INVALID_INFO_CLASS;
  1261. goto ExitHandler;
  1262. case SaferObjectSingleIdentification:
  1263. // These only modify Code Identity keys.
  1264. break;
  1265. default:
  1266. Status = STATUS_INVALID_INFO_CLASS;
  1267. goto ExitHandler;
  1268. }
  1269. //
  1270. // Open the registry handle to where this Level is stored.
  1271. //
  1272. if (bNeedLevelRegKey) {
  1273. WCHAR szRegistrySuffix[MAX_PATH];
  1274. RtlInitEmptyUnicodeString(
  1275. &UnicodeRegistrySuffix,
  1276. szRegistrySuffix,
  1277. sizeof(szRegistrySuffix));
  1278. Status = CodeAuthzpFormatLevelKeyPath(
  1279. pLevelRecord->dwLevelId,
  1280. &UnicodeRegistrySuffix);
  1281. if (!NT_SUCCESS(Status)) {
  1282. goto ExitHandler;
  1283. }
  1284. Status = CodeAuthzpOpenPolicyRootKey(
  1285. g_hKeyCustomRoot != NULL ?
  1286. SAFER_SCOPEID_REGISTRY : SAFER_SCOPEID_MACHINE,
  1287. g_hKeyCustomRoot, szRegistrySuffix,
  1288. KEY_WRITE, TRUE, &hRegLevelBase);
  1289. if (!NT_SUCCESS(Status)) {
  1290. goto ExitHandler;
  1291. }
  1292. } else {
  1293. hRegLevelBase = NULL;
  1294. }
  1295. //
  1296. // Otherwise perform the actual "Set" operation.
  1297. //
  1298. switch (dwInfoType)
  1299. {
  1300. case SaferObjectFriendlyName: // LPCTSTR
  1301. ASSERT(hRegLevelBase != NULL);
  1302. RtlInitUnicodeString(&ValueName,
  1303. SAFER_OBJFRIENDLYNAME_REGVALUEW);
  1304. Status = NtSetValueKey(hRegLevelBase,
  1305. &ValueName, 0, REG_SZ,
  1306. (LPBYTE) lpQueryBuffer, dwInBufferSize);
  1307. goto ExitHandler2;
  1308. case SaferObjectDescription: // LPCTSTR
  1309. ASSERT(hRegLevelBase != NULL);
  1310. RtlInitUnicodeString(&ValueName,
  1311. SAFER_OBJDESCRIPTION_REGVALUEW);
  1312. Status = NtSetValueKey(hRegLevelBase,
  1313. &ValueName, 0, REG_SZ,
  1314. (LPBYTE) lpQueryBuffer, dwInBufferSize);
  1315. goto ExitHandler2;
  1316. #ifdef ALLOW_FULL_WINSAFER
  1317. case SaferObjectDisallowed: // DWORD boolean
  1318. ASSERT(hRegLevelBase != NULL);
  1319. if (!ARGUMENT_PRESENT(lpQueryBuffer) ||
  1320. dwInBufferSize != sizeof(DWORD)) {
  1321. Status = STATUS_INVALID_PARAMETER;
  1322. goto ExitHandler2;
  1323. }
  1324. RtlInitUnicodeString(&ValueName, SAFER_OBJDISALLOW_REGVALUE);
  1325. Status = NtSetValueKey(hRegLevelBase,
  1326. &ValueName, 0, REG_DWORD,
  1327. (LPBYTE) lpQueryBuffer, dwInBufferSize);
  1328. if (NT_SUCCESS(Status)) {
  1329. goto ExitHandler2;
  1330. } else {
  1331. pLevelRecord->DisallowExecution =
  1332. ( *((LPDWORD) lpQueryBuffer) != 0 ? TRUE : FALSE );
  1333. }
  1334. //BLACKCOMB TODO: update cached pLevelRecord on success
  1335. break;
  1336. case SaferObjectDisableMaxPrivilege: // DWORD boolean
  1337. ASSERT(hRegLevelBase != NULL);
  1338. // Make sure the argument is the correct size.
  1339. if (!ARGUMENT_PRESENT(lpQueryBuffer) ||
  1340. dwInBufferSize != sizeof(DWORD)) {
  1341. Status = STATUS_INVALID_PARAMETER;
  1342. goto ExitHandler2;
  1343. }
  1344. // Actually write the value to the correct place.
  1345. Status = SaferpSetRegistryHelper(
  1346. hRegLevelBase,
  1347. L"Restrictions",
  1348. L"PrivsToRemove",
  1349. L"DisableMaxPrivilege",
  1350. REG_DWORD,
  1351. lpQueryBuffer,
  1352. dwInBufferSize);
  1353. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1354. //BLACKCOMB TODO: update cached pLevelRecord on success
  1355. break;
  1356. case SaferObjectInvertDeletedPrivileges: // DWORD boolean
  1357. ASSERT(hRegLevelBase != NULL);
  1358. // Make sure the argument is the correct size.
  1359. if (!ARGUMENT_PRESENT(lpQueryBuffer) ||
  1360. dwInBufferSize != sizeof(DWORD)) {
  1361. Status = STATUS_INVALID_PARAMETER;
  1362. goto ExitHandler2;
  1363. }
  1364. // Actually write the value to the correct place.
  1365. Status = SaferpSetRegistryHelper(
  1366. hRegLevelBase,
  1367. L"Restrictions",
  1368. L"PrivsToRemove",
  1369. L"InvertPrivs",
  1370. REG_DWORD,
  1371. lpQueryBuffer,
  1372. dwInBufferSize);
  1373. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1374. //BLACKCOMB TODO: update cached pLevelRecord on success
  1375. break;
  1376. case SaferObjectDefaultOwner: // TOKEN_OWNER
  1377. {
  1378. BOOLEAN AllocatedStringSid = FALSE;
  1379. UNICODE_STRING UnicodeStringSid;
  1380. PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) lpQueryBuffer;
  1381. ASSERT(hRegLevelBase != NULL);
  1382. if (pTokenOwner->Owner == NULL) {
  1383. RtlInitUnicodeString(&UnicodeStringSid, L"");
  1384. }
  1385. else {
  1386. Status = RtlConvertSidToUnicodeString( &UnicodeStringSid,
  1387. pTokenOwner->Owner, TRUE );
  1388. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1389. AllocatedStringSid = TRUE;
  1390. }
  1391. Status = SaferpSetRegistryHelper(
  1392. hRegLevelBase,
  1393. L"Restrictions",
  1394. NULL,
  1395. L"DefaultOwner",
  1396. REG_SZ,
  1397. lpQueryBuffer,
  1398. dwInBufferSize);
  1399. if (AllocatedStringSid)
  1400. RtlFreeUnicodeString(&UnicodeStringSid);
  1401. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1402. //BLACKCOMB TODO: update cached pLevelRecord on success
  1403. break;
  1404. }
  1405. case SaferObjectDeletedPrivileges: // TOKEN_PRIVILEGES
  1406. {
  1407. HKEY hKeyPrivsToRemove;
  1408. UNICODE_STRING ValueName;
  1409. PTOKEN_PRIVILEGES pTokenPrivs =
  1410. (PTOKEN_PRIVILEGES) lpQueryBuffer;
  1411. // Open a handle to the correct subkey.
  1412. ASSERT(hRegLevelBase != NULL);
  1413. Status = SaferpCreateSecondLevelKey(
  1414. hRegLevelBase,
  1415. L"Restrictions",
  1416. L"PrivsToRemove",
  1417. &hKeyPrivsToRemove);
  1418. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1419. // Clear out all old values under the subkey.
  1420. Status = SaferpClearRegistryListHelper(
  1421. hKeyPrivsToRemove,
  1422. L"Count",
  1423. L"Priv");
  1424. if (!NT_SUCCESS(Status)) {
  1425. // Bad luck! Possibly left in incomplete state!
  1426. NtClose(hKeyPrivsToRemove);
  1427. goto ExitHandler2;
  1428. }
  1429. // Now add all of the new ones we're supposed to add.
  1430. RtlInitUnicodeString(&ValueName, L"Count");
  1431. Status = NtSetValueKey(hKeyPrivsToRemove,
  1432. &ValueName, 0, REG_DWORD,
  1433. (LPBYTE) pTokenPrivs->PrivilegeCount, sizeof(DWORD));
  1434. if (!NT_SUCCESS(Status)) {
  1435. // Bad luck! Possibly left in incomplete state!
  1436. NtClose(hKeyPrivsToRemove);
  1437. goto ExitHandler2;
  1438. }
  1439. for (Index = 0; Index < pTokenPrivs->PrivilegeCount; Index++)
  1440. {
  1441. WCHAR ValueNameBuffer[20];
  1442. WCHAR PrivilegeNameBuffer[64];
  1443. DWORD dwPrivilegeNameLen;
  1444. wsprintfW(ValueNameBuffer, L"Priv%d", Index);
  1445. RtlInitUnicodeString(&ValueName, ValueNameBuffer);
  1446. dwPrivilegeNameLen = sizeof(PrivilegeNameBuffer) / sizeof(WCHAR);
  1447. if (!LookupPrivilegeNameW(NULL,
  1448. &pTokenPrivs->Privileges[Index].Luid,
  1449. PrivilegeNameBuffer,
  1450. &dwPrivilegeNameLen))
  1451. {
  1452. // Bad luck! Possibly left in incomplete state!
  1453. Status = STATUS_NO_SUCH_PRIVILEGE;
  1454. NtClose(hKeyPrivsToRemove);
  1455. goto ExitHandler2;
  1456. }
  1457. Status = NtSetValueKey(hKeyPrivsToRemove,
  1458. &ValueName, 0, REG_SZ,
  1459. (LPBYTE) PrivilegeNameBuffer,
  1460. (wcslen(PrivilegeNameBuffer) + 1) * sizeof(WCHAR));
  1461. if (!NT_SUCCESS(Status)) {
  1462. // Bad luck! Possibly left in incomplete state!
  1463. NtClose(hKeyPrivsToRemove);
  1464. goto ExitHandler2;
  1465. }
  1466. }
  1467. NtClose(hKeyPrivsToRemove);
  1468. //BLACKCOMB TODO: update cached pLevelRecord on success
  1469. break;
  1470. }
  1471. case SaferObjectSidsToDisable: // TOKEN_GROUPS
  1472. //BLACKCOMB TODO: allow wildcard sids to be specified.
  1473. ASSERT(hRegLevelBase != NULL);
  1474. Status = SaferpSetListOfSids(
  1475. hRegLevelBase,
  1476. L"Restrictions",
  1477. L"SidsToDisable",
  1478. L"Count",
  1479. L"Group",
  1480. (PTOKEN_GROUPS) lpQueryBuffer);
  1481. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1482. //BLACKCOMB TODO: update cached pLevelRecord on success
  1483. break;
  1484. case SaferObjectRestrictedSidsInverted: // TOKEN_GROUPS
  1485. //BLACKCOMB TODO: allow wildcard sids to be specified.
  1486. ASSERT(hRegLevelBase != NULL);
  1487. Status = SaferpSetListOfSids(
  1488. hRegLevelBase,
  1489. L"Restrictions",
  1490. L"RestrictingSidsInverted",
  1491. L"Count",
  1492. L"Group",
  1493. (PTOKEN_GROUPS) lpQueryBuffer);
  1494. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1495. //BLACKCOMB TODO: update cached pLevelRecord on success
  1496. break;
  1497. case SaferObjectRestrictedSidsAdded: // TOKEN_GROUPS
  1498. ASSERT(hRegLevelBase != NULL);
  1499. Status = SaferpSetListOfSids(
  1500. hRegLevelBase,
  1501. L"Restrictions",
  1502. L"RestrictingSidsAdded",
  1503. L"Count",
  1504. L"Group",
  1505. (PTOKEN_GROUPS) lpQueryBuffer);
  1506. if (!NT_SUCCESS(Status)) goto ExitHandler2;
  1507. //BLACKCOMB TODO: update cached pLevelRecord on success
  1508. break;
  1509. #endif
  1510. case SaferObjectSingleIdentification:
  1511. {
  1512. PAUTHZIDENTSTABLERECORD pIdentRecord;
  1513. PSAFER_IDENTIFICATION_HEADER pCommon =
  1514. (PSAFER_IDENTIFICATION_HEADER) lpQueryBuffer;
  1515. if (!ARGUMENT_PRESENT(pCommon)) {
  1516. Status = STATUS_ACCESS_VIOLATION;
  1517. goto ExitHandler2;
  1518. }
  1519. if (dwInBufferSize < sizeof(SAFER_IDENTIFICATION_HEADER) ||
  1520. dwInBufferSize < pCommon->cbStructSize) {
  1521. Status = STATUS_INFO_LENGTH_MISMATCH;
  1522. goto ExitHandler2;
  1523. }
  1524. pIdentRecord = CodeAuthzIdentsLookupByGuid(
  1525. &g_CodeIdentitiesTable,
  1526. &pCommon->IdentificationGuid);
  1527. if (!pIdentRecord)
  1528. {
  1529. // Request to create a new Code Identifier.
  1530. Status = SaferpCreateNewSingleIdentification(
  1531. dwHandleScopeId, pLevelRecord, pCommon);
  1532. }
  1533. else if (pCommon->dwIdentificationType == 0)
  1534. {
  1535. // Request to delete an existing Code Identifier.
  1536. if (pIdentRecord->dwLevelId != pLevelRecord->dwLevelId ||
  1537. pIdentRecord->dwScopeId != dwHandleScopeId) {
  1538. Status = STATUS_NOT_FOUND;
  1539. } else {
  1540. Status = SaferpDeleteSingleIdentificationGuid(
  1541. pLevelRecord, pIdentRecord);
  1542. }
  1543. }
  1544. else
  1545. {
  1546. // Request to modify an existing Code Identifier.
  1547. if (pIdentRecord->dwLevelId != pLevelRecord->dwLevelId ||
  1548. pIdentRecord->dwScopeId != dwHandleScopeId)
  1549. {
  1550. // This was likely a request to create a new Code
  1551. // Identifier, but with a GUID that already exists.
  1552. Status = STATUS_OBJECT_NAME_COLLISION;
  1553. } else {
  1554. Status = SaferpSetExistingSingleIdentification(
  1555. pIdentRecord, pCommon);
  1556. }
  1557. }
  1558. goto ExitHandler2;
  1559. }
  1560. default:
  1561. ASSERTMSG("invalid info class unhandled earlier", 0);
  1562. Status = STATUS_INVALID_INFO_CLASS;
  1563. goto ExitHandler2;
  1564. }
  1565. Status = STATUS_SUCCESS;
  1566. //
  1567. // Cleanup and epilogue code.
  1568. //
  1569. ExitHandler2:
  1570. if (hRegLevelBase != NULL) {
  1571. NtClose(hRegLevelBase);
  1572. }
  1573. ExitHandler:
  1574. return Status;
  1575. }
  1576. BOOL WINAPI
  1577. SaferSetLevelInformation(
  1578. IN SAFER_LEVEL_HANDLE LevelHandle,
  1579. IN SAFER_OBJECT_INFO_CLASS dwInfoType,
  1580. IN LPVOID lpQueryBuffer,
  1581. IN DWORD dwInBufferSize
  1582. )
  1583. /*++
  1584. Routine Description:
  1585. Allows the user to modify various pieces of information about a
  1586. given WinSafer Level.
  1587. Arguments:
  1588. LevelHandle - the handle to the WinSafer Level to evaluate.
  1589. dwInfoType - specifies the type of information being modified.
  1590. lpQueryBuffer - pointer to a user-supplied memory buffer that
  1591. contains the new data for the item being modified.
  1592. dwInBufferSize - specifies the size of the user's memory block.
  1593. For string arguments, this size includes the terminating null.
  1594. Return Value:
  1595. Returns FALSE on error, otherwise success.
  1596. --*/
  1597. {
  1598. NTSTATUS Status;
  1599. if (!g_bInitializedFirstTime) {
  1600. Status = STATUS_UNSUCCESSFUL;
  1601. goto ExitHandler;
  1602. }
  1603. RtlEnterCriticalSection(&g_TableCritSec);
  1604. Status = CodeAuthzpSetAuthzLevelInfo(
  1605. LevelHandle, dwInfoType,
  1606. lpQueryBuffer, dwInBufferSize);
  1607. RtlLeaveCriticalSection(&g_TableCritSec);
  1608. if (NT_SUCCESS(Status))
  1609. return TRUE;
  1610. ExitHandler:
  1611. if (Status == STATUS_OBJECT_NAME_COLLISION) {
  1612. SetLastError(ERROR_OBJECT_ALREADY_EXISTS);
  1613. } else {
  1614. BaseSetLastNTError(Status);
  1615. }
  1616. return FALSE;
  1617. }