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.

1168 lines
40 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. static HMODULE hAdvApiInst = NULL;
  487. BOOL bUnicodeInitialized = FALSE;
  488. UNICODE_STRING UnicodeName = {0};
  489. BOOL b = FALSE;
  490. //
  491. // Obtain a pointer to the authorization Level structure.
  492. //
  493. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  494. Status = CodeAuthzHandleToLevelStruct(hLevelHandle, &pAuthzLevelStruct);
  495. if (!NT_SUCCESS(Status)) {
  496. goto ExitHandler;
  497. }
  498. ASSERT(pAuthzLevelStruct != NULL);
  499. pAuthzLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  500. &g_CodeLevelObjTable, pAuthzLevelStruct->dwLevelId);
  501. if (!pAuthzLevelRecord) {
  502. Status = STATUS_INVALID_HANDLE;
  503. goto ExitHandler;
  504. }
  505. dwHandleScopeId = pAuthzLevelStruct->dwScopeId;
  506. //
  507. // Some of the attributes are fixed size, or are known before performing
  508. // the full query against the registry. Compute their size first.
  509. //
  510. *lpdwOutBufferSize = 0;
  511. switch (dwInfoType)
  512. {
  513. case SaferObjectLevelId: // DWORD
  514. case SaferObjectScopeId: // DWORD
  515. case SaferObjectBuiltin: // DWORD boolean
  516. *lpdwOutBufferSize = sizeof(DWORD);
  517. break;
  518. case SaferObjectFriendlyName: // LPCTSTR
  519. if (hAdvApiInst == NULL)
  520. {
  521. hAdvApiInst = (HANDLE) GetModuleHandleW(L"advapi32");
  522. }
  523. if (hAdvApiInst == NULL)
  524. {
  525. Status = STATUS_NOT_FOUND;
  526. goto ExitHandler;
  527. }
  528. // load the friendly name.
  529. b = SaferpLoadUnicodeResourceString(
  530. hAdvApiInst,
  531. (UINT) (pAuthzLevelRecord->uResourceID + 0),
  532. &UnicodeName,
  533. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
  534. if (!b)
  535. {
  536. Status = STATUS_NOT_FOUND;
  537. goto ExitHandler;
  538. }
  539. bUnicodeInitialized = TRUE;
  540. *lpdwOutBufferSize = UnicodeName.Length + sizeof(UNICODE_NULL);
  541. break;
  542. case SaferObjectDescription: // LPCTSTR
  543. if (hAdvApiInst == NULL)
  544. {
  545. hAdvApiInst = (HANDLE) GetModuleHandleW(L"advapi32");
  546. }
  547. if (hAdvApiInst == NULL)
  548. {
  549. Status = STATUS_NOT_FOUND;
  550. goto ExitHandler;
  551. }
  552. // load the friendly name.
  553. b = SaferpLoadUnicodeResourceString(
  554. hAdvApiInst,
  555. (UINT) (pAuthzLevelRecord->uResourceID + 1),
  556. &UnicodeName,
  557. MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
  558. if (!b)
  559. {
  560. Status = STATUS_NOT_FOUND;
  561. goto ExitHandler;
  562. }
  563. *lpdwOutBufferSize = UnicodeName.Length + sizeof(UNICODE_NULL);
  564. break;
  565. #ifdef ALLOW_FULL_WINSAFER
  566. case SaferObjectDisallowed: // DWORD boolean
  567. case SaferObjectDisableMaxPrivilege: // DWORD boolean
  568. case SaferObjectInvertDeletedPrivileges: // DWORD boolean
  569. *lpdwOutBufferSize = sizeof(DWORD);
  570. break;
  571. case SaferObjectDeletedPrivileges: // TOKEN_PRIVILEGES
  572. *lpdwOutBufferSize = (sizeof(TOKEN_PRIVILEGES) - sizeof(LUID_AND_ATTRIBUTES)) +
  573. pAuthzLevelRecord->DeletePrivilegeUsedCount * sizeof(LUID_AND_ATTRIBUTES);
  574. break;
  575. case SaferObjectDefaultOwner: // TOKEN_OWNER
  576. *lpdwOutBufferSize = sizeof(TOKEN_OWNER);
  577. if (pAuthzLevelRecord->DefaultOwner != NULL)
  578. *lpdwOutBufferSize += RtlLengthSid(pAuthzLevelRecord->DefaultOwner);
  579. break;
  580. case SaferObjectSidsToDisable: // TOKEN_GROUPS
  581. *lpdwOutBufferSize = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  582. pAuthzLevelRecord->DisableSidUsedCount * sizeof(SID_AND_ATTRIBUTES);
  583. for (Index = 0; Index < pAuthzLevelRecord->DisableSidUsedCount; Index++)
  584. *lpdwOutBufferSize += RtlLengthSid(pAuthzLevelRecord->SidsToDisable[Index].Sid);
  585. break;
  586. case SaferObjectRestrictedSidsInverted: // TOKEN_GROUPS
  587. *lpdwOutBufferSize = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  588. pAuthzLevelRecord->RestrictedSidsInvUsedCount * sizeof(SID_AND_ATTRIBUTES);
  589. for (Index = 0; Index < pAuthzLevelRecord->RestrictedSidsInvUsedCount; Index++)
  590. *lpdwOutBufferSize += RtlLengthSid(pAuthzLevelRecord->RestrictedSidsInv[Index].Sid);
  591. break;
  592. case SaferObjectRestrictedSidsAdded: // TOKEN_GROUPS
  593. *lpdwOutBufferSize = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  594. pAuthzLevelRecord->RestrictedSidsAddedUsedCount * sizeof(SID_AND_ATTRIBUTES);
  595. for (Index = 0; Index < pAuthzLevelRecord->RestrictedSidsAddedUsedCount; Index++)
  596. *lpdwOutBufferSize += RtlLengthSid(pAuthzLevelRecord->RestrictedSidsAdded[Index].Sid);
  597. break;
  598. #endif
  599. case SaferObjectAllIdentificationGuids:
  600. *lpdwOutBufferSize = sizeof(GUID) *
  601. __CodeAuthzpCountIdentsForLevel(
  602. dwHandleScopeId,
  603. pAuthzLevelRecord->dwLevelId);
  604. if (!*lpdwOutBufferSize) {
  605. Status = STATUS_NOT_FOUND;
  606. goto ExitHandler;
  607. }
  608. break;
  609. case SaferObjectSingleIdentification:
  610. {
  611. *lpdwOutBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  612. if (ARGUMENT_PRESENT(lpQueryBuffer) &&
  613. dwInBufferSize >= *lpdwOutBufferSize)
  614. {
  615. PSAFER_IDENTIFICATION_HEADER pIdentCommonHeader =
  616. (PSAFER_IDENTIFICATION_HEADER) lpQueryBuffer;
  617. if (pIdentCommonHeader->cbStructSize < *lpdwOutBufferSize) {
  618. // the caller claimed that the dwInBufferSize was
  619. // large enough, but the common header size doesn't.
  620. goto ExitBufferTooSmall;
  621. }
  622. if (IsZeroGUID(&pIdentCommonHeader->IdentificationGuid))
  623. {
  624. //
  625. // Caller supplied a zero GUID and wants to retrieve
  626. // the rule that produced the SaferIdentifyLevel
  627. // result match, if this Level handle was from it.
  628. //
  629. if (IsZeroGUID(&pAuthzLevelStruct->identGuid)) {
  630. // This was a handle that was explicitly opened
  631. // by the user with SaferCreateLevel().
  632. Status = STATUS_NOT_FOUND;
  633. goto ExitHandler;
  634. }
  635. pSingleIdentRecord = CodeAuthzIdentsLookupByGuid(
  636. &g_CodeIdentitiesTable,
  637. &pAuthzLevelStruct->identGuid);
  638. if (!pSingleIdentRecord) {
  639. // This handle was obtained via a match to one of
  640. // the special GUIDs or an code identity GUID
  641. // that no longer exists. Just return a blank
  642. // structure with just the GUID in the header.
  643. *lpdwOutBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  644. break;
  645. }
  646. } else {
  647. //
  648. // Caller is explicitly supplying the GUID of the
  649. // code identifier rule that details should be
  650. // retrieved for.
  651. //
  652. pSingleIdentRecord = CodeAuthzIdentsLookupByGuid(
  653. &g_CodeIdentitiesTable,
  654. &pIdentCommonHeader->IdentificationGuid);
  655. }
  656. //
  657. // We now have a pointer to the identity record that
  658. // information should be retrieved for. Perform the
  659. // necessary work to marshal back the details about it.
  660. //
  661. if (!pSingleIdentRecord ||
  662. pSingleIdentRecord->dwLevelId !=
  663. pAuthzLevelRecord->dwLevelId ||
  664. pSingleIdentRecord->dwScopeId != dwHandleScopeId)
  665. {
  666. Status = STATUS_NOT_FOUND;
  667. goto ExitHandler;
  668. }
  669. switch (pSingleIdentRecord->dwIdentityType) {
  670. case SaferIdentityTypeImageName:
  671. // Size is calculated later on.
  672. *lpdwOutBufferSize = 0;
  673. break;
  674. case SaferIdentityTypeImageHash:
  675. *lpdwOutBufferSize = sizeof(SAFER_HASH_IDENTIFICATION);
  676. break;
  677. case SaferIdentityTypeUrlZone:
  678. *lpdwOutBufferSize = sizeof(SAFER_URLZONE_IDENTIFICATION);
  679. break;
  680. default:
  681. Status = STATUS_NOT_FOUND;
  682. goto ExitHandler;
  683. }
  684. }
  685. break;
  686. }
  687. case SaferObjectExtendedError:
  688. *lpdwOutBufferSize = sizeof(DWORD);
  689. break;
  690. default:
  691. Status = STATUS_INVALID_INFO_CLASS;
  692. goto ExitHandler;
  693. }
  694. //ASSERTMSG("required buffer size must be computed", *lpdwOutBufferSize != 0);
  695. //
  696. // If there is not enough space for the query, then return with error.
  697. //
  698. if (*lpdwOutBufferSize != -1 &&
  699. (!ARGUMENT_PRESENT(lpQueryBuffer) ||
  700. dwInBufferSize < *lpdwOutBufferSize) )
  701. {
  702. ExitBufferTooSmall:
  703. Status = STATUS_BUFFER_TOO_SMALL;
  704. goto ExitHandler;
  705. }
  706. //
  707. // Otherwise there is enough space for the request buffer,
  708. // so now actually perform the copy.
  709. //
  710. switch (dwInfoType)
  711. {
  712. case SaferObjectLevelId: // DWORD
  713. *(PDWORD)lpQueryBuffer = pAuthzLevelRecord->dwLevelId;
  714. break;
  715. case SaferObjectScopeId: // DWORD
  716. *(PDWORD)lpQueryBuffer = dwHandleScopeId;
  717. break;
  718. case SaferObjectBuiltin: // DWORD boolean
  719. *((LPDWORD)lpQueryBuffer) =
  720. (pAuthzLevelRecord->Builtin ? TRUE : FALSE);
  721. break;
  722. case SaferObjectExtendedError:
  723. *((DWORD *)lpQueryBuffer) = pAuthzLevelStruct->dwExtendedError;
  724. break;
  725. case SaferObjectFriendlyName: // LPCTSTR
  726. RtlCopyMemory(lpQueryBuffer,
  727. UnicodeName.Buffer,
  728. UnicodeName.Length);
  729. ((LPWSTR) lpQueryBuffer)[
  730. UnicodeName.Length /
  731. sizeof(WCHAR) ] = UNICODE_NULL;
  732. *lpdwOutBufferSize =
  733. UnicodeName.Length +
  734. sizeof(UNICODE_NULL);
  735. break;
  736. case SaferObjectDescription: // LPCTSTR
  737. RtlCopyMemory(lpQueryBuffer,
  738. UnicodeName.Buffer,
  739. UnicodeName.Length);
  740. ((LPWSTR) lpQueryBuffer)[UnicodeName.Length / sizeof(WCHAR)] = UNICODE_NULL;
  741. *lpdwOutBufferSize = UnicodeName.Length + sizeof(UNICODE_NULL);
  742. break;
  743. #ifdef ALLOW_FULL_WINSAFER
  744. case SaferObjectDisallowed: // DWORD boolean
  745. *((LPDWORD)lpQueryBuffer) = (pAuthzLevelRecord->DisallowExecution != 0) ? TRUE : FALSE;
  746. break;
  747. case SaferObjectDisableMaxPrivilege: // DWORD boolean
  748. *((LPDWORD)lpQueryBuffer) = (pAuthzLevelRecord->Flags & DISABLE_MAX_PRIVILEGE) != 0;
  749. break;
  750. case SaferObjectInvertDeletedPrivileges: // DWORD boolean
  751. *((LPDWORD)lpQueryBuffer) = (pAuthzLevelRecord->InvertDeletePrivs != 0) ? TRUE : FALSE;
  752. break;
  753. case SaferObjectDeletedPrivileges: // TOKEN_PRIVILEGES
  754. {
  755. PTOKEN_PRIVILEGES pTokenPrivs = (PTOKEN_PRIVILEGES) lpQueryBuffer;
  756. pTokenPrivs->PrivilegeCount = pAuthzLevelRecord->DeletePrivilegeUsedCount;
  757. RtlCopyMemory(&pTokenPrivs->Privileges[0],
  758. &pAuthzLevelRecord->PrivilegesToDelete[0],
  759. sizeof(LUID_AND_ATTRIBUTES) * pAuthzLevelRecord->DeletePrivilegeUsedCount);
  760. break;
  761. }
  762. case SaferObjectDefaultOwner: // TOKEN_OWNER
  763. {
  764. PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) lpQueryBuffer;
  765. if (pAuthzLevelRecord->DefaultOwner == NULL)
  766. pTokenOwner->Owner = NULL;
  767. else {
  768. pTokenOwner->Owner = (PSID) &pTokenOwner[1];
  769. Status = RtlCopySid(dwInBufferSize - sizeof(TOKEN_OWNER),
  770. pTokenOwner->Owner, pAuthzLevelRecord->DefaultOwner);
  771. ASSERT(NT_SUCCESS(Status));
  772. }
  773. break;
  774. }
  775. case SaferObjectSidsToDisable: // TOKEN_GROUPS (wildcard sids)
  776. {
  777. PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS) lpQueryBuffer;
  778. DWORD dwUsedOffset = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  779. (sizeof(SID_AND_ATTRIBUTES) * pAuthzLevelRecord->DisableSidUsedCount);
  780. pTokenGroups->GroupCount = pAuthzLevelRecord->DisableSidUsedCount;
  781. for (Index = 0; Index < pAuthzLevelRecord->DisableSidUsedCount; Index++) {
  782. pTokenGroups->Groups[Index].Sid = (PSID) &((LPBYTE)lpQueryBuffer)[dwUsedOffset];
  783. DWORD dwSidLength = RtlLengthSid(pAuthzLevelRecord->SidsToDisable[Index].Sid);
  784. ASSERT(dwUsedOffset + dwSidLength <= dwInBufferSize);
  785. RtlCopyMemory(pTokenGroups->Groups[Index].Sid,
  786. pAuthzLevelRecord->SidsToDisable[Index].Sid, dwSidLength);
  787. dwUsedOffset += dwSidLength;
  788. //BLACKCOMB TODO: handle wildcard sids differently?
  789. if (pAuthzLevelRecord->SidsToDisable[Index].WildcardPos == -1)
  790. pTokenGroups->Groups[Index].Attributes = 0;
  791. else
  792. pTokenGroups->Groups[Index].Attributes = (((DWORD) '*') << 24) |
  793. (pAuthzLevelRecord->SidsToDisable[Index].WildcardPos & 0x0000FFFF);
  794. }
  795. break;
  796. }
  797. case SaferObjectRestrictedSidsInverted: // TOKEN_GROUPS (wildcard sids)
  798. {
  799. PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS) lpQueryBuffer;
  800. DWORD dwUsedOffset = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  801. (sizeof(SID_AND_ATTRIBUTES) * pAuthzLevelRecord->RestrictedSidsInvUsedCount);
  802. pTokenGroups->GroupCount = pAuthzLevelRecord->RestrictedSidsInvUsedCount;
  803. for (Index = 0; Index < pAuthzLevelRecord->RestrictedSidsInvUsedCount; Index++) {
  804. pTokenGroups->Groups[Index].Sid = (PSID) &((LPBYTE)lpQueryBuffer)[dwUsedOffset];
  805. DWORD dwSidLength = RtlLengthSid(pAuthzLevelRecord->RestrictedSidsInv[Index].Sid);
  806. ASSERT(dwUsedOffset + dwSidLength <= dwInBufferSize);
  807. RtlCopyMemory(pTokenGroups->Groups[Index].Sid,
  808. pAuthzLevelRecord->RestrictedSidsInv[Index].Sid, dwSidLength);
  809. dwUsedOffset += dwSidLength;
  810. //BLACKCOMB TODO: handle wildcard sids differently?
  811. if (pAuthzLevelRecord->RestrictedSidsInv[Index].WildcardPos == -1)
  812. pTokenGroups->Groups[Index].Attributes = 0;
  813. else
  814. pTokenGroups->Groups[Index].Attributes = (((DWORD) '*') << 24) |
  815. (pAuthzLevelRecord->RestrictedSidsInv[Index].WildcardPos & 0x0000FFFF);
  816. }
  817. break;
  818. }
  819. case SaferObjectRestrictedSidsAdded: // TOKEN_GROUPS
  820. {
  821. PTOKEN_GROUPS pTokenGroups = (PTOKEN_GROUPS) lpQueryBuffer;
  822. DWORD dwUsedOffset = (sizeof(TOKEN_GROUPS) - sizeof(SID_AND_ATTRIBUTES)) +
  823. (sizeof(SID_AND_ATTRIBUTES) * pAuthzLevelRecord->RestrictedSidsAddedUsedCount);
  824. pTokenGroups->GroupCount = pAuthzLevelRecord->RestrictedSidsAddedUsedCount;
  825. for (Index = 0; Index < pAuthzLevelRecord->RestrictedSidsAddedUsedCount; Index++) {
  826. pTokenGroups->Groups[Index].Attributes = 0;
  827. pTokenGroups->Groups[Index].Sid = (PSID) &((LPBYTE)lpQueryBuffer)[dwUsedOffset];
  828. DWORD dwSidLength = RtlLengthSid(pAuthzLevelRecord->RestrictedSidsAdded[Index].Sid);
  829. ASSERT(dwUsedOffset + dwSidLength <= dwInBufferSize);
  830. RtlCopyMemory(pTokenGroups->Groups[Index].Sid,
  831. pAuthzLevelRecord->RestrictedSidsAdded[Index].Sid, dwSidLength);
  832. dwUsedOffset += dwSidLength;
  833. }
  834. break;
  835. }
  836. #endif
  837. case SaferObjectAllIdentificationGuids:
  838. Status = __CodeAuthzpFetchIdentsForLevel(
  839. dwHandleScopeId,
  840. pAuthzLevelRecord->dwLevelId,
  841. dwInBufferSize,
  842. lpQueryBuffer,
  843. lpdwOutBufferSize);
  844. if (!NT_SUCCESS(Status)) {
  845. goto ExitHandler;
  846. }
  847. break;
  848. case SaferObjectSingleIdentification:
  849. if (pSingleIdentRecord == NULL)
  850. {
  851. // One of the special identifier GUIDs is being returned,
  852. // or a no-longer existing identifier GUID.
  853. PSAFER_IDENTIFICATION_HEADER pCommon =
  854. (PSAFER_IDENTIFICATION_HEADER) lpQueryBuffer;
  855. ASSERT(*lpdwOutBufferSize == sizeof(SAFER_IDENTIFICATION_HEADER));
  856. RtlZeroMemory(pCommon, sizeof(SAFER_IDENTIFICATION_HEADER));
  857. pCommon->cbStructSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  858. RtlCopyMemory(&pCommon->IdentificationGuid,
  859. &pAuthzLevelStruct->identGuid,
  860. sizeof(GUID));
  861. }
  862. else
  863. {
  864. // Query information about a specific, existing GUID.
  865. Status = __CodeAuthzpQuerySingleIdentification(
  866. pSingleIdentRecord,
  867. lpQueryBuffer,
  868. dwInBufferSize,
  869. lpdwOutBufferSize
  870. );
  871. if (!NT_SUCCESS(Status)) {
  872. goto ExitHandler;
  873. }
  874. }
  875. break;
  876. default:
  877. ASSERTMSG("all info classes were not handled", 0);
  878. Status = STATUS_INVALID_INFO_CLASS;
  879. goto ExitHandler;
  880. }
  881. Status = STATUS_SUCCESS;
  882. //
  883. // Cleanup and epilogue code.
  884. //
  885. ExitHandler:
  886. if (bUnicodeInitialized)
  887. {
  888. RtlFreeUnicodeString(&UnicodeName);
  889. }
  890. return Status;
  891. }
  892. BOOL WINAPI
  893. SaferGetLevelInformation(
  894. IN SAFER_LEVEL_HANDLE LevelHandle,
  895. IN SAFER_OBJECT_INFO_CLASS dwInfoType,
  896. OUT LPVOID lpQueryBuffer OPTIONAL ,
  897. IN DWORD dwInBufferSize,
  898. OUT LPDWORD lpdwOutBufferSize
  899. )
  900. /*++
  901. Routine Description:
  902. Allows the user to query various pieces of information about a
  903. given AuthzObject handle.
  904. Arguments:
  905. LevelHandle - the handle to the authorization object to evaluate.
  906. dwInfoType - specifies the type of information being requested.
  907. lpQueryBuffer - pointer to a user-supplied memory buffer that
  908. will receive the requested information.
  909. dwInBufferSize - specifies the size of the user's memory block.
  910. lpdwOutBufferSize - receives the used size of the data within the
  911. memory block, or the minimum necessary size if the passed
  912. buffer was too small.
  913. Return Value:
  914. Returns FALSE on error, otherwise success.
  915. --*/
  916. {
  917. NTSTATUS Status;
  918. if (!g_bInitializedFirstTime) {
  919. Status = STATUS_UNSUCCESSFUL;
  920. goto ExitHandler;
  921. }
  922. if (!ARGUMENT_PRESENT(lpdwOutBufferSize)) {
  923. Status = STATUS_INVALID_PARAMETER;
  924. goto ExitHandler;
  925. }
  926. RtlEnterCriticalSection(&g_TableCritSec);
  927. Status = __CodeAuthzpGetAuthzLevelInfo(
  928. LevelHandle, dwInfoType,
  929. lpQueryBuffer, dwInBufferSize,
  930. lpdwOutBufferSize);
  931. RtlLeaveCriticalSection(&g_TableCritSec);
  932. if (NT_SUCCESS(Status))
  933. return TRUE;
  934. ExitHandler:
  935. BaseSetLastNTError(Status);
  936. return FALSE;
  937. }