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.

2577 lines
88 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. SafeIden.c (WinSAFER SaferIdentifyLevel)
  5. Abstract:
  6. This module implements the WinSAFER APIs that evaluate the system
  7. policies to determine which Authorization Level has been configured
  8. to apply restrictions for a specified application or code library.
  9. Author:
  10. Jeffrey Lawson (JLawson) - Nov 1999
  11. Environment:
  12. User mode only.
  13. Exported Functions:
  14. SaferiSearchMatchingHashRules (privately exported)
  15. SaferIdentifyLevel
  16. Revision History:
  17. Created - Nov 1999
  18. --*/
  19. #include "pch.h"
  20. #pragma hdrstop
  21. #include <md5.h>
  22. #include <wchar.h> //for swprintf
  23. #pragma warning(push, 3)
  24. #include <wintrust.h> // WinVerifyTrust
  25. #include <softpub.h> // WINTRUST_ACTION_GENERIC_VERIFY_V2
  26. #pragma warning(pop)
  27. #include <winsafer.h>
  28. #include <winsaferp.h>
  29. #include "saferp.h"
  30. #define EXPAND_REGPATH
  31. //#define VERBOSE_IDENTIFICATIONS
  32. #ifdef VERBOSE_IDENTIFICATIONS
  33. #define OUTPUTDEBUGSTRING(v) OutputDebugStringW(v)
  34. #else
  35. #define OUTPUTDEBUGSTRING(v)
  36. #endif
  37. const static GUID guidTrustedCert = SAFER_GUID_RESULT_TRUSTED_CERT;
  38. const static GUID guidDefaultRule = SAFER_GUID_RESULT_DEFAULT_LEVEL;
  39. NTSTATUS NTAPI
  40. __CodeAuthzpEnsureMapped(
  41. IN OUT PLOCALIDENTITYCONTEXT pIdentContext
  42. )
  43. /*++
  44. Routine Description:
  45. Evaluates the supplied identification context structure and
  46. attempts to gain access to a mapped memory region of the entity
  47. being identified. It does the following steps:
  48. 1) if the identification context already has a non-NULL memory
  49. pointer then returns successfully.
  50. 2) if the identification context has a non-NULL file handle
  51. then that handle is memory mapped into memory and
  52. returns successfully.
  53. 3) if the identification context has a non-NULL image filename
  54. then that filename is opened for read access and memory
  55. mapped into memory.
  56. Otherwise the function call is not successful.
  57. The caller must be sure to call CodeAuthzpEnsureUnmapped later.
  58. Arguments:
  59. pIdentContext = pointer to the identification context structure.
  60. After this function call succeeds, the caller can assume
  61. that pIdentContext->pImageMemory and pIdentContext->ImageSize
  62. are valid and can be used.
  63. Return Value:
  64. Returns STATUS_SUCCESS if a memory-mapped image pointer and size
  65. are now available, otherwise a failure occurred trying to map them.
  66. --*/
  67. {
  68. HANDLE hMapping;
  69. ASSERT(ARGUMENT_PRESENT(pIdentContext) &&
  70. pIdentContext->CodeProps != NULL);
  71. if (pIdentContext->pImageMemory == NULL ||
  72. pIdentContext->ImageSize.QuadPart == 0)
  73. {
  74. //
  75. // If a memory pointer and imagesize were supplied to us
  76. // in the CodeProperties, then just use them directly.
  77. //
  78. if (pIdentContext->CodeProps->ImageSize.QuadPart != 0 &&
  79. pIdentContext->CodeProps->pByteBlock != NULL)
  80. {
  81. pIdentContext->pImageMemory =
  82. pIdentContext->CodeProps->pByteBlock;
  83. pIdentContext->ImageSize.QuadPart =
  84. pIdentContext->CodeProps->ImageSize.QuadPart;
  85. pIdentContext->bImageMemoryNeedUnmap = FALSE;
  86. return STATUS_SUCCESS;
  87. }
  88. //
  89. // Ensure that we have an open file handle, by using the
  90. // handle supplied to us in the CodeProperties if possible,
  91. // otherwise by opening the supplied ImagePath.
  92. //
  93. if (pIdentContext->hFileHandle == NULL) {
  94. // no file handle supplied.
  95. return STATUS_UNSUCCESSFUL; // failed.
  96. }
  97. //
  98. // Get the size of the file. We assume that if we had to
  99. // open the file ourself that the ImageSize cannot be used.
  100. //
  101. if (!GetFileSizeEx(pIdentContext->hFileHandle,
  102. &pIdentContext->ImageSize)) {
  103. return STATUS_UNSUCCESSFUL; // failure
  104. }
  105. if (pIdentContext->ImageSize.HighPart != 0) {
  106. //BLACKCOMB TODO: maybe later handle very large files.
  107. return STATUS_NO_MEMORY; // failure--too large.
  108. }
  109. if (pIdentContext->ImageSize.QuadPart == 0) {
  110. return STATUS_UNSUCCESSFUL; // failure--zero file size.
  111. }
  112. //
  113. // Now that we have an open file handle, open it up
  114. // as a memory-mapped file mapping.
  115. //
  116. hMapping = CreateFileMapping(
  117. pIdentContext->hFileHandle,
  118. NULL,
  119. PAGE_READONLY,
  120. (DWORD) 0, // highword zero
  121. (DWORD) pIdentContext->ImageSize.LowPart,
  122. NULL);
  123. if (hMapping == NULL || hMapping == INVALID_HANDLE_VALUE) {
  124. return STATUS_UNSUCCESSFUL;
  125. }
  126. //
  127. // View map the file into memory.
  128. //
  129. pIdentContext->pImageMemory =
  130. MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0,
  131. pIdentContext->ImageSize.LowPart);
  132. CloseHandle(hMapping);
  133. if (pIdentContext->pImageMemory == NULL) {
  134. return STATUS_UNSUCCESSFUL;
  135. }
  136. pIdentContext->bImageMemoryNeedUnmap = TRUE;
  137. }
  138. return STATUS_SUCCESS;
  139. }
  140. NTSTATUS NTAPI
  141. __CodeAuthzpEnsureUnmapped(
  142. IN OUT PLOCALIDENTITYCONTEXT pIdentContext
  143. )
  144. /*++
  145. Routine Description:
  146. Reverses the effects of __CodeAuthzEnsureMapped and closes and
  147. frees any handles that were opened to the specified file.
  148. Arguments:
  149. pIdentContext - pointer to the context structure.
  150. Return Value:
  151. Returns STATUS_SUCCESS if no errors occurred.
  152. --*/
  153. {
  154. ASSERT(pIdentContext != NULL);
  155. if (pIdentContext->bImageMemoryNeedUnmap &&
  156. pIdentContext->pImageMemory != NULL)
  157. {
  158. UnmapViewOfFile((LPCVOID) pIdentContext->pImageMemory);
  159. pIdentContext->pImageMemory = NULL;
  160. pIdentContext->bImageMemoryNeedUnmap = FALSE;
  161. }
  162. return STATUS_SUCCESS;
  163. }
  164. NTSTATUS NTAPI
  165. CodeAuthzpComputeImageHash(
  166. IN PVOID pImageMemory,
  167. IN DWORD dwImageSize,
  168. OUT PBYTE pComputedHash OPTIONAL,
  169. IN OUT PDWORD pdwHashSize OPTIONAL,
  170. OUT ALG_ID *pHashAlgorithm OPTIONAL
  171. )
  172. /*++
  173. Routine Description:
  174. Computes an MD5 image hash of a specified region of memory.
  175. Note, MD5 hashes are always 16 bytes in length.
  176. Arguments:
  177. pImageMemory - Pointer to a memory buffer to compute the hash of.
  178. dwImageSize - Total size of the pImageMemory buffer in bytes.
  179. pComputedHash - Pointer that receives the computed hash.
  180. pdwHashSize - Pointer to a DWORD value. On input, this DWORD should
  181. specify the maximum size of the pComputedHash buffer.
  182. On successful execution of this function, the length of the
  183. resulting hash is written to this pointer.
  184. pHashAlgorithm - pointer to a variable that will receive the hash
  185. algorithm that was used to compute the hash. This will
  186. always be the constant CALG_MD5.
  187. Return Value:
  188. Returns STATUS_SUCCESS on successful execution.
  189. --*/
  190. {
  191. MD5_CTX md5ctx;
  192. //
  193. // Check the validity of the arguments supplied to us.
  194. //
  195. if (!ARGUMENT_PRESENT(pImageMemory) ||
  196. dwImageSize == 0) {
  197. return STATUS_INVALID_PARAMETER;
  198. }
  199. if (!ARGUMENT_PRESENT(pComputedHash) ||
  200. !ARGUMENT_PRESENT(pdwHashSize) ||
  201. *pdwHashSize < 16) {
  202. return STATUS_BUFFER_TOO_SMALL;
  203. }
  204. //
  205. // Compute the MD5 hash of it.
  206. // (this could also be done with CryptCreateHash+CryptHashData)
  207. //
  208. MD5Init(&md5ctx);
  209. MD5Update(&md5ctx, (LPBYTE) pImageMemory, dwImageSize);
  210. MD5Final(&md5ctx);
  211. //
  212. // Copy the hash to the user's buffer.
  213. //
  214. RtlCopyMemory(pComputedHash, &md5ctx.digest[0], 16);
  215. *pdwHashSize = 16;
  216. if (ARGUMENT_PRESENT(pHashAlgorithm)) {
  217. *pHashAlgorithm = CALG_MD5;
  218. }
  219. return STATUS_SUCCESS;
  220. }
  221. NTSTATUS NTAPI
  222. __CodeAuthzpCheckIdentityPathRules(
  223. IN OUT PLOCALIDENTITYCONTEXT pIdentStruct,
  224. OUT PAUTHZLEVELTABLERECORD *pFoundLevel,
  225. OUT PBOOL pbExactMatch,
  226. OUT PAUTHZIDENTSTABLERECORD *pFoundIdentity
  227. )
  228. /*++
  229. Routine Description:
  230. Evaluates a wildcard pattern against a specified pathname and
  231. indicates if they match.
  232. Arguments:
  233. pIdentStruct -
  234. pFoundLevel - receives a pointer to the authorization Level record
  235. indicated by the best matching rule.
  236. pbExactMatch - receives a boolean value indicating if the match
  237. was against an exact fully qualified path rule.
  238. pFoundIdentity - receives a pointer to the identifier entry rule
  239. that best matched.
  240. Return Value:
  241. Returns STATUS_SUCCESS if a WinSafer Level has been found,
  242. or STATUS_NOT_FOUND if not. Otherwise an error code.
  243. --*/
  244. {
  245. NTSTATUS Status;
  246. PVOID RestartKey;
  247. UNICODE_STRING UnicodePath;
  248. WCHAR ExpandedPath[MAX_PATH];
  249. WCHAR szLongPath[MAX_PATH];
  250. PAUTHZIDENTSTABLERECORD pAuthzIdentRecord, pBestIdentRecord;
  251. PAUTHZLEVELTABLERECORD pAuthzLevelRecord;
  252. LPWSTR lpKeyname = NULL;
  253. LONG lBestLevelDepth;
  254. DWORD dwBestLevelId;
  255. BOOLEAN bFirstPass;
  256. LONG bPathIdentIsBadType = -1; // represents uninit'd state
  257. //
  258. // Verify that our input arguments all make sense.
  259. //
  260. if (!ARGUMENT_PRESENT(pIdentStruct) ||
  261. pIdentStruct->CodeProps == NULL ||
  262. !ARGUMENT_PRESENT(pFoundLevel) ||
  263. !ARGUMENT_PRESENT(pbExactMatch))
  264. {
  265. Status = STATUS_INVALID_PARAMETER;
  266. goto ExitHandler;
  267. }
  268. if ((pIdentStruct->dwCheckFlags & SAFER_CRITERIA_IMAGEPATH) == 0 ||
  269. pIdentStruct->UnicodeFullyQualfiedLongFileName.Buffer == NULL ||
  270. RtlIsGenericTableEmpty(&g_CodeIdentitiesTable))
  271. {
  272. // We're not supposed to evaluate image paths.
  273. Status = STATUS_NOT_FOUND;
  274. goto ExitHandler;
  275. }
  276. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  277. //
  278. // Enumerate through all path subkey GUIDs.
  279. //
  280. bFirstPass = TRUE;
  281. RestartKey = NULL;
  282. for (pAuthzIdentRecord = (PAUTHZIDENTSTABLERECORD)
  283. RtlEnumerateGenericTableWithoutSplaying(
  284. &g_CodeIdentitiesTable, &RestartKey);
  285. pAuthzIdentRecord != NULL;
  286. pAuthzIdentRecord = (PAUTHZIDENTSTABLERECORD)
  287. RtlEnumerateGenericTableWithoutSplaying(
  288. &g_CodeIdentitiesTable, &RestartKey)
  289. )
  290. {
  291. if (pAuthzIdentRecord->dwIdentityType ==
  292. SaferIdentityTypeImageName)
  293. {//begin reg key lookup block
  294. LONG lMatchDepth;
  295. //
  296. // Explicitly expand environmental variables.
  297. //
  298. if (pAuthzIdentRecord->ImageNameInfo.bExpandVars) {
  299. #ifdef EXPAND_REGPATH
  300. //This code attempts to expand "path" entries that are really reg keys.
  301. //For example, some paths are install dependent. These paths are commonly written into
  302. //the registry. You can specify a regkey that is a path.
  303. //For example see the following regkeys:
  304. //HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders
  305. //HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
  306. //HKEY_CURRENT_USER\Software\Microsoft\Office\9.0\Outlook\Security\OutlookSecureTempFolder
  307. {
  308. LPWSTR lpzRegKey = pAuthzIdentRecord->ImageNameInfo.ImagePath.Buffer;
  309. HKEY hKey=NULL, hKeyHive=NULL;
  310. BOOL bIsCurrentUser = FALSE;
  311. //leading percent does two things:
  312. //1. The rules created will be the Expandable String Type (REG_EXPAND_SZ)
  313. //2. Reduces the chance of a real path name conflict.
  314. LPCWSTR LP_CU_HIVE = L"%HKEY_CURRENT_USER";
  315. LPCWSTR LP_LM_HIVE = L"%HKEY_LOCAL_MACHINE";
  316. BYTE buffer[MAX_PATH *2 + 80];
  317. LPWSTR lpValue=NULL;
  318. DWORD dwBufferSize = sizeof(buffer);
  319. LPWSTR lpHivename;
  320. LPWSTR lpLastPercentSign;
  321. LONG retval;
  322. BOOL bIsRegKey=TRUE;
  323. DWORD dwKeyLength;
  324. //We expect a string like the following:
  325. //%HKEY_CURRENT_USER\Software\Microsoft\Office\9.0\Outlook\Security\OutlookSecureTempFolder%
  326. //We need to break it into three parts for the registry query:
  327. //1. The hive: HKEY_CURRENT_USER
  328. //2. The key name: Software\Microsoft\Office\9.0\Outlook\Security
  329. //3. The value name: OutlookSecureTempFolder
  330. lpKeyname=NULL;
  331. lpValue=NULL;
  332. lpHivename=NULL;
  333. lpLastPercentSign=NULL;
  334. memset(buffer, 0, dwBufferSize);
  335. lpHivename = wcsstr(lpzRegKey, LP_CU_HIVE);
  336. OUTPUTDEBUGSTRING(L"\n");
  337. OUTPUTDEBUGSTRING(L"$");
  338. OUTPUTDEBUGSTRING(lpzRegKey);
  339. OUTPUTDEBUGSTRING(L"\n");
  340. lpLastPercentSign = wcsrchr(lpzRegKey, '%');
  341. //if (lpLastPercentSign != &lpzRegKey[wcslen(lpzRegKey) - 1]) { //needs to end in a '%' as well
  342. //
  343. // we allow %key+valuename%OLK* type paths now
  344. // but there still has to be a matching %
  345. //
  346. if (!lpLastPercentSign) {
  347. bIsRegKey = FALSE;
  348. }
  349. if (bIsRegKey) {
  350. if (lpHivename != NULL) {
  351. hKeyHive = HKEY_CURRENT_USER;
  352. bIsCurrentUser = TRUE;
  353. dwKeyLength = (wcslen(&lpzRegKey[wcslen(LP_CU_HIVE)+1]) +1) * sizeof (WCHAR);
  354. lpKeyname = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, dwKeyLength);
  355. if ( lpKeyname == NULL ) {
  356. Status = STATUS_NO_MEMORY;
  357. goto ForLoopCleanup;
  358. }
  359. wcscpy(lpKeyname, &lpzRegKey[wcslen(LP_CU_HIVE)+1] );
  360. OUTPUTDEBUGSTRING(L"HKEY_CURRENT_USER");
  361. OUTPUTDEBUGSTRING(L"\n");
  362. } else {
  363. lpHivename = wcsstr(lpzRegKey, LP_LM_HIVE);
  364. if (lpHivename != NULL) {
  365. hKeyHive = HKEY_LOCAL_MACHINE;
  366. dwKeyLength = (wcslen(&lpzRegKey[wcslen(LP_LM_HIVE)+1]) +1) * sizeof (WCHAR);
  367. lpKeyname = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, dwKeyLength);
  368. if ( lpKeyname == NULL ) {
  369. Status = STATUS_NO_MEMORY;
  370. goto ForLoopCleanup;
  371. }
  372. wcscpy(lpKeyname, &lpzRegKey[wcslen(LP_LM_HIVE)+1] );
  373. OUTPUTDEBUGSTRING(L"HKEY_LOCAL_MACHINE");
  374. OUTPUTDEBUGSTRING(L"\n");
  375. } else {
  376. //The string is either a path or bogus data
  377. bIsRegKey = FALSE;
  378. }
  379. }
  380. }
  381. if (bIsRegKey) {
  382. lpValue = wcsrchr(lpKeyname, '\\');
  383. if (lpValue==NULL) {
  384. Status = STATUS_NOT_FOUND;
  385. goto ForLoopCleanup;
  386. }
  387. //Take the regkey and value and stick a null terminator in between them.
  388. *lpValue = '\0';
  389. lpValue++;
  390. //lpValue[wcslen(lpValue)-1] = '\0';
  391. //lpLastPercentSign[0] = L'\0'; //replace the final '%' char with a null terminator
  392. lpLastPercentSign = wcsrchr(lpValue, '%');
  393. if (lpLastPercentSign == NULL) {
  394. Status = STATUS_NOT_FOUND;
  395. goto ForLoopCleanup;
  396. }
  397. *lpLastPercentSign = '\0';
  398. //
  399. // Bug# 416461 - causes handle leak so use a different API
  400. // for the user hive
  401. //
  402. if ( bIsCurrentUser ) {
  403. if (retval = RegOpenCurrentUser( KEY_READ, &hKeyHive ) ) {
  404. if ( retval == ERROR_FILE_NOT_FOUND ||
  405. retval == ERROR_NOT_FOUND ||
  406. retval == ERROR_PATH_NOT_FOUND) {
  407. if (lpKeyname) {
  408. HeapFree(GetProcessHeap(), 0,lpKeyname);
  409. lpKeyname = NULL;
  410. }
  411. continue;
  412. }
  413. Status = STATUS_NOT_FOUND;
  414. goto ForLoopCleanup;
  415. }
  416. }
  417. retval = RegOpenKeyEx(hKeyHive,
  418. lpKeyname,
  419. 0,
  420. KEY_READ,
  421. &hKey);
  422. if ( bIsCurrentUser ) {
  423. RegCloseKey(hKeyHive);
  424. }
  425. if (retval)
  426. {
  427. if ( retval == ERROR_FILE_NOT_FOUND ||
  428. retval == ERROR_NOT_FOUND ||
  429. retval == ERROR_PATH_NOT_FOUND) {
  430. if (lpKeyname) {
  431. HeapFree(GetProcessHeap(), 0,lpKeyname);
  432. lpKeyname = NULL;
  433. }
  434. continue;
  435. }
  436. Status = STATUS_NOT_FOUND;
  437. goto ForLoopCleanup;
  438. } else {
  439. OUTPUTDEBUGSTRING(lpKeyname);
  440. OUTPUTDEBUGSTRING(L"\n");
  441. OUTPUTDEBUGSTRING(lpValue);
  442. OUTPUTDEBUGSTRING(L"\n");
  443. if (retval = RegQueryValueEx(hKey,
  444. lpValue,
  445. NULL,
  446. NULL,
  447. buffer,
  448. &dwBufferSize))
  449. {
  450. RegCloseKey(hKey);
  451. Status = STATUS_NOT_FOUND;
  452. goto ForLoopCleanup;
  453. } else {
  454. #ifdef VERBOSE_IDENTIFICATIONS
  455. UNICODE_STRING UnicodeDebug;
  456. WCHAR DebugBuffer[MAX_PATH*2 + 80];
  457. #endif
  458. UNICODE_STRING NewPath;
  459. PUNICODE_STRING pPathFromRule;
  460. //
  461. // if it exists, concatenate the filename after
  462. // i.e. the OLK in %HKEY\somekey\somevalue%OLK
  463. //
  464. if (lpLastPercentSign[1] != L'\0') {
  465. //
  466. // there is some stuff after %HKEY\somekey\somevalue%
  467. //
  468. if (sizeof(buffer) >
  469. ((wcslen((WCHAR*)buffer) + wcslen(lpLastPercentSign+1))* sizeof(WCHAR))) {
  470. WCHAR *pwcBuffer = (WCHAR *)buffer;
  471. if (pwcBuffer[0] != L'\0' &&
  472. pwcBuffer[wcslen(pwcBuffer)-1] != L'\\') {
  473. wcscat((WCHAR*)buffer, L"\\");
  474. }
  475. wcscat((WCHAR*)buffer, lpLastPercentSign+1);
  476. }
  477. }
  478. pPathFromRule=&(pAuthzIdentRecord->ImageNameInfo.ImagePath);
  479. NewPath.Length = (USHORT)wcslen((WCHAR*)buffer) * sizeof(WCHAR);
  480. NewPath.MaximumLength = (USHORT)wcslen((WCHAR*)buffer) * sizeof(WCHAR);
  481. NewPath.Buffer = (PWCHAR)buffer;
  482. #ifdef VERBOSE_IDENTIFICATIONS
  483. RtlInitEmptyUnicodeString(&UnicodeDebug, DebugBuffer, sizeof(DebugBuffer));
  484. swprintf(UnicodeDebug.Buffer, L"pPathFromRule(L,ML,Buffer)=(%d,%d,%s)\n",
  485. pPathFromRule->Length,
  486. pPathFromRule->MaximumLength,
  487. pPathFromRule->Buffer);
  488. OUTPUTDEBUGSTRING(UnicodeDebug.Buffer);
  489. memset(DebugBuffer, '0', sizeof(DebugBuffer));
  490. swprintf(UnicodeDebug.Buffer, L"NewPath(L,ML,Buffer)=(%d,%d,%s)\n",
  491. NewPath.Length,
  492. NewPath.MaximumLength,
  493. NewPath.Buffer);
  494. OUTPUTDEBUGSTRING(UnicodeDebug.Buffer);
  495. #endif
  496. //The new path may be bigger than the current UNICODE_STRING can store. Reallocate if necessary.
  497. if (pPathFromRule->MaximumLength >=
  498. NewPath.Length + sizeof(UNICODE_NULL)) {
  499. RtlCopyUnicodeString(
  500. pPathFromRule,
  501. &NewPath);
  502. } else {
  503. UNICODE_STRING UnicodeExpandedCopy;
  504. Status = RtlDuplicateUnicodeString(
  505. RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
  506. RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING,
  507. &NewPath,
  508. &UnicodeExpandedCopy);
  509. if (NT_SUCCESS(Status)) {
  510. RtlFreeUnicodeString(&pAuthzIdentRecord->ImageNameInfo.ImagePath);
  511. pAuthzIdentRecord->ImageNameInfo.ImagePath = UnicodeExpandedCopy;
  512. }
  513. }
  514. #ifdef VERBOSE_IDENTIFICATIONS
  515. memset(DebugBuffer, '0', sizeof(DebugBuffer));
  516. swprintf(UnicodeDebug.Buffer, L"pPathFromRule after copy(L,ML,Buffer)=(%d,%d,%s)\n",
  517. pPathFromRule->Length,
  518. pPathFromRule->MaximumLength,
  519. pPathFromRule->Buffer);
  520. OUTPUTDEBUGSTRING(UnicodeDebug.Buffer);
  521. #endif
  522. }
  523. }
  524. RegCloseKey(hKey);
  525. }
  526. if (lpKeyname) {
  527. HeapFree(GetProcessHeap(), 0,lpKeyname);
  528. lpKeyname = NULL;
  529. }
  530. } //end reg key lookup block
  531. #endif
  532. // Attempt to expand now.
  533. RtlInitEmptyUnicodeString(
  534. &UnicodePath,
  535. &ExpandedPath[0],
  536. sizeof(ExpandedPath) );
  537. Status = RtlExpandEnvironmentStrings_U(
  538. NULL, // environment
  539. &pAuthzIdentRecord->ImageNameInfo.ImagePath, // unexpanded path
  540. &UnicodePath, // resulting path
  541. NULL); // needed buffer size.
  542. if (!NT_SUCCESS(Status)) {
  543. // Failed to expand environment strings.
  544. continue;
  545. }
  546. // Perf optimization: If the expansion was successful,
  547. // update the table to keep the expanded version, eliminating
  548. // the need to expand the string for any future comparisons.
  549. if (pAuthzIdentRecord->ImageNameInfo.ImagePath.MaximumLength >=
  550. UnicodePath.Length + sizeof(UNICODE_NULL)) {
  551. RtlCopyUnicodeString(
  552. &pAuthzIdentRecord->ImageNameInfo.ImagePath,
  553. &UnicodePath);
  554. pAuthzIdentRecord->ImageNameInfo.bExpandVars = FALSE;
  555. } else {
  556. UNICODE_STRING UnicodeExpandedCopy;
  557. Status = RtlDuplicateUnicodeString(
  558. RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
  559. RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING,
  560. &UnicodePath,
  561. &UnicodeExpandedCopy);
  562. if (NT_SUCCESS(Status)) {
  563. RtlFreeUnicodeString(
  564. &pAuthzIdentRecord->ImageNameInfo.ImagePath);
  565. pAuthzIdentRecord->ImageNameInfo.ImagePath =
  566. UnicodeExpandedCopy;
  567. pAuthzIdentRecord->ImageNameInfo.bExpandVars = FALSE;
  568. }
  569. }
  570. } else {
  571. UnicodePath.Buffer = pAuthzIdentRecord->ImageNameInfo.ImagePath.Buffer;
  572. UnicodePath.Length = pAuthzIdentRecord->ImageNameInfo.ImagePath.Length;
  573. UnicodePath.MaximumLength = pAuthzIdentRecord->ImageNameInfo.ImagePath.MaximumLength;
  574. }
  575. //
  576. // Attempt short -> long filename expansion (if there is a need)
  577. //
  578. szLongPath[0] = L'\0';
  579. //
  580. // unicode buffer is guaranteed to be < MAX_PATH
  581. //
  582. wcsncpy(szLongPath,
  583. pAuthzIdentRecord->ImageNameInfo.ImagePath.Buffer,
  584. pAuthzIdentRecord->ImageNameInfo.ImagePath.Length/sizeof(WCHAR));
  585. szLongPath[pAuthzIdentRecord->ImageNameInfo.ImagePath.Length/sizeof(WCHAR)] = L'\0';
  586. if ( wcschr(szLongPath, L'~') ) {
  587. if (!GetLongPathNameW(szLongPath,
  588. szLongPath,
  589. sizeof(szLongPath) / sizeof(WCHAR))) {
  590. Status = STATUS_VARIABLE_NOT_FOUND;
  591. continue;
  592. }
  593. RtlInitUnicodeString(&UnicodePath, szLongPath);
  594. if (pAuthzIdentRecord->ImageNameInfo.ImagePath.MaximumLength >=
  595. UnicodePath.Length + sizeof(UNICODE_NULL)) {
  596. RtlCopyUnicodeString(
  597. &pAuthzIdentRecord->ImageNameInfo.ImagePath,
  598. &UnicodePath);
  599. } else {
  600. UNICODE_STRING UnicodeExpandedCopy;
  601. Status = RtlDuplicateUnicodeString(
  602. RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE |
  603. RTL_DUPLICATE_UNICODE_STRING_ALLOCATE_NULL_STRING,
  604. &UnicodePath,
  605. &UnicodeExpandedCopy);
  606. if (NT_SUCCESS(Status)) {
  607. RtlFreeUnicodeString(
  608. &pAuthzIdentRecord->ImageNameInfo.ImagePath);
  609. pAuthzIdentRecord->ImageNameInfo.ImagePath =
  610. UnicodeExpandedCopy;
  611. }
  612. }
  613. }
  614. //
  615. // Compute the quality of which the wildcard path identity
  616. // matches the ImagePath property we were asked to evaluate.
  617. //
  618. ASSERT(UnicodePath.Buffer[UnicodePath.Length / sizeof(WCHAR)] == UNICODE_NULL);
  619. ASSERT(pIdentStruct->UnicodeFullyQualfiedLongFileName.Buffer[
  620. pIdentStruct->UnicodeFullyQualfiedLongFileName.Length / sizeof(WCHAR)] == UNICODE_NULL);
  621. lMatchDepth = CodeAuthzpCompareImagePath(UnicodePath.Buffer,
  622. pIdentStruct->UnicodeFullyQualfiedLongFileName.Buffer);
  623. if (!lMatchDepth) continue;
  624. //
  625. // If this path identity is configured to only apply to
  626. // file extensions on the "bad list" then check to see if
  627. // the ImagePath specifies one of the bad extensions.
  628. //
  629. #ifdef AUTHZPOL_SAFERFLAGS_ONLY_EXES
  630. if (lMatchDepth > 0 &&
  631. (pAuthzIdentRecord->ImageNameInfo.dwSaferFlags &
  632. AUTHZPOL_SAFERFLAGS_ONLY_EXES) != 0)
  633. {
  634. if (bPathIdentIsBadType == -1) {
  635. BOOLEAN bResult;
  636. Status = CodeAuthzIsExecutableFileType(
  637. &pIdentStruct->UnicodeFullyQualfiedLongFileName, FALSE,
  638. &bResult );
  639. if (!NT_SUCCESS(Status) || !bResult) {
  640. bPathIdentIsBadType = FALSE;
  641. } else {
  642. bPathIdentIsBadType = TRUE;
  643. }
  644. }
  645. if (!bPathIdentIsBadType) {
  646. // This identity matches against only the "bad"
  647. // extensions, so pretend that this didn't match.
  648. continue;
  649. }
  650. }
  651. #endif
  652. //
  653. // Emit some diagnostic debugging code to show the result
  654. // of all of the path evaluations and their match depths.
  655. //
  656. #ifdef VERBOSE_IDENTIFICATIONS
  657. {
  658. UNICODE_STRING UnicodeDebug;
  659. WCHAR DebugBuffer[MAX_PATH*2 + 80];
  660. // sprintf is for wimps.
  661. RtlInitEmptyUnicodeString(&UnicodeDebug, DebugBuffer, sizeof(DebugBuffer));
  662. RtlAppendUnicodeToString(&UnicodeDebug, L"Safer pattern ");
  663. RtlAppendUnicodeStringToString(&UnicodeDebug, &UnicodePath);
  664. RtlAppendUnicodeToString(&UnicodeDebug, L" matched ");
  665. RtlAppendUnicodeStringToString(&UnicodeDebug, &(pIdentStruct->UnicodeFullyQualfiedLongFileName));
  666. RtlAppendUnicodeToString(&UnicodeDebug, L" with value ");
  667. UnicodeDebug.Buffer += UnicodeDebug.Length / sizeof(WCHAR);
  668. UnicodeDebug.MaximumLength -= UnicodeDebug.Length;
  669. RtlIntegerToUnicodeString(lMatchDepth, 10, &UnicodeDebug);
  670. RtlAppendUnicodeToString(&UnicodeDebug, L"\n");
  671. OUTPUTDEBUGSTRING(DebugBuffer);
  672. }
  673. #endif
  674. //
  675. // Evaluate if this path identity matches better than whatever
  676. // best path identity that we previously had, and keep it if so.
  677. //
  678. if (lMatchDepth < 0) // an exact fully-qualified path!
  679. {
  680. if (bFirstPass ||
  681. lBestLevelDepth >= 0 ||
  682. pAuthzIdentRecord->dwLevelId < dwBestLevelId)
  683. {
  684. pBestIdentRecord = pAuthzIdentRecord;
  685. dwBestLevelId = pAuthzIdentRecord->dwLevelId;
  686. lBestLevelDepth = lMatchDepth;
  687. bFirstPass = FALSE;
  688. }
  689. }
  690. else // an inexact leading prefix path match.
  691. {
  692. ASSERT(lMatchDepth > 0);
  693. if (bFirstPass ||
  694. (lBestLevelDepth >= 0 &&
  695. (lMatchDepth > lBestLevelDepth ||
  696. (lMatchDepth == lBestLevelDepth &&
  697. pAuthzIdentRecord->dwLevelId < dwBestLevelId)
  698. )
  699. )
  700. )
  701. {
  702. pBestIdentRecord = pAuthzIdentRecord;
  703. dwBestLevelId = pAuthzIdentRecord->dwLevelId;
  704. lBestLevelDepth = lMatchDepth;
  705. bFirstPass = FALSE;
  706. }
  707. }
  708. ForLoopCleanup:
  709. if (lpKeyname)
  710. {
  711. HeapFree(GetProcessHeap(), 0,lpKeyname);
  712. lpKeyname = NULL;
  713. }
  714. }
  715. }
  716. //
  717. // If we have identified a matching WinSafer Level then
  718. // look up the Level record for it and return success.
  719. //
  720. if (bFirstPass) {
  721. Status = STATUS_NOT_FOUND;
  722. goto ExitHandler;
  723. }
  724. pAuthzLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  725. &g_CodeLevelObjTable, dwBestLevelId);
  726. if (!pAuthzLevelRecord) {
  727. Status = STATUS_NOT_FOUND;
  728. goto ExitHandler;
  729. }
  730. *pFoundLevel = pAuthzLevelRecord;
  731. *pbExactMatch = (lBestLevelDepth < 0 ? TRUE : FALSE);
  732. *pFoundIdentity = pBestIdentRecord;
  733. Status = STATUS_SUCCESS;
  734. ExitHandler:
  735. if (lpKeyname)
  736. HeapFree(GetProcessHeap(), 0,lpKeyname);
  737. return Status;
  738. }
  739. NTSTATUS NTAPI
  740. __CodeAuthzpCheckIdentityCertificateRules(
  741. IN OUT PLOCALIDENTITYCONTEXT pIdentStruct,
  742. OUT DWORD *dwExtendedError,
  743. OUT PAUTHZLEVELTABLERECORD *pFoundLevel,
  744. IN DWORD dwUIChoice
  745. )
  746. /*++
  747. Routine Description:
  748. Calls WinVerifyTrust to determine the trust level of the code
  749. signer that has signed a piece of code.
  750. Arguments:
  751. pIdentStruct - context state structure.
  752. dwExtendedError - To return extended error returned by WinVerifyTrust.
  753. pFoundLevel - receives a pointer to the authorization Level record
  754. indicated by the best matching rule.
  755. dwUIChoice - optionally specifies the amount of UI that WinVerifyTrust
  756. is allowed to display. If this argument is 0, then it is treated
  757. as if WTD_UI_ALL had been supplied.
  758. Return Value:
  759. Returns STATUS_SUCCESS if a WinSafer Level has been found,
  760. or STATUS_RETRY if the publisher was unknown and UIflags blocked prompting,
  761. or STATUS_NOT_FOUND if not. Otherwise an error code.
  762. --*/
  763. {
  764. NTSTATUS Status;
  765. PAUTHZLEVELTABLERECORD pLevelRecord;
  766. GUID wvtFileActionID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
  767. WINTRUST_FILE_INFO wvtFileInfo;
  768. WINTRUST_DATA wvtData;
  769. LONG lStatus;
  770. DWORD dwLastError;
  771. DWORD LocalHandleSequenceNumber;
  772. //
  773. // Verify that our input arguments all make sense.
  774. //
  775. if (!ARGUMENT_PRESENT(pIdentStruct) ||
  776. pIdentStruct->CodeProps == NULL ) {
  777. Status = STATUS_INVALID_PARAMETER;
  778. goto ExitHandler;
  779. }
  780. if ((pIdentStruct->dwCheckFlags & SAFER_CRITERIA_AUTHENTICODE) == 0 ||
  781. !ARGUMENT_PRESENT(pIdentStruct->UnicodeFullyQualfiedLongFileName.Buffer)) {
  782. // We're not supposed to evaluate certificates, or the
  783. // filename was not supplied (WinVerifyTrust requires a
  784. // filename, even if an opened handle to is also supplied).
  785. Status = STATUS_NOT_FOUND;
  786. goto ExitHandler;
  787. }
  788. if ( !ARGUMENT_PRESENT(pFoundLevel) ) {
  789. Status = STATUS_ACCESS_VIOLATION;
  790. goto ExitHandler;
  791. }
  792. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  793. //
  794. // Prepare the input data structure that WinVerifyTrust expects.
  795. //
  796. RtlZeroMemory(&wvtData, sizeof(WINTRUST_DATA));
  797. wvtData.cbStruct = sizeof(WINTRUST_DATA);
  798. if ((wvtData.dwUIChoice = dwUIChoice) == 0) {
  799. // If the UI choice element was left zero, then assume all UI.
  800. wvtData.dwUIChoice = WTD_UI_ALL;
  801. }
  802. wvtData.dwProvFlags = WTD_SAFER_FLAG; // our magic flag.
  803. wvtData.dwUnionChoice = WTD_CHOICE_FILE;
  804. wvtData.pFile = &wvtFileInfo;
  805. //
  806. // Prepare the input file data structure used by WinVerifyTrust.
  807. //
  808. RtlZeroMemory(&wvtFileInfo, sizeof(WINTRUST_FILE_INFO));
  809. wvtFileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO);
  810. wvtFileInfo.hFile = pIdentStruct->hFileHandle;
  811. wvtFileInfo.pcwszFilePath = pIdentStruct->UnicodeFullyQualfiedLongFileName.Buffer;
  812. //
  813. // Save the global state number.
  814. //
  815. LocalHandleSequenceNumber = g_dwLevelHandleSequence;
  816. //
  817. // Leave the critical section to prevent deadlock with the LoaderLock.
  818. //
  819. RtlLeaveCriticalSection(&g_TableCritSec);
  820. //
  821. // Actually call WinVerifyTrust and save off the return code
  822. // and last error code.
  823. //
  824. lStatus = WinVerifyTrust(
  825. pIdentStruct->CodeProps->hWndParent, // hwnd
  826. &wvtFileActionID,
  827. &wvtData
  828. );
  829. dwLastError = GetLastError();
  830. *dwExtendedError = dwLastError;
  831. //
  832. // Reacquire the lock and check global state.
  833. //
  834. RtlEnterCriticalSection(&g_TableCritSec);
  835. //
  836. // Check the global state and make sure that the tables were not reloaded
  837. // when we were not looking.
  838. //
  839. if (LocalHandleSequenceNumber != g_dwLevelHandleSequence) {
  840. ASSERT(FALSE);
  841. Status = STATUS_INTERNAL_ERROR;
  842. goto ExitHandler;
  843. }
  844. //
  845. // Process the WinVerifyTrust errors per PhilH
  846. //
  847. pLevelRecord = NULL;
  848. if (S_OK == lStatus && TRUST_E_SUBJECT_NOT_TRUSTED != dwLastError) {
  849. //
  850. // The file is signed. The publisher or hash is explicitly trusted
  851. //
  852. pLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  853. &g_CodeLevelObjTable, SAFER_LEVELID_FULLYTRUSTED);
  854. } else if (TRUST_E_EXPLICIT_DISTRUST == lStatus || TRUST_E_SUBJECT_NOT_TRUSTED == lStatus) {
  855. //
  856. // The publisher is revoked or explicitly untrusted. Alternatively, the hash is
  857. // explicitly untrusted.
  858. //
  859. pLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  860. &g_CodeLevelObjTable, SAFER_LEVELID_DISALLOWED);
  861. } else {
  862. //
  863. // we won't be too conservative in any of the following cases.
  864. // No explicit trust or untrust. Continue on to other SAFER checks.
  865. //
  866. // TRUST_E_NOSIGNATURE == lStatus
  867. // The file isn't signed. Alternatively for TRUST_E_BAD_DIGEST == dwLastError,
  868. // a signed file has been modified.
  869. // CRYPT_E_SECURITY_SETTINGS == lStatus
  870. // For authenticode downloads, the admin has disabled user UI and trust.
  871. // any other combination of lStatus and dwLastError
  872. // The file is signed. WVT has already called safer to check the hash rules.
  873. Status = STATUS_NOT_FOUND;
  874. goto ExitHandler;
  875. }
  876. if (!pLevelRecord) {
  877. Status = STATUS_ACCESS_DENIED;
  878. } else {
  879. *pFoundLevel = pLevelRecord;
  880. Status = STATUS_SUCCESS;
  881. }
  882. ExitHandler:
  883. return Status;
  884. }
  885. BOOL WINAPI
  886. SaferiSearchMatchingHashRules(
  887. IN ALG_ID HashAlgorithm OPTIONAL,
  888. IN PBYTE pHashBytes,
  889. IN DWORD dwHashSize,
  890. IN DWORD dwOriginalImageSize OPTIONAL,
  891. OUT PDWORD pdwFoundLevel,
  892. OUT PDWORD pdwSaferFlags
  893. )
  894. /*++
  895. Routine Description:
  896. This is a private function that is exported for WinVerifyTrust
  897. to call to determine if a given hash has a WinSafer policy
  898. associated with it.
  899. Because this is a private function that is directly called by
  900. outside code, there is extra work needed to enter the critical
  901. section, reload the policy if needed, and set the value returned
  902. by GetLastError.
  903. Arguments:
  904. HashAlgorithm - specifies the algorithm in which the hash
  905. was computed (CALG_MD5, CALG_SHA, etc).
  906. pHashBytes - pointer to a buffer containing the pre-computed
  907. hash value of the file's contents.
  908. dwHashSize - length indicating the size of the hash value that
  909. is referenced by the pHashBytes argument. For example,
  910. a 128-bit MD5 hash should have a dwHashSize length of 16.
  911. dwOriginalImageSize - Specifies the size of the original file's
  912. contents that are being hashed. This value is used as a
  913. heuristic to minimize the number of comparisons that must
  914. be done to identify a match. If this parameter is 0, then
  915. this heuristic will not be used.
  916. pdwFoundLevel - pointer that receives a DWORD indicating the
  917. WinSafer LevelId that is found. This value is only written
  918. when TRUE is returned.
  919. pdwSaferFlags - pointer that receives a DWORD value containing flags
  920. that control the supression of User-Interface dialogs.
  921. This value is only written when TRUE is returned.
  922. Return Value:
  923. Returns TRUE if a WinSafer Level has been found, or FALSE if not.
  924. If FALSE is returned, GetLastError() may be used to find out
  925. specifics about why no match was found (possibly argument errors).
  926. --*/
  927. {
  928. NTSTATUS Status;
  929. PVOID RestartKey;
  930. PAUTHZIDENTSTABLERECORD pAuthzIdentRecord;
  931. DWORD dwBestLevelId;
  932. DWORD dwBestSaferFlags;
  933. BOOLEAN bFirstPass;
  934. //
  935. // Verify that our input arguments all make sense.
  936. //
  937. if (!ARGUMENT_PRESENT(pHashBytes) ||
  938. dwHashSize < 1) {
  939. Status = STATUS_INVALID_PARAMETER;
  940. goto ExitHandler;
  941. }
  942. if (!ARGUMENT_PRESENT(pdwFoundLevel) ||
  943. !ARGUMENT_PRESENT(pdwSaferFlags)) {
  944. Status = STATUS_ACCESS_VIOLATION;
  945. goto ExitHandler;
  946. }
  947. //
  948. // Enter the critical section and reload the tables if needed.
  949. // Notice that a potential reload is needed here because this
  950. // function is externally called directly.
  951. //
  952. if (!g_bInitializedFirstTime) {
  953. Status = STATUS_UNSUCCESSFUL;
  954. goto ExitHandler;
  955. }
  956. RtlEnterCriticalSection(&g_TableCritSec);
  957. if (g_bNeedCacheReload) {
  958. Status = CodeAuthzpImmediateReloadCacheTables();
  959. if (!NT_SUCCESS(Status)) {
  960. goto ExitHandler2;
  961. }
  962. }
  963. //
  964. // Enumerate through all hash subkey GUIDs.
  965. //
  966. bFirstPass = TRUE;
  967. RestartKey = NULL;
  968. for (pAuthzIdentRecord = (PAUTHZIDENTSTABLERECORD)
  969. RtlEnumerateGenericTableWithoutSplaying(
  970. &g_CodeIdentitiesTable, &RestartKey);
  971. pAuthzIdentRecord != NULL;
  972. pAuthzIdentRecord = (PAUTHZIDENTSTABLERECORD)
  973. RtlEnumerateGenericTableWithoutSplaying(
  974. &g_CodeIdentitiesTable, &RestartKey)
  975. )
  976. {
  977. if (pAuthzIdentRecord->dwIdentityType == SaferIdentityTypeImageHash)
  978. {
  979. //
  980. // Ensure that the hash algorithm is the same type between
  981. // what we were supplied and what we are matching against.
  982. //
  983. if (HashAlgorithm != 0 &&
  984. pAuthzIdentRecord->ImageHashInfo.HashAlgorithm !=
  985. HashAlgorithm) {
  986. continue;
  987. }
  988. //
  989. // If the actual filesize does not match the filesize stored
  990. // with the hash identity then there is no need to perform
  991. // any comparisons involving the hash.
  992. //
  993. if ( dwOriginalImageSize != 0 && dwOriginalImageSize !=
  994. pAuthzIdentRecord->ImageHashInfo.ImageSize.QuadPart ) {
  995. continue;
  996. }
  997. //
  998. // If the hash doesn't match at all, then go onto the next one.
  999. //
  1000. if ( dwHashSize != pAuthzIdentRecord->ImageHashInfo.HashSize ||
  1001. !RtlEqualMemory(
  1002. &pAuthzIdentRecord->ImageHashInfo.ImageHash[0],
  1003. &pHashBytes[0], dwHashSize))
  1004. {
  1005. continue;
  1006. }
  1007. //
  1008. // Evaluate if this identity matches better than whatever
  1009. // best path identity that we previously had, and keep it if so.
  1010. //
  1011. if ( bFirstPass ||
  1012. // we didn't have anything before.
  1013. pAuthzIdentRecord->dwLevelId < dwBestLevelId
  1014. // or specifies a less-privileged level.
  1015. )
  1016. {
  1017. dwBestLevelId = pAuthzIdentRecord->dwLevelId;
  1018. dwBestSaferFlags = pAuthzIdentRecord->ImageHashInfo.dwSaferFlags;
  1019. bFirstPass = FALSE;
  1020. }
  1021. }
  1022. }
  1023. //
  1024. // If we have identified a matching WinSafer Level then
  1025. // pass it back and return success.
  1026. //
  1027. if (bFirstPass) {
  1028. Status = STATUS_NOT_FOUND;
  1029. goto ExitHandler2;
  1030. }
  1031. *pdwFoundLevel = dwBestLevelId;
  1032. *pdwSaferFlags = dwBestSaferFlags;
  1033. Status = STATUS_SUCCESS;
  1034. ExitHandler2:
  1035. RtlLeaveCriticalSection(&g_TableCritSec);
  1036. ExitHandler:
  1037. if (NT_SUCCESS(Status)) {
  1038. return TRUE;
  1039. } else {
  1040. BaseSetLastNTError(Status);
  1041. return FALSE;
  1042. }
  1043. }
  1044. NTSTATUS NTAPI
  1045. __CodeAuthzpCheckIdentityHashRules(
  1046. IN OUT PLOCALIDENTITYCONTEXT pIdentStruct,
  1047. OUT PAUTHZLEVELTABLERECORD *pFoundLevel,
  1048. OUT PAUTHZIDENTSTABLERECORD *pFoundIdentity
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. Assumes that the global table lock has already been acquired.
  1053. Arguments:
  1054. pIdentStruct -
  1055. pFoundLevel - receives a pointer to the authorization Level record
  1056. indicated by the best matching rule.
  1057. pFoundIdentity - receives a pointer to the identifier entry rule
  1058. that best matched.
  1059. Return Value:
  1060. Returns STATUS_SUCCESS if a WinSafer Level has been found,
  1061. or STATUS_NOT_FOUND if not. Otherwise an error code.
  1062. --*/
  1063. {
  1064. NTSTATUS Status;
  1065. PVOID RestartKey;
  1066. PAUTHZIDENTSTABLERECORD pAuthzIdentRecord, pBestIdentRecord;
  1067. PAUTHZLEVELTABLERECORD pAuthzLevelRecord;
  1068. DWORD dwBestLevelId;
  1069. BOOLEAN bFirstPass;
  1070. //
  1071. // Verify that our input arguments all make sense.
  1072. //
  1073. if (!ARGUMENT_PRESENT(pIdentStruct) ||
  1074. pIdentStruct->CodeProps == NULL ) {
  1075. Status = STATUS_INVALID_PARAMETER;
  1076. goto ExitHandler;
  1077. }
  1078. if ((pIdentStruct->dwCheckFlags & SAFER_CRITERIA_IMAGEHASH) == 0 ||
  1079. RtlIsGenericTableEmpty(&g_CodeIdentitiesTable)) {
  1080. // We're not supposed to evaluate hashes.
  1081. Status = STATUS_NOT_FOUND;
  1082. goto ExitHandler;
  1083. }
  1084. if ( !ARGUMENT_PRESENT(pFoundLevel) ||
  1085. !ARGUMENT_PRESENT(pFoundIdentity) ) {
  1086. Status = STATUS_ACCESS_VIOLATION;
  1087. goto ExitHandler;
  1088. }
  1089. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  1090. //
  1091. // Enumerate through all hash subkey GUIDs.
  1092. //
  1093. bFirstPass = TRUE;
  1094. RestartKey = NULL;
  1095. for (pAuthzIdentRecord = (PAUTHZIDENTSTABLERECORD)
  1096. RtlEnumerateGenericTableWithoutSplaying(
  1097. &g_CodeIdentitiesTable, &RestartKey);
  1098. pAuthzIdentRecord != NULL;
  1099. pAuthzIdentRecord = (PAUTHZIDENTSTABLERECORD)
  1100. RtlEnumerateGenericTableWithoutSplaying(
  1101. &g_CodeIdentitiesTable, &RestartKey)
  1102. )
  1103. {
  1104. if (pAuthzIdentRecord->dwIdentityType == SaferIdentityTypeImageHash)
  1105. {
  1106. //
  1107. // If the user already supplied the pre-computed hash to us,
  1108. // but not the file size, then assume that we do not need
  1109. // to consider the file size when making a comparison.
  1110. //
  1111. if (pIdentStruct->bHaveHash &&
  1112. pIdentStruct->ImageSize.QuadPart == 0) {
  1113. goto SkipToActualHashCheck;
  1114. }
  1115. //
  1116. // If the actual filesize does not match the filesize stored
  1117. // with the hash identity then there is no need to perform
  1118. // any comparisons involving the hash.
  1119. //
  1120. if ( pIdentStruct->ImageSize.QuadPart == 0 )
  1121. {
  1122. // If we don't have the ImageSize yet, then try to
  1123. // open the file and memory map it to find the size.
  1124. Status = __CodeAuthzpEnsureMapped(pIdentStruct);
  1125. if (!NT_SUCCESS(Status)) {
  1126. // If we failed to compute the MD5 sum of this, then that is
  1127. // actually rather bad, but we'll proceed to evaluate any
  1128. // non-MD5 identity rules, since ignoring them could be worse.
  1129. pIdentStruct->dwCheckFlags &= ~SAFER_CRITERIA_IMAGEHASH;
  1130. goto ExitHandler;
  1131. }
  1132. ASSERTMSG("EnsureMapped failed but did not return error",
  1133. pIdentStruct->pImageMemory != NULL &&
  1134. pIdentStruct->ImageSize.QuadPart != 0);
  1135. }
  1136. if ( pAuthzIdentRecord->ImageHashInfo.ImageSize.QuadPart !=
  1137. pIdentStruct->ImageSize.QuadPart) {
  1138. continue;
  1139. }
  1140. SkipToActualHashCheck:
  1141. //
  1142. // Dynamically compute the MD5 hash of the item if needed.
  1143. //
  1144. if (!pIdentStruct->bHaveHash)
  1145. {
  1146. // Otherwise hash was not supplied, so we must compute it now.
  1147. // Open the file and memory map it.
  1148. Status = __CodeAuthzpEnsureMapped(pIdentStruct);
  1149. if (!NT_SUCCESS(Status)) {
  1150. // If we failed to compute the MD5 sum of this, then
  1151. // that is actually rather bad, but we'll proceed to
  1152. // evaluate any non-MD5 identity rules, since ignoring
  1153. // them could be worse.
  1154. pIdentStruct->dwCheckFlags &= ~SAFER_CRITERIA_IMAGEHASH;
  1155. goto ExitHandler;
  1156. }
  1157. ASSERTMSG("EnsureMapped failed but did not return error",
  1158. pIdentStruct->pImageMemory != NULL &&
  1159. pIdentStruct->ImageSize.QuadPart != 0);
  1160. // We now have a MD5 hash to use.
  1161. pIdentStruct->FinalHashSize =
  1162. sizeof(pIdentStruct->FinalHash);
  1163. Status = CodeAuthzpComputeImageHash(
  1164. pIdentStruct->pImageMemory,
  1165. pIdentStruct->ImageSize.LowPart,
  1166. &pIdentStruct->FinalHash[0],
  1167. &pIdentStruct->FinalHashSize,
  1168. &pIdentStruct->FinalHashAlgorithm);
  1169. if (!NT_SUCCESS(Status)) {
  1170. goto ExitHandler;
  1171. }
  1172. pIdentStruct->bHaveHash = TRUE;
  1173. }
  1174. //
  1175. // Ensure that the hash algorithm is the same type between
  1176. // what we were supplied and what we are matching against.
  1177. //
  1178. if ( pIdentStruct->FinalHashAlgorithm != 0 &&
  1179. pAuthzIdentRecord->ImageHashInfo.HashAlgorithm !=
  1180. pIdentStruct->FinalHashAlgorithm) {
  1181. continue;
  1182. }
  1183. //
  1184. // If the hash doesn't match at all, then go onto the next one.
  1185. //
  1186. if ( pIdentStruct->FinalHashSize !=
  1187. pAuthzIdentRecord->ImageHashInfo.HashSize ||
  1188. !RtlEqualMemory(
  1189. &pIdentStruct->FinalHash[0],
  1190. &pAuthzIdentRecord->ImageHashInfo.ImageHash[0],
  1191. pIdentStruct->FinalHashSize))
  1192. {
  1193. continue;
  1194. }
  1195. //
  1196. // Evaluate if this identity matches better than whatever
  1197. // best path identity that we previously had, and keep it if so.
  1198. //
  1199. if ( bFirstPass ||
  1200. // we didn't have anything before.
  1201. pAuthzIdentRecord->dwLevelId < dwBestLevelId
  1202. // same scope, but specifies a less-privileged level.
  1203. )
  1204. {
  1205. pBestIdentRecord = pAuthzIdentRecord;
  1206. dwBestLevelId = pAuthzIdentRecord->dwLevelId;
  1207. bFirstPass = FALSE;
  1208. }
  1209. }
  1210. }
  1211. //
  1212. // If we have identified a matching WinSafer Level then
  1213. // look up the Level record for it and return success.
  1214. //
  1215. if (bFirstPass) {
  1216. Status = STATUS_NOT_FOUND;
  1217. goto ExitHandler;
  1218. }
  1219. pAuthzLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  1220. &g_CodeLevelObjTable, dwBestLevelId);
  1221. if (!pAuthzLevelRecord) {
  1222. Status = STATUS_NOT_FOUND;
  1223. goto ExitHandler;
  1224. }
  1225. *pFoundLevel = pAuthzLevelRecord;
  1226. *pFoundIdentity = pBestIdentRecord;
  1227. Status = STATUS_SUCCESS;
  1228. ExitHandler:
  1229. return Status;
  1230. }
  1231. NTSTATUS NTAPI
  1232. __CodeAuthzpCheckIdentityUrlZoneRules(
  1233. IN OUT PLOCALIDENTITYCONTEXT pIdentStruct,
  1234. OUT PAUTHZLEVELTABLERECORD *pFoundLevel,
  1235. OUT PAUTHZIDENTSTABLERECORD *pFoundIdentity
  1236. )
  1237. /*++
  1238. Routine Description:
  1239. Arguments:
  1240. pIdentStruct -
  1241. pFoundLevel - receives a pointer to the authorization Level record
  1242. indicated by the best matching rule.
  1243. pFoundIdentity - receives a pointer to the identifier entry rule
  1244. that best matched.
  1245. Return Value:
  1246. Returns STATUS_SUCCESS if a WinSafer Level has been found,
  1247. or STATUS_NOT_FOUND if not. Otherwise an error code.
  1248. --*/
  1249. {
  1250. NTSTATUS Status;
  1251. PVOID RestartKey;
  1252. PAUTHZIDENTSTABLERECORD pAuthzIdentRecord, pBestIdentRecord;
  1253. PAUTHZLEVELTABLERECORD pAuthzLevelRecord;
  1254. DWORD dwBestLevelId;
  1255. BOOLEAN bFirstPass;
  1256. //
  1257. // Verify that our input arguments all make sense.
  1258. //
  1259. if (!ARGUMENT_PRESENT(pIdentStruct) ||
  1260. pIdentStruct->CodeProps == NULL) {
  1261. Status = STATUS_INVALID_PARAMETER;
  1262. goto ExitHandler;
  1263. }
  1264. if ((pIdentStruct->dwCheckFlags & SAFER_CRITERIA_URLZONE) == 0 ||
  1265. RtlIsGenericTableEmpty(&g_CodeIdentitiesTable)) {
  1266. // We're not supposed to evaluate zones.
  1267. Status = STATUS_NOT_FOUND;
  1268. goto ExitHandler;
  1269. }
  1270. if (!ARGUMENT_PRESENT(pFoundLevel) ||
  1271. !ARGUMENT_PRESENT(pFoundIdentity) ) {
  1272. Status = STATUS_ACCESS_VIOLATION;
  1273. goto ExitHandler;
  1274. }
  1275. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  1276. //
  1277. // Enumerate through all UrlZone subkey GUIDs.
  1278. //
  1279. RestartKey = NULL;
  1280. bFirstPass = TRUE;
  1281. for (pAuthzIdentRecord = (PAUTHZIDENTSTABLERECORD)
  1282. RtlEnumerateGenericTableWithoutSplaying(
  1283. &g_CodeIdentitiesTable, &RestartKey);
  1284. pAuthzIdentRecord != NULL;
  1285. pAuthzIdentRecord = (PAUTHZIDENTSTABLERECORD)
  1286. RtlEnumerateGenericTableWithoutSplaying(
  1287. &g_CodeIdentitiesTable, &RestartKey)
  1288. )
  1289. {
  1290. if (pAuthzIdentRecord->dwIdentityType ==
  1291. SaferIdentityTypeUrlZone)
  1292. {
  1293. //
  1294. // Compare the identity with what was supplied to us.
  1295. //
  1296. if (pAuthzIdentRecord->ImageZone.UrlZoneId !=
  1297. pIdentStruct->CodeProps->UrlZoneId) {
  1298. // this zone does not match, so ignore it.
  1299. continue;
  1300. }
  1301. //
  1302. // Evaluate if this path identity matches better than whatever
  1303. // best path identity that we previously had, and keep it if so.
  1304. //
  1305. if (bFirstPass ||
  1306. // we didn't have anything better before.
  1307. pAuthzIdentRecord->dwLevelId < dwBestLevelId)
  1308. // this also matches, but specifies a less-privileged level.
  1309. {
  1310. pBestIdentRecord = pAuthzIdentRecord;
  1311. dwBestLevelId = pAuthzIdentRecord->dwLevelId;
  1312. bFirstPass = FALSE;
  1313. }
  1314. }
  1315. }
  1316. //
  1317. // If we have identified a matching WinSafer Level then
  1318. // look up the Level record for it and return success.
  1319. //
  1320. if (bFirstPass) {
  1321. Status = STATUS_NOT_FOUND;
  1322. goto ExitHandler;
  1323. }
  1324. pAuthzLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  1325. &g_CodeLevelObjTable, dwBestLevelId);
  1326. if (!pAuthzLevelRecord) {
  1327. Status = STATUS_NOT_FOUND;
  1328. goto ExitHandler;
  1329. }
  1330. *pFoundLevel = pAuthzLevelRecord;
  1331. *pFoundIdentity = pBestIdentRecord;
  1332. Status = STATUS_SUCCESS;
  1333. ExitHandler:
  1334. return Status;
  1335. }
  1336. NTSTATUS NTAPI
  1337. __CodeAuthzpIdentifyOneCodeAuthzLevel(
  1338. IN PSAFER_CODE_PROPERTIES pCodeProperties OPTIONAL,
  1339. OUT DWORD *dwExtendedError,
  1340. OUT PAUTHZLEVELTABLERECORD *pBestLevelRecord,
  1341. OUT GUID *pBestIdentGuid
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. Performs the code identification process.
  1346. Assumes that the caller has already locked the global critsec.
  1347. Arguments:
  1348. pCodeProperties - pointer the single CODE_PROPERTIESW structure
  1349. that should be analyzed and evaluated. This parameter
  1350. may be specified as NULL to indicate that there are
  1351. no specific properties that should be evaluated and that
  1352. only the configured Default Level should be used.
  1353. dwExtendedError - In case of certificate rule match, return the extended
  1354. error from WinVerifyTrust.
  1355. pBestLevelRecord - returns the matching WinSafer Level record.
  1356. The value written to this parameter should only be
  1357. considered valid when STATUS_SUCCESS is also returned.
  1358. pBestIdentGuid - returns the matching Code Identity guid from
  1359. which the resulting WinSafer Level was determined.
  1360. The value written to this parameter should only be
  1361. considered valid when STATUS_SUCCESS is also returned.
  1362. This GUID may also be SAFER_GUID_RESULT_TRUSTED_CERT or
  1363. SAFER_GUID_RESULT_DEFAULT_LEVEL to indicate that the result
  1364. was from a publisher cert or a default rule match.
  1365. Note that a cert hash match will also
  1366. Return Value:
  1367. Returns STATUS_SUCCESS if a WinSafer Level has been found,
  1368. or STATUS_NOT_FOUND or another error code if not.
  1369. --*/
  1370. {
  1371. NTSTATUS Status;
  1372. LOCALIDENTITYCONTEXT identStruct = {0};
  1373. //
  1374. // Verify our input state and perform any explicit
  1375. // policy loading, if it hasn't been loaded yet.
  1376. //
  1377. if (!ARGUMENT_PRESENT(pBestLevelRecord) ||
  1378. !ARGUMENT_PRESENT(pBestIdentGuid)) {
  1379. Status = STATUS_ACCESS_VIOLATION;
  1380. goto ExitHandler;
  1381. }
  1382. ASSERT(g_TableCritSec.OwningThread == UlongToHandle(GetCurrentThreadId()));
  1383. //
  1384. // Star the identification process. If no code properties were
  1385. // supplied to us, then we can immediately skip to only
  1386. // considering the default WinSafer Level configurations.
  1387. //
  1388. if (ARGUMENT_PRESENT(pCodeProperties))
  1389. {
  1390. BOOLEAN bRetryCertRuleCheck = FALSE;
  1391. BOOLEAN bPathIsNtNamespace;
  1392. // Current best identity match.
  1393. PAUTHZLEVELTABLERECORD pAuthzLevelRecord = NULL;
  1394. PAUTHZIDENTSTABLERECORD pAuthzIdentRecord;
  1395. // Temporary evaluation identity match.
  1396. BOOL bExactPath;
  1397. PAUTHZLEVELTABLERECORD pTempLevelRecord;
  1398. PAUTHZIDENTSTABLERECORD pTempIdentRecord;
  1399. //
  1400. // Check that the CODE_PROPERTIES structure is the right size.
  1401. //
  1402. if (pCodeProperties->cbSize != sizeof(SAFER_CODE_PROPERTIES)) {
  1403. Status = STATUS_INFO_LENGTH_MISMATCH;
  1404. goto ExitHandler;
  1405. }
  1406. //
  1407. // Initialize the structure that we use to store our
  1408. // stateful information during policy evaluation.
  1409. // We don't copy everything from the CODE_PROPERTIES
  1410. // structure into the identStruct, since some of it
  1411. // is dynamically loaded/copied within "EnsureMapped".
  1412. //
  1413. RtlZeroMemory(&identStruct, sizeof(LOCALIDENTITYCONTEXT));
  1414. identStruct.CodeProps = pCodeProperties;
  1415. identStruct.dwCheckFlags = pCodeProperties->dwCheckFlags;
  1416. identStruct.ImageSize.QuadPart =
  1417. pCodeProperties->ImageSize.QuadPart;
  1418. if (identStruct.ImageSize.QuadPart != 0 &&
  1419. pCodeProperties->dwImageHashSize > 0 &&
  1420. pCodeProperties->dwImageHashSize <= SAFER_MAX_HASH_SIZE)
  1421. {
  1422. // The image hash and filesize were both supplied, therefore
  1423. // we have a valid hash and don't need to compute it ourself.
  1424. RtlCopyMemory(&identStruct.FinalHash[0],
  1425. &pCodeProperties->ImageHash[0],
  1426. pCodeProperties->dwImageHashSize);
  1427. identStruct.FinalHashSize = pCodeProperties->dwImageHashSize;
  1428. identStruct.bHaveHash = TRUE;
  1429. }
  1430. bPathIsNtNamespace = ((identStruct.dwCheckFlags &
  1431. SAFER_CRITERIA_IMAGEPATH_NT) != 0 ? TRUE : FALSE);
  1432. //
  1433. // Copy over the file handle into the context structure, if a
  1434. // handle was supplied, otherwise try to open the filepath.
  1435. //
  1436. if (pCodeProperties->hImageFileHandle != NULL &&
  1437. pCodeProperties->hImageFileHandle != INVALID_HANDLE_VALUE)
  1438. {
  1439. identStruct.hFileHandle = pCodeProperties->hImageFileHandle;
  1440. identStruct.bCloseFileHandle = FALSE;
  1441. }
  1442. else if (pCodeProperties->ImagePath != NULL)
  1443. {
  1444. HANDLE hFile;
  1445. if (bPathIsNtNamespace) {
  1446. UNICODE_STRING UnicodeFilename;
  1447. IO_STATUS_BLOCK IoStatusBlock;
  1448. OBJECT_ATTRIBUTES ObjectAttributes;
  1449. RtlInitUnicodeString(&UnicodeFilename, pCodeProperties->ImagePath);
  1450. InitializeObjectAttributes(
  1451. &ObjectAttributes, &UnicodeFilename,
  1452. OBJ_CASE_INSENSITIVE, NULL, NULL);
  1453. Status = NtOpenFile(&hFile, FILE_GENERIC_READ, &ObjectAttributes,
  1454. &IoStatusBlock, FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE);
  1455. if (!NT_SUCCESS(Status)) {
  1456. hFile = NULL;
  1457. }
  1458. } else {
  1459. hFile = CreateFileW(
  1460. pCodeProperties->ImagePath,
  1461. GENERIC_READ,
  1462. FILE_SHARE_READ,
  1463. NULL,
  1464. OPEN_EXISTING,
  1465. FILE_ATTRIBUTE_NORMAL,
  1466. NULL);
  1467. }
  1468. if (hFile != NULL && hFile != INVALID_HANDLE_VALUE) {
  1469. identStruct.hFileHandle = hFile;
  1470. identStruct.bCloseFileHandle = TRUE;
  1471. }
  1472. }
  1473. //
  1474. // Reconstruct the fully qualified pathname from the handle
  1475. // or from the supplied filename.
  1476. //
  1477. Status = CodeAuthzFullyQualifyFilename(
  1478. identStruct.hFileHandle,
  1479. bPathIsNtNamespace,
  1480. pCodeProperties->ImagePath,
  1481. &identStruct.UnicodeFullyQualfiedLongFileName);
  1482. if (!NT_SUCCESS(Status) &&
  1483. pCodeProperties->ImagePath != NULL &&
  1484. !bPathIsNtNamespace)
  1485. {
  1486. // Otherwise just live with what was passed in to us.
  1487. // If allocation fails, then path criteria will just be ignored.
  1488. Status = RtlCreateUnicodeString(
  1489. &identStruct.UnicodeFullyQualfiedLongFileName,
  1490. pCodeProperties->ImagePath);
  1491. }
  1492. //
  1493. // Perform the WinVerifyTrust sequence to see if the signing
  1494. // certificate matches any of the publishers that are in the
  1495. // trusted or distrusted publisher stores. This also has the
  1496. // additional effect of checking the "signed hashes".
  1497. //
  1498. Status = __CodeAuthzpCheckIdentityCertificateRules(
  1499. &identStruct,
  1500. dwExtendedError,
  1501. &pAuthzLevelRecord,
  1502. WTD_UI_NONE);
  1503. if (NT_SUCCESS(Status)) {
  1504. // An exact publisher was found, so return immediately.
  1505. ASSERT(pAuthzLevelRecord != NULL);
  1506. *pBestLevelRecord = pAuthzLevelRecord;
  1507. RtlCopyMemory(pBestIdentGuid,
  1508. &guidTrustedCert, sizeof(GUID));
  1509. goto ExitHandler2;
  1510. } else if (STATUS_RETRY == Status) {
  1511. if (WTD_UI_NONE != identStruct.CodeProps->dwWVTUIChoice) {
  1512. // if originally supposed to suppress UI, no need to retry.
  1513. bRetryCertRuleCheck = TRUE;
  1514. }
  1515. }
  1516. //
  1517. // Search hash rules defined for this level/scope.
  1518. // Note that hashes match exactly or not at all,
  1519. // so if we get a positive match, then that level
  1520. // is absolutely returned.
  1521. //
  1522. Status = __CodeAuthzpCheckIdentityHashRules(
  1523. &identStruct,
  1524. &pAuthzLevelRecord,
  1525. &pAuthzIdentRecord);
  1526. if (NT_SUCCESS(Status)) {
  1527. // An exact hash identity was found, so return immediately.
  1528. ASSERT(pAuthzLevelRecord != NULL);
  1529. *pBestLevelRecord = pAuthzLevelRecord;
  1530. RtlCopyMemory(pBestIdentGuid,
  1531. &pAuthzIdentRecord->IdentGuid, sizeof(GUID));
  1532. goto ExitHandler2;
  1533. }
  1534. ASSERT(pAuthzLevelRecord == NULL);
  1535. //
  1536. // Search file path rules defined for this level/scope.
  1537. // Note that file paths can either be an exact match
  1538. // or a partial match. If we find an exact match, then
  1539. // it should be absolutely returned. Otherwise the
  1540. // path was a "grouping match" and we must compare the
  1541. // Level with all of the remaining "grouping checks".
  1542. //
  1543. Status = __CodeAuthzpCheckIdentityPathRules(
  1544. &identStruct,
  1545. &pAuthzLevelRecord,
  1546. &bExactPath,
  1547. &pAuthzIdentRecord);
  1548. if (NT_SUCCESS(Status)) {
  1549. ASSERT(pAuthzLevelRecord != NULL);
  1550. pTempLevelRecord = pAuthzLevelRecord;
  1551. pTempIdentRecord = pAuthzIdentRecord;
  1552. if (bExactPath) {
  1553. *pBestLevelRecord = pTempLevelRecord;
  1554. RtlCopyMemory(pBestIdentGuid,
  1555. &pTempIdentRecord->IdentGuid, sizeof(GUID));
  1556. goto ExitHandler2;
  1557. }
  1558. }
  1559. //
  1560. // Search URL Zone identity rules.
  1561. // Note that zones are always "grouping matches",
  1562. // so they must be compared against all of the remaining
  1563. // "grouping checks".
  1564. //
  1565. Status = __CodeAuthzpCheckIdentityUrlZoneRules(
  1566. &identStruct,
  1567. &pTempLevelRecord,
  1568. &pTempIdentRecord);
  1569. if (NT_SUCCESS(Status)) {
  1570. ASSERT(pTempLevelRecord != NULL);
  1571. if (pAuthzLevelRecord == NULL ||
  1572. pTempLevelRecord->dwLevelId <
  1573. pAuthzLevelRecord->dwLevelId)
  1574. {
  1575. pAuthzLevelRecord = pTempLevelRecord;
  1576. pAuthzIdentRecord = pTempIdentRecord;
  1577. }
  1578. }
  1579. #ifdef SAFER_PROMPT_USER_FOR_DECISION_MAKING
  1580. #error "Prompting user in WinVerifyTrust"
  1581. //
  1582. // We were originally passed UI flag, but we supressed
  1583. // the UI display the first time. Call WinVerifyTrust
  1584. // again and see if user choice would allow code to run.
  1585. //
  1586. if (bRetryCertRuleCheck)
  1587. {
  1588. if (pAuthzLevelRecord != NULL) {
  1589. //If we have a rule match and the rule match is FULLYTRUSTED skip retry.
  1590. if (pAuthzLevelRecord->dwLevelId == SAFER_LEVELID_FULLYTRUSTED) {
  1591. bRetryCertRuleCheck = FALSE;
  1592. }
  1593. } else if (g_DefaultCodeLevel != NULL) {
  1594. //No rule match so far. Check default level.
  1595. //If default level is FULLY_TRUSTED skip retry
  1596. if (g_DefaultCodeLevel->dwLevelId == SAFER_LEVELID_FULLYTRUSTED) {
  1597. bRetryCertRuleCheck = FALSE;
  1598. }
  1599. }
  1600. //
  1601. // Perform the WinVerifyTrust sequence again to see if the signing
  1602. // certificate matches any of the publishers that are in the
  1603. // trusted or distrusted publisher stores.
  1604. //
  1605. if (bRetryCertRuleCheck) {
  1606. Status = __CodeAuthzpCheckIdentityCertificateRules(
  1607. &identStruct,
  1608. &pTempLevelRecord,
  1609. identStruct.CodeProps->dwWVTUIChoice);
  1610. if (NT_SUCCESS(Status)) {
  1611. // User clicked Yes or No. Run it as such.
  1612. ASSERT(pTempLevelRecord != NULL);
  1613. *pBestLevelRecord = pTempLevelRecord;
  1614. RtlCopyMemory(pBestIdentGuid,
  1615. &guidTrustedCert, sizeof(GUID));
  1616. goto ExitHandler2;
  1617. }
  1618. }
  1619. }
  1620. #endif
  1621. //
  1622. // If we found any Level matches at this point, then we
  1623. // should simply return that match. The identified Level
  1624. // will be the MIN() of all "grouping matches" found.
  1625. //
  1626. if (pAuthzLevelRecord != NULL) {
  1627. Status = STATUS_SUCCESS;
  1628. *pBestLevelRecord = pAuthzLevelRecord;
  1629. ASSERT(pAuthzIdentRecord != NULL);
  1630. RtlCopyMemory(pBestIdentGuid,
  1631. &pAuthzIdentRecord->IdentGuid, sizeof(GUID));
  1632. goto ExitHandler2;
  1633. }
  1634. }
  1635. //
  1636. // Now we need to consider the default WinSafer Level and
  1637. // return it if one was defined. If there was no default
  1638. // defined, then we should simply return STATUS_NOT_FOUND.
  1639. //
  1640. if (g_DefaultCodeLevel != NULL) {
  1641. *pBestLevelRecord = g_DefaultCodeLevel;
  1642. RtlCopyMemory(pBestIdentGuid, &guidDefaultRule, sizeof(GUID));
  1643. Status = STATUS_SUCCESS;
  1644. goto ExitHandler2;
  1645. }
  1646. Status = STATUS_NOT_FOUND;
  1647. ExitHandler2:
  1648. __CodeAuthzpEnsureUnmapped(&identStruct);
  1649. if (identStruct.UnicodeFullyQualfiedLongFileName.Buffer != NULL) {
  1650. RtlFreeUnicodeString(&identStruct.UnicodeFullyQualfiedLongFileName);
  1651. }
  1652. if (identStruct.bCloseFileHandle && identStruct.hFileHandle != NULL) {
  1653. NtClose(identStruct.hFileHandle);
  1654. }
  1655. ExitHandler:
  1656. return Status;
  1657. }
  1658. BOOL
  1659. SaferpSkipPolicyForAdmins(VOID)
  1660. /*++
  1661. Routine Description:
  1662. Decides whether or not Safer policy should be skipped.
  1663. Policy is skipped if
  1664. 1. The caller is an Admin AND
  1665. 2. The registry key specifies that the policy should be skipped
  1666. for Admins.
  1667. Arguments:
  1668. Return Value:
  1669. Returns TRUE if a policy should be skipped for admins.
  1670. Returns FALSE otherwise or in case of any intermediate errors.
  1671. --*/
  1672. {
  1673. static BOOL gSaferSkipPolicy = 2;
  1674. BOOL bIsAdmin = FALSE;
  1675. DWORD AdminSid[] = {0x201, 0x5000000, 0x20, 0x220};
  1676. NTSTATUS Status = STATUS_SUCCESS;
  1677. // If we have already evaluated policy once, return the cached value.
  1678. if (2 != gSaferSkipPolicy)
  1679. {
  1680. return gSaferSkipPolicy;
  1681. }
  1682. // Set the default to "will not skip policy"
  1683. gSaferSkipPolicy = 0;
  1684. // Check if the caller is an admin.
  1685. if (CheckTokenMembership(NULL, (PSID) AdminSid, &bIsAdmin))
  1686. {
  1687. // The caller is an Admin. Let's check whether the regkey says it's ok
  1688. // to skip the policy for admins.
  1689. if (bIsAdmin)
  1690. {
  1691. const static UNICODE_STRING SaferUnicodeKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers");
  1692. const static OBJECT_ATTRIBUTES SaferObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&SaferUnicodeKeyName, OBJ_CASE_INSENSITIVE);
  1693. const static UNICODE_STRING SaferPolicyScope = RTL_CONSTANT_STRING(SAFER_POLICY_SCOPE);
  1694. HANDLE hKeyEnabled = NULL;
  1695. BYTE QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 64];
  1696. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
  1697. DWORD dwActualSize = 0;
  1698. // Open the CodeIdentifiers key.
  1699. Status = NtOpenKey(
  1700. &hKeyEnabled,
  1701. KEY_QUERY_VALUE,
  1702. (POBJECT_ATTRIBUTES) &SaferObjectAttributes
  1703. );
  1704. if (NT_SUCCESS(Status)) {
  1705. // Read the Policy Scope value.
  1706. Status = NtQueryValueKey(
  1707. hKeyEnabled,
  1708. (PUNICODE_STRING) &SaferPolicyScope,
  1709. KeyValuePartialInformation,
  1710. pKeyValueInfo,
  1711. sizeof(QueryBuffer),
  1712. &dwActualSize
  1713. );
  1714. NtClose(hKeyEnabled);
  1715. // Skip policy if the flag is set to 1.
  1716. if (NT_SUCCESS(Status)) {
  1717. if ((pKeyValueInfo->Type == REG_DWORD) &&
  1718. (pKeyValueInfo->DataLength == sizeof(DWORD)) &&
  1719. (*((PDWORD) pKeyValueInfo->Data) & 0x1)) {
  1720. gSaferSkipPolicy = 1;
  1721. }
  1722. }
  1723. }
  1724. }
  1725. }
  1726. return gSaferSkipPolicy;
  1727. }
  1728. VOID
  1729. SaferpLogResultsToFile(
  1730. LPWSTR InputImageName,
  1731. LPWSTR LevelName,
  1732. LPWSTR RuleTypeName,
  1733. GUID *Guid
  1734. )
  1735. /*++
  1736. Routine Description:
  1737. Logs a message to a file specified in
  1738. HKLM\Software\Policies\Microsoft\Windows\Safer\CodeIdentifiers LogFileName.
  1739. The format of the message is:
  1740. TLIST.EXE (PID = 1076) identified C:\SAFERTEST\TEST.VBS as FULLY TRUSTED
  1741. using CERTIFICATE rul, Guid = {abcdef00-abcd-abcd-abcdefabcdef00}
  1742. Arguments:
  1743. Return Value:
  1744. --*/
  1745. {
  1746. #define SAFER_LOG_NAME1 L" (PID = "
  1747. #define SAFER_LOG_NAME2 L") identified "
  1748. #define SAFER_LOG_NAME3 L" as "
  1749. #define SAFER_LOG_NAME4 L" using "
  1750. #define SAFER_LOG_NAME5 L" rule, Guid = "
  1751. #define SAFER_INTEGER_LENGTH 20
  1752. #define SAFER_MAX_RULE_DESCRIPTION_LENGTH 12
  1753. #define SAFER_GUID_LENGTH 38
  1754. NTSTATUS Status = STATUS_SUCCESS;
  1755. HANDLE hFile = NULL;
  1756. HANDLE hKey = NULL;
  1757. ULONG ProcessNameLength = 0;
  1758. PWCHAR Buffer = NULL;
  1759. ULONG BasicInfoLength = 0;
  1760. ULONG BytesWritten = 0;
  1761. UCHAR TmpBuf[] = {0xFF, 0xFE};
  1762. const static UNICODE_STRING SaferUnicodeKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers");
  1763. const static OBJECT_ATTRIBUTES SaferObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&SaferUnicodeKeyName, OBJ_CASE_INSENSITIVE);
  1764. const static UNICODE_STRING SaferPolicyScope = RTL_CONSTANT_STRING(SAFER_LOGFILE_NAME);
  1765. PROCESS_BASIC_INFORMATION ProcInfo = {0};
  1766. ULONG TotalSize = sizeof(SAFER_LOG_NAME1) +
  1767. sizeof(SAFER_LOG_NAME2) +
  1768. sizeof(SAFER_LOG_NAME3) +
  1769. sizeof(SAFER_LOG_NAME4) +
  1770. sizeof(SAFER_LOG_NAME5) +
  1771. ((SAFER_INTEGER_LENGTH +
  1772. SAFER_MAX_RULE_DESCRIPTION_LENGTH +
  1773. SAFER_GUID_LENGTH) * sizeof(WCHAR));
  1774. UCHAR QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
  1775. PWCHAR ProcessImageName = NULL;
  1776. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
  1777. DWORD dwActualSize = 0;
  1778. // Open the CodeIdentifiers key.
  1779. Status = NtOpenKey(
  1780. &hKey,
  1781. KEY_QUERY_VALUE,
  1782. (POBJECT_ATTRIBUTES) &SaferObjectAttributes
  1783. );
  1784. if (!NT_SUCCESS(Status)) {
  1785. return;
  1786. }
  1787. // Read the name of the file for logging.
  1788. Status = NtQueryValueKey(
  1789. hKey,
  1790. (PUNICODE_STRING) &SaferPolicyScope,
  1791. KeyValuePartialInformation,
  1792. pKeyValueInfo,
  1793. sizeof(QueryBuffer),
  1794. &dwActualSize
  1795. );
  1796. NtClose(hKey);
  1797. // We do not care if the buffer size was too small to retrieve the logfile
  1798. // name since this is for troubleshooting.
  1799. if (!NT_SUCCESS(Status)) {
  1800. return;
  1801. }
  1802. // This was not a string.
  1803. if (pKeyValueInfo->Type != REG_SZ) {
  1804. return;
  1805. }
  1806. hFile = CreateFileW((LPCWSTR) pKeyValueInfo->Data, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
  1807. if (hFile == INVALID_HANDLE_VALUE) {
  1808. return;
  1809. }
  1810. SetFilePointer (hFile, 0, NULL, FILE_BEGIN);
  1811. WriteFile (hFile, (LPCVOID)TmpBuf, 2, &BytesWritten, NULL);
  1812. SetFilePointer (hFile, 0, NULL, FILE_END);
  1813. Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessImageFileName, QueryBuffer, sizeof(QueryBuffer), &ProcessNameLength);
  1814. if (!NT_SUCCESS(Status)) {
  1815. goto Cleanup;
  1816. }
  1817. ProcessImageName = (PWCHAR) (QueryBuffer + ProcessNameLength - sizeof(WCHAR));
  1818. ProcessNameLength = 1;
  1819. while (((PUCHAR) ProcessImageName >= QueryBuffer) && (*(ProcessImageName - 1) != L'\\')) {
  1820. ProcessImageName--;
  1821. ProcessNameLength++;
  1822. }
  1823. TotalSize += (ProcessNameLength + (wcslen(InputImageName) + wcslen(LevelName)) * sizeof(WCHAR));
  1824. Status = NtQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, (PVOID) &ProcInfo, sizeof(PROCESS_BASIC_INFORMATION), &BasicInfoLength);
  1825. if (!NT_SUCCESS(Status)) {
  1826. goto Cleanup;
  1827. }
  1828. Buffer = (PWCHAR) RtlAllocateHeap(RtlProcessHeap(), 0, TotalSize);
  1829. if (Buffer == NULL) {
  1830. goto Cleanup;
  1831. }
  1832. swprintf(Buffer, L"%s%s%d%s%s%s%s%s%s%s{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\r\n",
  1833. ProcessImageName,
  1834. SAFER_LOG_NAME1,
  1835. ProcInfo.UniqueProcessId,
  1836. SAFER_LOG_NAME2,
  1837. InputImageName,
  1838. SAFER_LOG_NAME3,
  1839. LevelName,
  1840. SAFER_LOG_NAME4,
  1841. RuleTypeName,
  1842. SAFER_LOG_NAME5,
  1843. Guid->Data1, Guid->Data2, Guid->Data3, Guid->Data4[0], Guid->Data4[1], Guid->Data4[2], Guid->Data4[3], Guid->Data4[4], Guid->Data4[5], Guid->Data4[6], Guid->Data4[7]);
  1844. ASSERT((wcslen(Buffer) + 1) * sizeof(WCHAR) < TotalSize);
  1845. WriteFile (hFile, (LPCVOID)Buffer, (wcslen(Buffer) * sizeof(WCHAR)), &BytesWritten, NULL);
  1846. RtlFreeHeap(RtlProcessHeap(), 0, Buffer);
  1847. Cleanup:
  1848. CloseHandle(hFile);
  1849. }
  1850. BOOL WINAPI
  1851. SaferIdentifyLevel(
  1852. IN DWORD dwNumProperties,
  1853. IN PSAFER_CODE_PROPERTIES pCodeProperties,
  1854. OUT SAFER_LEVEL_HANDLE *pLevelHandle,
  1855. IN LPVOID lpReserved
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. Performs the code identification process. Accepts an array of
  1860. CODE_PROPERTIES structures that supply all of the identification
  1861. criteria. The final result is the least privileged match resulting
  1862. from each element of the array.
  1863. Arguments:
  1864. dwNumProperties - indicates the number of CODE_PROPERTIES structures
  1865. pointed to by the CodeProperties argument.
  1866. pCodeProperties - pointer to one or more structures that specify
  1867. all of the input criteria that will be used to identify level.
  1868. pLevelHandle - pointer that will receive the opened Level object
  1869. handle when the identification operation is successful.
  1870. lpReserved - unused, must be zero.
  1871. Return Value:
  1872. Returns TRUE if a Level was identified and an opened handle
  1873. to it stored in the 'LevelHandle' argument. Otherwise this
  1874. function returns FALSE on error and GetLastError() can be used
  1875. to obtain additional information about the error.
  1876. --*/
  1877. {
  1878. DWORD Index;
  1879. NTSTATUS Status;
  1880. BOOL ReturnValue = FALSE;
  1881. PAUTHZLEVELTABLERECORD pBestLevelRecord;
  1882. GUID BestIdentGuid;
  1883. PWCHAR LocalLevelName = L"\"default\"";
  1884. PWCHAR LocalRuleName = L"default";
  1885. PWCHAR LocalImageName = L"Default";
  1886. DWORD dwExtendedError = ERROR_SUCCESS;
  1887. //
  1888. // Validate the input parameters.
  1889. //
  1890. UNREFERENCED_PARAMETER(lpReserved);
  1891. if (!ARGUMENT_PRESENT(pLevelHandle)) {
  1892. Status = STATUS_ACCESS_VIOLATION;
  1893. goto ExitHandler;
  1894. }
  1895. if (!g_bInitializedFirstTime) {
  1896. Status = STATUS_UNSUCCESSFUL;
  1897. goto ExitHandler;
  1898. }
  1899. RtlEnterCriticalSection(&g_TableCritSec);
  1900. if (g_bNeedCacheReload) {
  1901. Status = CodeAuthzpImmediateReloadCacheTables();
  1902. if (!NT_SUCCESS(Status)) {
  1903. goto ExitHandler2;
  1904. }
  1905. }
  1906. if (RtlIsGenericTableEmpty(&g_CodeLevelObjTable)) {
  1907. // There are no levels defined! Should not happen.
  1908. Status = STATUS_NOT_FOUND;
  1909. goto ExitHandler2;
  1910. }
  1911. //
  1912. // Do not allow filehandles unless filename is specified.
  1913. //
  1914. for (Index = 0; Index < dwNumProperties; Index++)
  1915. {
  1916. if (pCodeProperties[Index].hImageFileHandle != NULL &&
  1917. pCodeProperties[Index].hImageFileHandle != INVALID_HANDLE_VALUE &&
  1918. pCodeProperties[Index].ImagePath == NULL)
  1919. {
  1920. Status = STATUS_INVALID_PARAMETER;
  1921. goto ExitHandler2;
  1922. }
  1923. }
  1924. if (SaferpSkipPolicyForAdmins())
  1925. {
  1926. pBestLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
  1927. &g_CodeLevelObjTable, SAFER_LEVELID_FULLYTRUSTED);
  1928. RtlCopyMemory(&BestIdentGuid, &guidDefaultRule, sizeof(GUID));
  1929. goto GotMatchingRule;
  1930. }
  1931. if (!ARGUMENT_PRESENT(pCodeProperties) || dwNumProperties == 0) {
  1932. // We were given no criteria to evaluate, so just return
  1933. // the default level. If there was no default defined,
  1934. // then we should simply return STATUS_NOT_FOUND.
  1935. if (g_DefaultCodeLevel != NULL) {
  1936. pBestLevelRecord = g_DefaultCodeLevel;
  1937. RtlCopyMemory(&BestIdentGuid, &guidDefaultRule, sizeof(GUID));
  1938. goto GotMatchingRule;
  1939. } else {
  1940. Status = STATUS_NOT_FOUND;
  1941. goto ExitHandler2;
  1942. }
  1943. }
  1944. //
  1945. // Iterate through the list of CODE_PROPERTIES supplied
  1946. // and determine the final code Level that should be used.
  1947. //
  1948. pBestLevelRecord = NULL;
  1949. for (Index = 0; Index < dwNumProperties; Index++)
  1950. {
  1951. PAUTHZLEVELTABLERECORD pOneLevelRecord;
  1952. GUID OneIdentGuid;
  1953. Status = __CodeAuthzpIdentifyOneCodeAuthzLevel(
  1954. &pCodeProperties[Index],
  1955. &dwExtendedError,
  1956. &pOneLevelRecord,
  1957. &OneIdentGuid);
  1958. if (NT_SUCCESS(Status)) {
  1959. ASSERT(pOneLevelRecord != NULL);
  1960. if (!pBestLevelRecord ||
  1961. pOneLevelRecord->dwLevelId <
  1962. pBestLevelRecord->dwLevelId )
  1963. {
  1964. pBestLevelRecord = pOneLevelRecord;
  1965. RtlCopyMemory(&BestIdentGuid, &OneIdentGuid, sizeof(GUID));
  1966. }
  1967. } else if (Status != STATUS_NOT_FOUND) {
  1968. // An unexpected error occurred, so return that.
  1969. goto ExitHandler2;
  1970. }
  1971. }
  1972. if (pBestLevelRecord == NULL) {
  1973. Status = STATUS_NOT_FOUND;
  1974. goto ExitHandler2;
  1975. }
  1976. //
  1977. // Now we have the result so pass back a handle to the
  1978. // identified WinSafer Level.
  1979. // Allocate a handle to represent this level.
  1980. //
  1981. GotMatchingRule:
  1982. ASSERT(pBestLevelRecord != NULL);
  1983. if (IsEqualGUID(&guidDefaultRule, &BestIdentGuid))
  1984. {
  1985. // The resulting level match came from the default rule.
  1986. // Now we have to try to guess whether the default actually
  1987. // came from the Machine or User scope.
  1988. DWORD dwScopeId;
  1989. if (g_hKeyCustomRoot != NULL) {
  1990. dwScopeId = SAFER_SCOPEID_REGISTRY;
  1991. } else if (g_DefaultCodeLevelUser != NULL &&
  1992. g_DefaultCodeLevelUser->dwLevelId ==
  1993. pBestLevelRecord->dwLevelId) {
  1994. dwScopeId = SAFER_SCOPEID_USER;
  1995. } else {
  1996. dwScopeId = SAFER_SCOPEID_MACHINE;
  1997. }
  1998. Status = CodeAuthzpCreateLevelHandleFromRecord(
  1999. pBestLevelRecord, // pLevelRecord
  2000. dwScopeId, // dwScopeId
  2001. 0, // dwSaferFlags
  2002. dwExtendedError,
  2003. SaferIdentityDefault,
  2004. &BestIdentGuid, // pIdentRecord
  2005. pLevelHandle // pLevelHandle
  2006. );
  2007. }
  2008. else if (IsEqualGUID(&guidTrustedCert, &BestIdentGuid))
  2009. {
  2010. // Note that when the result is from a certificate, we have
  2011. // no way of actually knowing whether the certificate was
  2012. // defined within the Machine or User scope, so we'll just
  2013. // arbitrarily pick the Machine scope for the handle to be
  2014. // based out of. Additionally, there are no SaferFlags
  2015. // persisted for certificates so we just assume 0.
  2016. Status = CodeAuthzpCreateLevelHandleFromRecord(
  2017. pBestLevelRecord, // pLevelRecord
  2018. SAFER_SCOPEID_MACHINE, // dwScopeId
  2019. 0, // dwSaferFlags
  2020. dwExtendedError,
  2021. SaferIdentityTypeCertificate,
  2022. &BestIdentGuid, // pIdentRecord
  2023. pLevelHandle // pLevelHandle
  2024. );
  2025. LocalRuleName = L"certificate";
  2026. }
  2027. else
  2028. {
  2029. // Otherwise the result must have come from a path, hash,
  2030. // or zone rule, so we must look up the resulting GUID in our
  2031. // identity table and retrieve the SaferFlags that were stored
  2032. // along with that Identity record. But we won't panic if we
  2033. // can't actually find the GUID anymore (even though that should
  2034. // not ever be the case while we have the critical section).
  2035. PAUTHZIDENTSTABLERECORD pBestIdentRecord;
  2036. DWORD dwSaferFlags = 0;
  2037. SAFER_IDENTIFICATION_TYPES LocalIdentificationType = SaferIdentityDefault;
  2038. pBestIdentRecord = CodeAuthzIdentsLookupByGuid(
  2039. &g_CodeIdentitiesTable, &BestIdentGuid);
  2040. if (pBestIdentRecord != NULL) {
  2041. // we identified a level, and the match came from a Identity.
  2042. switch (pBestIdentRecord->dwIdentityType) {
  2043. case SaferIdentityTypeImageName:
  2044. dwSaferFlags = pBestIdentRecord->ImageNameInfo.dwSaferFlags;
  2045. LocalRuleName = L"path";
  2046. LocalIdentificationType = SaferIdentityTypeImageName;
  2047. break;
  2048. case SaferIdentityTypeImageHash:
  2049. dwSaferFlags = pBestIdentRecord->ImageHashInfo.dwSaferFlags;
  2050. LocalRuleName = L"hash";
  2051. LocalIdentificationType = SaferIdentityTypeImageHash;
  2052. break;
  2053. case SaferIdentityTypeUrlZone:
  2054. dwSaferFlags = pBestIdentRecord->ImageZone.dwSaferFlags;
  2055. LocalRuleName = L"zone";
  2056. LocalIdentificationType = SaferIdentityTypeUrlZone;
  2057. break;
  2058. default: break;
  2059. }
  2060. Status = CodeAuthzpCreateLevelHandleFromRecord(
  2061. pBestLevelRecord, // pLevelRecord
  2062. pBestIdentRecord->dwScopeId,
  2063. dwSaferFlags, // dwSaferFlags
  2064. dwExtendedError,
  2065. LocalIdentificationType,
  2066. &BestIdentGuid, // pIdentRecord
  2067. pLevelHandle // pLevelHandle
  2068. );
  2069. }
  2070. else
  2071. {
  2072. Status = STATUS_UNSUCCESSFUL;
  2073. }
  2074. }
  2075. if (NT_SUCCESS(Status)) {
  2076. ReturnValue = TRUE; // success.
  2077. }
  2078. switch(pBestLevelRecord->dwLevelId)
  2079. {
  2080. case SAFER_LEVELID_FULLYTRUSTED:
  2081. LocalLevelName = L"Unrestricted";
  2082. break;
  2083. case SAFER_LEVELID_NORMALUSER:
  2084. LocalLevelName = L"Basic User";
  2085. break;
  2086. case SAFER_LEVELID_CONSTRAINED:
  2087. LocalLevelName = L"Restricted";
  2088. break;
  2089. case SAFER_LEVELID_UNTRUSTED:
  2090. LocalLevelName = L"Untrusted";
  2091. break;
  2092. case SAFER_LEVELID_DISALLOWED:
  2093. LocalLevelName = L"Disallowed";
  2094. break;
  2095. default:
  2096. ASSERT(FALSE);
  2097. break;
  2098. }
  2099. if (pCodeProperties->ImagePath != NULL) {
  2100. LocalImageName = (PWSTR) pCodeProperties->ImagePath;
  2101. }
  2102. SaferpLogResultsToFile(
  2103. LocalImageName,
  2104. LocalLevelName,
  2105. LocalRuleName,
  2106. &BestIdentGuid);
  2107. ExitHandler2:
  2108. RtlLeaveCriticalSection(&g_TableCritSec);
  2109. ExitHandler:
  2110. if (!ReturnValue) {
  2111. BaseSetLastNTError(Status);
  2112. }
  2113. return ReturnValue;
  2114. }