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.

1130 lines
38 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. safeget.cpp (SAFER SaferGetLevelInformation)
  5. Abstract:
  6. This module implements the WinSAFER APIs to get information about a
  7. sepcific Authorization Level and the attributes and identities that
  8. are associated with it.
  9. Author:
  10. Jeffrey Lawson (JLawson) - Nov 1999
  11. Environment:
  12. User mode only.
  13. Exported Functions:
  14. SaferGetLevelInformation
  15. Revision History:
  16. Created - Nov 1999
  17. --*/
  18. #include "pch.h"
  19. #pragma hdrstop
  20. #include <winsafer.h>
  21. #include <winsaferp.h>
  22. #include "saferp.h"
  23. DWORD NTAPI
  24. __CodeAuthzpCountIdentsForLevel(
  25. IN DWORD dwScopeId,
  26. IN DWORD dwLevelId
  27. )
  28. /*++
  29. Routine Description:
  30. Determines the number of Code Identities that have been associated
  31. with a given WinSafer LevelId. This number represents the number
  32. of identity GUIDs that will be returned to the caller.
  33. Arguments:
  34. dwScopeId - specifies the Scope value that will be considered.
  35. dwLevelId - specifies the LevelId value to be counted.
  36. Return Value:
  37. Returns the actual number of unique Code Identities that were found
  38. to be associated with the given LevelId. If no Identities were
  39. found, then 0 will be returned.
  40. --*/
  41. {
  42. PVOID RestartKey;
  43. PAUTHZIDENTSTABLERECORD pAuthzIdentsRec;
  44. DWORD dwMatchingCount = 0;
  45. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  46. RestartKey = NULL;
  47. for (pAuthzIdentsRec = (PAUTHZIDENTSTABLERECORD)
  48. RtlEnumerateGenericTableWithoutSplaying(
  49. &g_CodeIdentitiesTable, &RestartKey);
  50. pAuthzIdentsRec != NULL;
  51. pAuthzIdentsRec = (PAUTHZIDENTSTABLERECORD)
  52. RtlEnumerateGenericTableWithoutSplaying(
  53. &g_CodeIdentitiesTable, &RestartKey)
  54. )
  55. {
  56. if (pAuthzIdentsRec->dwLevelId == dwLevelId &&
  57. pAuthzIdentsRec->dwScopeId == dwScopeId)
  58. dwMatchingCount++;
  59. }
  60. return dwMatchingCount;
  61. }
  62. NTSTATUS NTAPI
  63. __CodeAuthzpFetchIdentsForLevel(
  64. IN DWORD dwScopeId,
  65. IN DWORD dwLevelId,
  66. IN DWORD dwInBufferSize,
  67. IN OUT LPVOID lpQueryBuffer,
  68. OUT LPDWORD pdwUsedSize
  69. )
  70. /*++
  71. Routine Description:
  72. Retrieves all of Code Identities that have been associated
  73. with a given WinSafer LevelId. The number of identity GUIDs
  74. that will be returned to the caller can be determined by
  75. first calling __CodeAuthzpCountIdentsForLevel. It is assumed
  76. that the caller has already determined and verified the appropriate
  77. size of the buffer that should be supplied using that function.
  78. Arguments:
  79. dwScopeId - specifies the Scope value that will be considered.
  80. dwLevelId - specifies the LevelId value to be matched.
  81. dwInBufferSize - specifies the size of the output buffer.
  82. lpQueryBuffer - points to the output buffer that should be filled.
  83. pdwUsedSize - receives the actual number of bytes used.
  84. Return Value:
  85. Returns the actual number of unique Code Identities that were found
  86. to be associated with the given LevelId. If no Identities were
  87. found, then 0 will be returned.
  88. --*/
  89. {
  90. PVOID RestartKey;
  91. PAUTHZIDENTSTABLERECORD pIdentRecord;
  92. LPVOID lpNextPtr;
  93. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  94. ASSERT(ARGUMENT_PRESENT(lpQueryBuffer));
  95. ASSERT(ARGUMENT_PRESENT(pdwUsedSize));
  96. RestartKey = NULL;
  97. lpNextPtr = (LPVOID) lpQueryBuffer;
  98. for (pIdentRecord = (PAUTHZIDENTSTABLERECORD)
  99. RtlEnumerateGenericTableWithoutSplaying(
  100. &g_CodeIdentitiesTable, &RestartKey);
  101. pIdentRecord != NULL;
  102. pIdentRecord = (PAUTHZIDENTSTABLERECORD)
  103. RtlEnumerateGenericTableWithoutSplaying(
  104. &g_CodeIdentitiesTable, &RestartKey))
  105. {
  106. if (pIdentRecord->dwLevelId == dwLevelId &&
  107. pIdentRecord->dwScopeId == dwScopeId)
  108. {
  109. if ( ((PBYTE) lpNextPtr) - ((PBYTE) lpQueryBuffer) +
  110. sizeof(GUID) > dwInBufferSize ) {
  111. return STATUS_BUFFER_TOO_SMALL;
  112. }
  113. RtlCopyMemory( lpNextPtr, &pIdentRecord->IdentGuid, sizeof(GUID) );
  114. lpNextPtr = (LPVOID) ( ((PBYTE) lpNextPtr) + sizeof(GUID));
  115. }
  116. }
  117. ASSERT((PBYTE) lpNextPtr <= ((PBYTE) lpQueryBuffer) + dwInBufferSize);
  118. *pdwUsedSize = (DWORD) (((PBYTE) lpNextPtr) - ((PBYTE) lpQueryBuffer));
  119. return STATUS_SUCCESS;
  120. }
  121. NTSTATUS NTAPI
  122. __CodeAuthzpOpenIdentifierKey(
  123. IN DWORD dwScopeId,
  124. IN DWORD dwLevelId,
  125. IN LPCWSTR szIdentityType,
  126. IN REFGUID refIdentGuid,
  127. OUT HANDLE *phOpenedKey
  128. )
  129. /*++
  130. Routine Description:
  131. Arguments:
  132. dwScopeId -
  133. dwLevelId -
  134. szIdentityType -
  135. refIdentGuid -
  136. phOpenedKey -
  137. Return Value:
  138. Returns STATUS_SUCCESS on success.
  139. --*/
  140. {
  141. NTSTATUS Status;
  142. UNICODE_STRING UnicodePath;
  143. WCHAR szPathBuffer[MAX_PATH];
  144. if (!ARGUMENT_PRESENT(refIdentGuid) ||
  145. !ARGUMENT_PRESENT(phOpenedKey)) {
  146. Status = STATUS_INVALID_PARAMETER;
  147. goto ExitHandler;
  148. }
  149. if (g_hKeyCustomRoot != NULL) {
  150. if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
  151. Status = STATUS_INVALID_PARAMETER_MIX;
  152. goto ExitHandler;
  153. }
  154. } else {
  155. if (dwScopeId != SAFER_SCOPEID_MACHINE &&
  156. dwScopeId != SAFER_SCOPEID_USER) {
  157. Status = STATUS_INVALID_PARAMETER_MIX;
  158. goto ExitHandler;
  159. }
  160. }
  161. RtlInitEmptyUnicodeString(&UnicodePath,
  162. szPathBuffer, sizeof(szPathBuffer));
  163. Status = CodeAuthzpFormatIdentityKeyPath(
  164. dwLevelId, szIdentityType,
  165. refIdentGuid, &UnicodePath);
  166. if (!NT_SUCCESS(Status)) {
  167. goto ExitHandler;
  168. }
  169. Status = CodeAuthzpOpenPolicyRootKey(
  170. dwScopeId, g_hKeyCustomRoot,
  171. UnicodePath.Buffer,
  172. KEY_READ, FALSE, phOpenedKey);
  173. ExitHandler:
  174. return Status;
  175. }
  176. NTSTATUS NTAPI
  177. __CodeAuthzpQueryIdentityRegValue(
  178. IN HANDLE hKeyIdentityBase,
  179. IN LPWSTR szValueName,
  180. IN DWORD dwRegType,
  181. OUT PVOID lpOutBuffer,
  182. IN ULONG ulOutBufferSize,
  183. OUT PULONG pulActualOutSize OPTIONAL
  184. )
  185. /*++
  186. Routine Description:
  187. Generic helper function to query a registry value, provided that a
  188. pre-opened registry handle to the key is already known.
  189. Arguments:
  190. hKeyIdentityBase - registry key handle.
  191. szValueName - null-terminated Unicode string of the registry value name.
  192. dwRegType - type of the registry value expected (REG_SZ, REG_DWORD, etc)
  193. If a registry value of the given name exists, but is not of this
  194. type, then this function will return STATUS_NOT_FOUND.
  195. lpOutBuffer - pointer to a target buffer that will receive the
  196. retrieved value contents.
  197. ulOutBufferSize - input argument that specifies the maximum size
  198. of the buffer pointed to by the lpOutBuffer argument.
  199. pulActualOutSize - output argument that receives the actual size
  200. of the retrieved value contents if the call is successful.
  201. Return Value:
  202. Returns STATUS_SUCCESS on success.
  203. --*/
  204. {
  205. NTSTATUS Status;
  206. ULONG ulResultLength;
  207. UNICODE_STRING ValueName;
  208. ULONG ulValueBufferSize;
  209. PKEY_VALUE_PARTIAL_INFORMATION pValuePartialInfo;
  210. //
  211. // Allocate enough memory for the query buffer.
  212. //
  213. ASSERT(ARGUMENT_PRESENT(lpOutBuffer) && ulOutBufferSize > 0);
  214. ulValueBufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
  215. ulOutBufferSize + sizeof(WCHAR) * 256;
  216. pValuePartialInfo = (PKEY_VALUE_PARTIAL_INFORMATION)
  217. RtlAllocateHeap(RtlProcessHeap(), 0, ulValueBufferSize);
  218. if (!pValuePartialInfo) {
  219. Status = STATUS_NO_MEMORY;
  220. goto ExitHandler;
  221. }
  222. //
  223. // Actually query the value into the temporary query buffer.
  224. //
  225. ASSERT(ARGUMENT_PRESENT(szValueName));
  226. RtlInitUnicodeString(&ValueName, szValueName);
  227. Status = NtQueryValueKey(hKeyIdentityBase, &ValueName,
  228. KeyValuePartialInformation,
  229. pValuePartialInfo, ulValueBufferSize,
  230. &ulResultLength);
  231. if (!NT_SUCCESS(Status)) {
  232. goto ExitHandler2;
  233. }
  234. if (pValuePartialInfo->Type != dwRegType) {
  235. Status = STATUS_NOT_FOUND;
  236. goto ExitHandler2;
  237. }
  238. //
  239. // Copy the resulting data from the query buffer into
  240. // the caller's buffer.
  241. //
  242. ulResultLength = pValuePartialInfo->DataLength;
  243. if (ulResultLength > ulOutBufferSize) {
  244. Status = STATUS_BUFFER_TOO_SMALL;
  245. } else {
  246. RtlCopyMemory(lpOutBuffer,
  247. pValuePartialInfo->Data,
  248. ulResultLength);
  249. Status = STATUS_SUCCESS;
  250. }
  251. if (ARGUMENT_PRESENT(pulActualOutSize)) {
  252. *pulActualOutSize = ulResultLength;
  253. }
  254. ExitHandler2:
  255. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID) pValuePartialInfo);
  256. ExitHandler:
  257. return Status;
  258. }
  259. NTSTATUS NTAPI
  260. __CodeAuthzpQuerySingleIdentification(
  261. IN PAUTHZIDENTSTABLERECORD pSingleIdentRecord,
  262. OUT LPVOID lpQueryBuffer,
  263. IN DWORD dwInBufferSize,
  264. OUT PDWORD dwNeededSize
  265. )
  266. /*++
  267. Routine Description:
  268. Allows the user to retrieve information about a single identity.
  269. Assumes that the caller has already obtained and locked the
  270. global critical section.
  271. Arguments:
  272. pSingleIdentRecord - pointer to the identity record structure.
  273. lpQueryBuffer - pointer to a user-supplied memory buffer that
  274. will receive the requested information.
  275. dwInBufferSize - specifies the size of the user's memory block.
  276. lpdwOutBufferSize - receives the used size of the data within the
  277. memory block, or the minimum necessary size if the passed
  278. buffer was too small.
  279. Return Value:
  280. Returns STATUS_SUCCESS on success.
  281. --*/
  282. {
  283. NTSTATUS Status = STATUS_SUCCESS;
  284. HANDLE hKeyIdentity = NULL;
  285. ULONG ulResultLength = 0;
  286. ULONG ulTextLen = 0;
  287. PSAFER_IDENTIFICATION_HEADER pIdentCommon = NULL;
  288. //
  289. // All of these conditions should have been already verified
  290. // by our caller before calling us, so we only assert them.
  291. //
  292. ASSERT(ARGUMENT_PRESENT(pSingleIdentRecord));
  293. ASSERT(ARGUMENT_PRESENT(lpQueryBuffer) &&
  294. dwInBufferSize >= sizeof(SAFER_IDENTIFICATION_HEADER));
  295. ASSERT(pSingleIdentRecord->dwIdentityType == SaferIdentityTypeImageName ||
  296. pSingleIdentRecord->dwIdentityType == SaferIdentityTypeImageHash ||
  297. pSingleIdentRecord->dwIdentityType == SaferIdentityTypeUrlZone);
  298. //
  299. // Start filling the resulting structure with the data.
  300. //
  301. pIdentCommon = (PSAFER_IDENTIFICATION_HEADER) lpQueryBuffer;
  302. switch (pSingleIdentRecord->dwIdentityType)
  303. {
  304. // --------------------
  305. case SaferIdentityTypeImageName:
  306. Status = __CodeAuthzpOpenIdentifierKey(
  307. pSingleIdentRecord->dwScopeId,
  308. pSingleIdentRecord->dwLevelId,
  309. SAFER_PATHS_REGSUBKEY,
  310. &pSingleIdentRecord->IdentGuid,
  311. &hKeyIdentity);
  312. if (!NT_SUCCESS(Status)) {
  313. goto ExitHandler;
  314. }
  315. pIdentCommon->dwIdentificationType = SaferIdentityTypeImageName;
  316. {
  317. PSAFER_PATHNAME_IDENTIFICATION pIdentOut = (PSAFER_PATHNAME_IDENTIFICATION) lpQueryBuffer;
  318. ASSERT(&pIdentOut->header == pIdentCommon);
  319. ulTextLen = pSingleIdentRecord->ImageNameInfo.ImagePath.Length;
  320. *dwNeededSize = ulTextLen + sizeof(UNICODE_NULL) +
  321. sizeof(SAFER_PATHNAME_IDENTIFICATION);
  322. if (*dwNeededSize > dwInBufferSize) {
  323. // the imagepath is vital, so we'll bail out.
  324. Status = STATUS_BUFFER_TOO_SMALL;
  325. goto ExitHandler2;
  326. }
  327. pIdentOut->ImageName = (PWCHAR) (((PUCHAR) pIdentOut) + sizeof(SAFER_PATHNAME_IDENTIFICATION));
  328. Status = __CodeAuthzpQueryIdentityRegValue(
  329. hKeyIdentity,
  330. SAFER_IDS_DESCRIPTION_REGVALUE,
  331. REG_SZ,
  332. pIdentOut->Description,
  333. SAFER_MAX_DESCRIPTION_SIZE * sizeof(WCHAR),
  334. NULL);
  335. if (!NT_SUCCESS(Status)) {
  336. pIdentOut->Description[0] = UNICODE_NULL;
  337. }
  338. RtlCopyMemory(pIdentOut->ImageName,
  339. pSingleIdentRecord->ImageNameInfo.ImagePath.Buffer,
  340. ulTextLen);
  341. pIdentOut->ImageName[ulTextLen / sizeof(WCHAR)] = UNICODE_NULL;
  342. pIdentOut->header.cbStructSize = *dwNeededSize;
  343. pIdentOut->dwSaferFlags =
  344. pSingleIdentRecord->ImageNameInfo.dwSaferFlags;
  345. }
  346. break;
  347. // --------------------
  348. case SaferIdentityTypeImageHash:
  349. Status = __CodeAuthzpOpenIdentifierKey(
  350. pSingleIdentRecord->dwScopeId,
  351. pSingleIdentRecord->dwLevelId,
  352. SAFER_HASHMD5_REGSUBKEY,
  353. &pSingleIdentRecord->IdentGuid,
  354. &hKeyIdentity);
  355. if (!NT_SUCCESS(Status)) {
  356. goto ExitHandler;
  357. }
  358. pIdentCommon->dwIdentificationType = SaferIdentityTypeImageHash;
  359. {
  360. PSAFER_HASH_IDENTIFICATION pIdentOut = (PSAFER_HASH_IDENTIFICATION) lpQueryBuffer;
  361. ASSERT(&pIdentOut->header == pIdentCommon);
  362. pIdentOut->header.cbStructSize =
  363. sizeof(SAFER_HASH_IDENTIFICATION);
  364. Status = __CodeAuthzpQueryIdentityRegValue(
  365. hKeyIdentity,
  366. SAFER_IDS_DESCRIPTION_REGVALUE,
  367. REG_SZ,
  368. pIdentOut->Description,
  369. SAFER_MAX_DESCRIPTION_SIZE * sizeof(WCHAR),
  370. NULL
  371. );
  372. if (!NT_SUCCESS(Status)) {
  373. pIdentOut->Description[0] = UNICODE_NULL;
  374. }
  375. Status = __CodeAuthzpQueryIdentityRegValue(
  376. hKeyIdentity,
  377. SAFER_IDS_FRIENDLYNAME_REGVALUE,
  378. REG_SZ,
  379. pIdentOut->FriendlyName,
  380. SAFER_MAX_FRIENDLYNAME_SIZE * sizeof(WCHAR),
  381. NULL
  382. );
  383. if (!NT_SUCCESS(Status)) {
  384. pIdentOut->FriendlyName[0] = UNICODE_NULL;
  385. }
  386. ASSERT(pSingleIdentRecord->ImageHashInfo.HashSize <= SAFER_MAX_HASH_SIZE);
  387. RtlCopyMemory(pIdentOut->ImageHash,
  388. pSingleIdentRecord->ImageHashInfo.ImageHash,
  389. pSingleIdentRecord->ImageHashInfo.HashSize);
  390. pIdentOut->HashSize =
  391. pSingleIdentRecord->ImageHashInfo.HashSize;
  392. pIdentOut->HashAlgorithm =
  393. pSingleIdentRecord->ImageHashInfo.HashAlgorithm;
  394. pIdentOut->ImageSize =
  395. pSingleIdentRecord->ImageHashInfo.ImageSize;
  396. pIdentOut->dwSaferFlags =
  397. pSingleIdentRecord->ImageHashInfo.dwSaferFlags;
  398. }
  399. break;
  400. // --------------------
  401. case SaferIdentityTypeUrlZone:
  402. {
  403. PSAFER_URLZONE_IDENTIFICATION pIdentOut = (PSAFER_URLZONE_IDENTIFICATION) lpQueryBuffer;
  404. Status = __CodeAuthzpOpenIdentifierKey(
  405. pSingleIdentRecord->dwScopeId,
  406. pSingleIdentRecord->dwLevelId,
  407. SAFER_SOURCEURL_REGSUBKEY,
  408. &pSingleIdentRecord->IdentGuid,
  409. &hKeyIdentity);
  410. if (!NT_SUCCESS(Status)) {
  411. goto ExitHandler;
  412. }
  413. pIdentCommon->dwIdentificationType = SaferIdentityTypeUrlZone;
  414. ASSERT(&pIdentOut->header == pIdentCommon);
  415. pIdentOut->header.cbStructSize =
  416. sizeof(SAFER_URLZONE_IDENTIFICATION);
  417. pIdentOut->UrlZoneId =
  418. pSingleIdentRecord->ImageZone.UrlZoneId;
  419. pIdentOut->dwSaferFlags =
  420. pSingleIdentRecord->ImageZone.dwSaferFlags;
  421. break;
  422. }
  423. // --------------------
  424. default:
  425. Status = STATUS_INVALID_INFO_CLASS;
  426. goto ExitHandler;
  427. }
  428. //
  429. // Fill in the other information that is applicable to all types.
  430. //
  431. RtlCopyMemory(&pIdentCommon->IdentificationGuid,
  432. &pSingleIdentRecord->IdentGuid,
  433. sizeof(GUID));
  434. ASSERT(sizeof(FILETIME) == sizeof(DWORD) * 2);
  435. Status = __CodeAuthzpQueryIdentityRegValue(
  436. hKeyIdentity,
  437. SAFER_IDS_LASTMODIFIED_REGVALUE,
  438. REG_QWORD,
  439. &pIdentCommon->lastModified,
  440. sizeof(FILETIME),
  441. &ulResultLength
  442. );
  443. if (!NT_SUCCESS(Status)) {
  444. pIdentCommon->lastModified.dwHighDateTime =
  445. pIdentCommon->lastModified.dwLowDateTime = 0;
  446. }
  447. Status = STATUS_SUCCESS;
  448. ExitHandler2:
  449. NtClose(hKeyIdentity);
  450. ExitHandler:
  451. return Status;
  452. }
  453. NTSTATUS NTAPI
  454. __CodeAuthzpGetAuthzLevelInfo(
  455. IN SAFER_LEVEL_HANDLE hLevelHandle,
  456. IN SAFER_OBJECT_INFO_CLASS dwInfoType,
  457. OUT LPVOID lpQueryBuffer OPTIONAL,
  458. IN DWORD dwInBufferSize,
  459. OUT LPDWORD lpdwOutBufferSize
  460. )
  461. /*++
  462. Routine Description:
  463. Allows the user to query various pieces of information about a
  464. given Level handle.
  465. Assumes that the caller has already obtained and locked the
  466. global critical section.
  467. Arguments:
  468. hLevelHandle - the handle to the authorization object to evaluate.
  469. dwInfoType - specifies the type of information being requested.
  470. lpQueryBuffer - pointer to a user-supplied memory buffer that
  471. will receive the requested information.
  472. dwInBufferSize - specifies the size of the user's memory block.
  473. lpdwOutBufferSize - receives the used size of the data within the
  474. memory block, or the minimum necessary size if the passed
  475. buffer was too small.
  476. Return Value:
  477. Returns STATUS_SUCCESS on success.
  478. --*/
  479. {
  480. const static SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
  481. NTSTATUS Status;
  482. PAUTHZLEVELHANDLESTRUCT pAuthzLevelStruct;
  483. PAUTHZLEVELTABLERECORD pAuthzLevelRecord;
  484. PAUTHZIDENTSTABLERECORD pSingleIdentRecord = NULL;
  485. DWORD dwHandleScopeId;
  486. //
  487. // Obtain a pointer to the authorization Level structure.
  488. //
  489. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  490. Status = CodeAuthzHandleToLevelStruct(hLevelHandle, &pAuthzLevelStruct);
  491. if (!NT_SUCCESS(Status)) {
  492. goto ExitHandler;
  493. }
  494. ASSERT(pAuthzLevelStruct != NULL);
  495. pAuthzLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  496. &g_CodeLevelObjTable, pAuthzLevelStruct->dwLevelId);
  497. if (!pAuthzLevelRecord) {
  498. Status = STATUS_INVALID_HANDLE;
  499. goto ExitHandler;
  500. }
  501. dwHandleScopeId = pAuthzLevelStruct->dwScopeId;
  502. //
  503. // Some of the attributes are fixed size, or are known before performing
  504. // the full query against the registry. Compute their size first.
  505. //
  506. *lpdwOutBufferSize = 0;
  507. switch (dwInfoType)
  508. {
  509. case SaferObjectLevelId: // DWORD
  510. case SaferObjectScopeId: // DWORD
  511. case SaferObjectBuiltin: // DWORD boolean
  512. *lpdwOutBufferSize = sizeof(DWORD);
  513. break;
  514. case SaferObjectFriendlyName: // LPCTSTR
  515. if (!pAuthzLevelRecord->UnicodeFriendlyName.Buffer ||
  516. !pAuthzLevelRecord->UnicodeFriendlyName.Length) {
  517. Status = STATUS_NOT_FOUND;
  518. goto ExitHandler;
  519. }
  520. *lpdwOutBufferSize =
  521. pAuthzLevelRecord->UnicodeFriendlyName.Length +
  522. sizeof(UNICODE_NULL);
  523. break;
  524. case SaferObjectDescription: // LPCTSTR
  525. if (!pAuthzLevelRecord->UnicodeDescription.Buffer ||
  526. !pAuthzLevelRecord->UnicodeDescription.Length) {
  527. Status = STATUS_NOT_FOUND;
  528. goto ExitHandler;
  529. }
  530. *lpdwOutBufferSize = pAuthzLevelRecord->UnicodeDescription.Length +
  531. sizeof(UNICODE_NULL);
  532. break;
  533. #ifdef ALLOW_FULL_WINSAFER
  534. case SaferObjectDisallowed: // DWORD boolean
  535. case SaferObjectDisableMaxPrivilege: // DWORD boolean
  536. case SaferObjectInvertDeletedPrivileges: // DWORD boolean
  537. *lpdwOutBufferSize = sizeof(DWORD);
  538. break;
  539. case SaferObjectDeletedPrivileges: // TOKEN_PRIVILEGES
  540. *lpdwOutBufferSize = (sizeof(TOKEN_PRIVILEGES) - sizeof(LUID_AND_ATTRIBUTES)) +
  541. pAuthzLevelRecord->DeletePrivilegeUsedCount * sizeof(LUID_AND_ATTRIBUTES);
  542. break;
  543. case SaferObjectDefaultOwner: // TOKEN_OWNER
  544. *lpdwOutBufferSize = sizeof(TOKEN_OWNER);
  545. if (pAuthzLevelRecord->DefaultOwner != NULL)
  546. *lpdwOutBufferSize += RtlLengthSid(pAuthzLevelRecord->DefaultOwner);
  547. break;
  548. case SaferObjectSidsToDisable: // TOKEN_GROUPS
  549. *lpdwOutBufferSize = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  550. pAuthzLevelRecord->DisableSidUsedCount * sizeof(SID_AND_ATTRIBUTES);
  551. for (Index = 0; Index < pAuthzLevelRecord->DisableSidUsedCount; Index++)
  552. *lpdwOutBufferSize += RtlLengthSid(pAuthzLevelRecord->SidsToDisable[Index].Sid);
  553. break;
  554. case SaferObjectRestrictedSidsInverted: // TOKEN_GROUPS
  555. *lpdwOutBufferSize = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  556. pAuthzLevelRecord->RestrictedSidsInvUsedCount * sizeof(SID_AND_ATTRIBUTES);
  557. for (Index = 0; Index < pAuthzLevelRecord->RestrictedSidsInvUsedCount; Index++)
  558. *lpdwOutBufferSize += RtlLengthSid(pAuthzLevelRecord->RestrictedSidsInv[Index].Sid);
  559. break;
  560. case SaferObjectRestrictedSidsAdded: // TOKEN_GROUPS
  561. *lpdwOutBufferSize = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  562. pAuthzLevelRecord->RestrictedSidsAddedUsedCount * sizeof(SID_AND_ATTRIBUTES);
  563. for (Index = 0; Index < pAuthzLevelRecord->RestrictedSidsAddedUsedCount; Index++)
  564. *lpdwOutBufferSize += RtlLengthSid(pAuthzLevelRecord->RestrictedSidsAdded[Index].Sid);
  565. break;
  566. #endif
  567. case SaferObjectAllIdentificationGuids:
  568. *lpdwOutBufferSize = sizeof(GUID) *
  569. __CodeAuthzpCountIdentsForLevel(
  570. dwHandleScopeId,
  571. pAuthzLevelRecord->dwLevelId);
  572. if (!*lpdwOutBufferSize) {
  573. Status = STATUS_NOT_FOUND;
  574. goto ExitHandler;
  575. }
  576. break;
  577. case SaferObjectSingleIdentification:
  578. {
  579. *lpdwOutBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  580. if (ARGUMENT_PRESENT(lpQueryBuffer) &&
  581. dwInBufferSize >= *lpdwOutBufferSize)
  582. {
  583. PSAFER_IDENTIFICATION_HEADER pIdentCommonHeader =
  584. (PSAFER_IDENTIFICATION_HEADER) lpQueryBuffer;
  585. if (pIdentCommonHeader->cbStructSize < *lpdwOutBufferSize) {
  586. // the caller claimed that the dwInBufferSize was
  587. // large enough, but the common header size doesn't.
  588. goto ExitBufferTooSmall;
  589. }
  590. if (IsZeroGUID(&pIdentCommonHeader->IdentificationGuid))
  591. {
  592. //
  593. // Caller supplied a zero GUID and wants to retrieve
  594. // the rule that produced the SaferIdentifyLevel
  595. // result match, if this Level handle was from it.
  596. //
  597. if (IsZeroGUID(&pAuthzLevelStruct->identGuid)) {
  598. // This was a handle that was explicitly opened
  599. // by the user with SaferCreateLevel().
  600. Status = STATUS_NOT_FOUND;
  601. goto ExitHandler;
  602. }
  603. pSingleIdentRecord = CodeAuthzIdentsLookupByGuid(
  604. &g_CodeIdentitiesTable,
  605. &pAuthzLevelStruct->identGuid);
  606. if (!pSingleIdentRecord) {
  607. // This handle was obtained via a match to one of
  608. // the special GUIDs or an code identity GUID
  609. // that no longer exists. Just return a blank
  610. // structure with just the GUID in the header.
  611. *lpdwOutBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  612. break;
  613. }
  614. } else {
  615. //
  616. // Caller is explicitly supplying the GUID of the
  617. // code identifier rule that details should be
  618. // retrieved for.
  619. //
  620. pSingleIdentRecord = CodeAuthzIdentsLookupByGuid(
  621. &g_CodeIdentitiesTable,
  622. &pIdentCommonHeader->IdentificationGuid);
  623. }
  624. //
  625. // We now have a pointer to the identity record that
  626. // information should be retrieved for. Perform the
  627. // necessary work to marshal back the details about it.
  628. //
  629. if (!pSingleIdentRecord ||
  630. pSingleIdentRecord->dwLevelId !=
  631. pAuthzLevelRecord->dwLevelId ||
  632. pSingleIdentRecord->dwScopeId != dwHandleScopeId)
  633. {
  634. Status = STATUS_NOT_FOUND;
  635. goto ExitHandler;
  636. }
  637. switch (pSingleIdentRecord->dwIdentityType) {
  638. case SaferIdentityTypeImageName:
  639. // Size is calculated later on.
  640. *lpdwOutBufferSize = 0;
  641. break;
  642. case SaferIdentityTypeImageHash:
  643. *lpdwOutBufferSize = sizeof(SAFER_HASH_IDENTIFICATION);
  644. break;
  645. case SaferIdentityTypeUrlZone:
  646. *lpdwOutBufferSize = sizeof(SAFER_URLZONE_IDENTIFICATION);
  647. break;
  648. default:
  649. Status = STATUS_NOT_FOUND;
  650. goto ExitHandler;
  651. }
  652. }
  653. break;
  654. }
  655. case SaferObjectExtendedError:
  656. *lpdwOutBufferSize = sizeof(DWORD);
  657. break;
  658. default:
  659. Status = STATUS_INVALID_INFO_CLASS;
  660. goto ExitHandler;
  661. }
  662. //ASSERTMSG("required buffer size must be computed", *lpdwOutBufferSize != 0);
  663. //
  664. // If there is not enough space for the query, then return with error.
  665. //
  666. if (*lpdwOutBufferSize != -1 &&
  667. (!ARGUMENT_PRESENT(lpQueryBuffer) ||
  668. dwInBufferSize < *lpdwOutBufferSize) )
  669. {
  670. ExitBufferTooSmall:
  671. Status = STATUS_BUFFER_TOO_SMALL;
  672. goto ExitHandler;
  673. }
  674. //
  675. // Otherwise there is enough space for the request buffer,
  676. // so now actually perform the copy.
  677. //
  678. switch (dwInfoType)
  679. {
  680. case SaferObjectLevelId: // DWORD
  681. *(PDWORD)lpQueryBuffer = pAuthzLevelRecord->dwLevelId;
  682. break;
  683. case SaferObjectScopeId: // DWORD
  684. *(PDWORD)lpQueryBuffer = dwHandleScopeId;
  685. break;
  686. case SaferObjectBuiltin: // DWORD boolean
  687. *((LPDWORD)lpQueryBuffer) =
  688. (pAuthzLevelRecord->Builtin ? TRUE : FALSE);
  689. break;
  690. case SaferObjectExtendedError:
  691. *((DWORD *)lpQueryBuffer) = pAuthzLevelStruct->dwExtendedError;
  692. break;
  693. case SaferObjectFriendlyName: // LPCTSTR
  694. RtlCopyMemory(lpQueryBuffer,
  695. pAuthzLevelRecord->UnicodeFriendlyName.Buffer,
  696. pAuthzLevelRecord->UnicodeFriendlyName.Length);
  697. ((LPWSTR) lpQueryBuffer)[
  698. pAuthzLevelRecord->UnicodeFriendlyName.Length /
  699. sizeof(WCHAR) ] = UNICODE_NULL;
  700. *lpdwOutBufferSize =
  701. pAuthzLevelRecord->UnicodeFriendlyName.Length +
  702. sizeof(UNICODE_NULL);
  703. break;
  704. case SaferObjectDescription: // LPCTSTR
  705. RtlCopyMemory(lpQueryBuffer,
  706. pAuthzLevelRecord->UnicodeDescription.Buffer,
  707. pAuthzLevelRecord->UnicodeDescription.Length);
  708. ((LPWSTR) lpQueryBuffer)[
  709. pAuthzLevelRecord->UnicodeDescription.Length /
  710. sizeof(WCHAR)] = UNICODE_NULL;
  711. *lpdwOutBufferSize =
  712. pAuthzLevelRecord->UnicodeDescription.Length +
  713. sizeof(UNICODE_NULL);
  714. break;
  715. #ifdef ALLOW_FULL_WINSAFER
  716. case SaferObjectDisallowed: // DWORD boolean
  717. *((LPDWORD)lpQueryBuffer) = (pAuthzLevelRecord->DisallowExecution != 0) ? TRUE : FALSE;
  718. break;
  719. case SaferObjectDisableMaxPrivilege: // DWORD boolean
  720. *((LPDWORD)lpQueryBuffer) = (pAuthzLevelRecord->Flags & DISABLE_MAX_PRIVILEGE) != 0;
  721. break;
  722. case SaferObjectInvertDeletedPrivileges: // DWORD boolean
  723. *((LPDWORD)lpQueryBuffer) = (pAuthzLevelRecord->InvertDeletePrivs != 0) ? TRUE : FALSE;
  724. break;
  725. case SaferObjectDeletedPrivileges: // TOKEN_PRIVILEGES
  726. {
  727. PTOKEN_PRIVILEGES pTokenPrivs = (PTOKEN_PRIVILEGES) lpQueryBuffer;
  728. pTokenPrivs->PrivilegeCount = pAuthzLevelRecord->DeletePrivilegeUsedCount;
  729. RtlCopyMemory(&pTokenPrivs->Privileges[0],
  730. &pAuthzLevelRecord->PrivilegesToDelete[0],
  731. sizeof(LUID_AND_ATTRIBUTES) * pAuthzLevelRecord->DeletePrivilegeUsedCount);
  732. break;
  733. }
  734. case SaferObjectDefaultOwner: // TOKEN_OWNER
  735. {
  736. PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) lpQueryBuffer;
  737. if (pAuthzLevelRecord->DefaultOwner == NULL)
  738. pTokenOwner->Owner = NULL;
  739. else {
  740. pTokenOwner->Owner = (PSID) &pTokenOwner[1];
  741. Status = RtlCopySid(dwInBufferSize - sizeof(TOKEN_OWNER),
  742. pTokenOwner->Owner, pAuthzLevelRecord->DefaultOwner);
  743. ASSERT(NT_SUCCESS(Status));
  744. }
  745. break;
  746. }
  747. case SaferObjectSidsToDisable: // TOKEN_GROUPS (wildcard sids)
  748. {
  749. PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS) lpQueryBuffer;
  750. DWORD dwUsedOffset = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  751. (sizeof(SID_AND_ATTRIBUTES) * pAuthzLevelRecord->DisableSidUsedCount);
  752. pTokenGroups->GroupCount = pAuthzLevelRecord->DisableSidUsedCount;
  753. for (Index = 0; Index < pAuthzLevelRecord->DisableSidUsedCount; Index++) {
  754. pTokenGroups->Groups[Index].Sid = (PSID) &((LPBYTE)lpQueryBuffer)[dwUsedOffset];
  755. DWORD dwSidLength = RtlLengthSid(pAuthzLevelRecord->SidsToDisable[Index].Sid);
  756. ASSERT(dwUsedOffset + dwSidLength <= dwInBufferSize);
  757. RtlCopyMemory(pTokenGroups->Groups[Index].Sid,
  758. pAuthzLevelRecord->SidsToDisable[Index].Sid, dwSidLength);
  759. dwUsedOffset += dwSidLength;
  760. //BLACKCOMB TODO: handle wildcard sids differently?
  761. if (pAuthzLevelRecord->SidsToDisable[Index].WildcardPos == -1)
  762. pTokenGroups->Groups[Index].Attributes = 0;
  763. else
  764. pTokenGroups->Groups[Index].Attributes = (((DWORD) '*') << 24) |
  765. (pAuthzLevelRecord->SidsToDisable[Index].WildcardPos & 0x0000FFFF);
  766. }
  767. break;
  768. }
  769. case SaferObjectRestrictedSidsInverted: // TOKEN_GROUPS (wildcard sids)
  770. {
  771. PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS) lpQueryBuffer;
  772. DWORD dwUsedOffset = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  773. (sizeof(SID_AND_ATTRIBUTES) * pAuthzLevelRecord->RestrictedSidsInvUsedCount);
  774. pTokenGroups->GroupCount = pAuthzLevelRecord->RestrictedSidsInvUsedCount;
  775. for (Index = 0; Index < pAuthzLevelRecord->RestrictedSidsInvUsedCount; Index++) {
  776. pTokenGroups->Groups[Index].Sid = (PSID) &((LPBYTE)lpQueryBuffer)[dwUsedOffset];
  777. DWORD dwSidLength = RtlLengthSid(pAuthzLevelRecord->RestrictedSidsInv[Index].Sid);
  778. ASSERT(dwUsedOffset + dwSidLength <= dwInBufferSize);
  779. RtlCopyMemory(pTokenGroups->Groups[Index].Sid,
  780. pAuthzLevelRecord->RestrictedSidsInv[Index].Sid, dwSidLength);
  781. dwUsedOffset += dwSidLength;
  782. //BLACKCOMB TODO: handle wildcard sids differently?
  783. if (pAuthzLevelRecord->RestrictedSidsInv[Index].WildcardPos == -1)
  784. pTokenGroups->Groups[Index].Attributes = 0;
  785. else
  786. pTokenGroups->Groups[Index].Attributes = (((DWORD) '*') << 24) |
  787. (pAuthzLevelRecord->RestrictedSidsInv[Index].WildcardPos & 0x0000FFFF);
  788. }
  789. break;
  790. }
  791. case SaferObjectRestrictedSidsAdded: // TOKEN_GROUPS
  792. {
  793. PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS) lpQueryBuffer;
  794. DWORD dwUsedOffset = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  795. (sizeof(SID_AND_ATTRIBUTES) * pAuthzLevelRecord->RestrictedSidsAddedUsedCount);
  796. pTokenGroups->GroupCount = pAuthzLevelRecord->RestrictedSidsAddedUsedCount;
  797. for (Index = 0; Index < pAuthzLevelRecord->RestrictedSidsAddedUsedCount; Index++) {
  798. pTokenGroups->Groups[Index].Attributes = 0;
  799. pTokenGroups->Groups[Index].Sid = (PSID) &((LPBYTE)lpQueryBuffer)[dwUsedOffset];
  800. DWORD dwSidLength = RtlLengthSid(pAuthzLevelRecord->RestrictedSidsAdded[Index].Sid);
  801. ASSERT(dwUsedOffset + dwSidLength <= dwInBufferSize);
  802. RtlCopyMemory(pTokenGroups->Groups[Index].Sid,
  803. pAuthzLevelRecord->RestrictedSidsAdded[Index].Sid, dwSidLength);
  804. dwUsedOffset += dwSidLength;
  805. }
  806. break;
  807. }
  808. #endif
  809. case SaferObjectAllIdentificationGuids:
  810. Status = __CodeAuthzpFetchIdentsForLevel(
  811. dwHandleScopeId,
  812. pAuthzLevelRecord->dwLevelId,
  813. dwInBufferSize,
  814. lpQueryBuffer,
  815. lpdwOutBufferSize);
  816. if (!NT_SUCCESS(Status)) {
  817. goto ExitHandler;
  818. }
  819. break;
  820. case SaferObjectSingleIdentification:
  821. if (pSingleIdentRecord == NULL)
  822. {
  823. // One of the special identifier GUIDs is being returned,
  824. // or a no-longer existing identifier GUID.
  825. PSAFER_IDENTIFICATION_HEADER pCommon =
  826. (PSAFER_IDENTIFICATION_HEADER) lpQueryBuffer;
  827. ASSERT(*lpdwOutBufferSize == sizeof(SAFER_IDENTIFICATION_HEADER));
  828. RtlZeroMemory(pCommon, sizeof(SAFER_IDENTIFICATION_HEADER));
  829. pCommon->cbStructSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  830. RtlCopyMemory(&pCommon->IdentificationGuid,
  831. &pAuthzLevelStruct->identGuid,
  832. sizeof(GUID));
  833. }
  834. else
  835. {
  836. // Query information about a specific, existing GUID.
  837. Status = __CodeAuthzpQuerySingleIdentification(
  838. pSingleIdentRecord,
  839. lpQueryBuffer,
  840. dwInBufferSize,
  841. lpdwOutBufferSize
  842. );
  843. if (!NT_SUCCESS(Status)) {
  844. goto ExitHandler;
  845. }
  846. }
  847. break;
  848. default:
  849. ASSERTMSG("all info classes were not handled", 0);
  850. Status = STATUS_INVALID_INFO_CLASS;
  851. goto ExitHandler;
  852. }
  853. Status = STATUS_SUCCESS;
  854. //
  855. // Cleanup and epilogue code.
  856. //
  857. ExitHandler:
  858. return Status;
  859. }
  860. BOOL WINAPI
  861. SaferGetLevelInformation(
  862. IN SAFER_LEVEL_HANDLE LevelHandle,
  863. IN SAFER_OBJECT_INFO_CLASS dwInfoType,
  864. OUT LPVOID lpQueryBuffer OPTIONAL ,
  865. IN DWORD dwInBufferSize,
  866. OUT LPDWORD lpdwOutBufferSize
  867. )
  868. /*++
  869. Routine Description:
  870. Allows the user to query various pieces of information about a
  871. given AuthzObject handle.
  872. Arguments:
  873. LevelHandle - the handle to the authorization object to evaluate.
  874. dwInfoType - specifies the type of information being requested.
  875. lpQueryBuffer - pointer to a user-supplied memory buffer that
  876. will receive the requested information.
  877. dwInBufferSize - specifies the size of the user's memory block.
  878. lpdwOutBufferSize - receives the used size of the data within the
  879. memory block, or the minimum necessary size if the passed
  880. buffer was too small.
  881. Return Value:
  882. Returns FALSE on error, otherwise success.
  883. --*/
  884. {
  885. NTSTATUS Status;
  886. if (!g_bInitializedFirstTime) {
  887. Status = STATUS_UNSUCCESSFUL;
  888. goto ExitHandler;
  889. }
  890. if (!ARGUMENT_PRESENT(lpdwOutBufferSize)) {
  891. Status = STATUS_INVALID_PARAMETER;
  892. goto ExitHandler;
  893. }
  894. RtlEnterCriticalSection(&g_TableCritSec);
  895. Status = __CodeAuthzpGetAuthzLevelInfo(
  896. LevelHandle, dwInfoType,
  897. lpQueryBuffer, dwInBufferSize,
  898. lpdwOutBufferSize);
  899. RtlLeaveCriticalSection(&g_TableCritSec);
  900. if (NT_SUCCESS(Status))
  901. return TRUE;
  902. ExitHandler:
  903. BaseSetLastNTError(Status);
  904. return FALSE;
  905. }