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.

1700 lines
52 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. saferbox.c (WinSafer Test application)
  5. Abstract:
  6. This module implements a utility program that tests some of the
  7. major child-execution and restricted token functionality.
  8. Author:
  9. Jeffrey Lawson (JLawson) - Nov 1999
  10. John Lambert (johnla) - Nov 2000
  11. Environment:
  12. User mode only.
  13. Revision History:
  14. Created - Nov 1999
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include <wincrypt.h>
  21. #include <aclapi.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <ctype.h>
  25. #include <assert.h>
  26. #include <wintrust.h>
  27. #include <winsafer.h>
  28. #include <winsaferp.h>
  29. #include <tchar.h>
  30. #include <winuser.h>
  31. #include "resource.h"
  32. #include <crypto\wintrustp.h>
  33. #include <softpub.h> // WINTRUST_ACTION_GENERIC_VERIFY_V2
  34. HMODULE hModule=NULL;
  35. #ifdef DBG
  36. //this is some bogus stuff to help when debugging in assembly
  37. //To use this:
  38. // run cdb saferbox args
  39. //type: bp saferbox!_STACKMARK
  40. //type g (this will break when the stackmark function is called.
  41. //type t after it breaks
  42. //look at eax to know what the stackmarker is
  43. //type t two more times to exit the function
  44. DWORD _S=0;
  45. int _fastcall _STACKMARK(int a)
  46. {
  47. _S=a;
  48. return _S;
  49. }
  50. #define STACKMARK(X) _STACKMARK(X)
  51. #else
  52. #define STACKMARK(X) {}
  53. #endif
  54. //some forward declarations
  55. void __cdecl printLastErrorWithIDSMessage(UINT resID);
  56. void printLastErrorWithMessage(LPTSTR lpErrorMessage);
  57. void printLastError(void);
  58. LPTSTR getSystemMessage(long error_code)
  59. {
  60. LPVOID message;
  61. const LPTSTR defaultMessage = TEXT("Format Message failed");
  62. if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  63. NULL,
  64. error_code,
  65. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  66. (LPTSTR) &message,
  67. 0,
  68. NULL)) {
  69. message = (LPTSTR) LocalAlloc(LPTR, (_tcslen(defaultMessage) +1)* sizeof(TCHAR));
  70. _tcscpy(message, defaultMessage);
  71. return message;
  72. } else {
  73. return message;
  74. }
  75. }
  76. BOOL InitModule(void)
  77. {
  78. if(!(hModule=GetModuleHandle(NULL)))
  79. return FALSE;
  80. return TRUE;
  81. }
  82. //caller must free string with LocalFree
  83. LPTSTR AllocAndLoadStringFromModule(HINSTANCE hModule, UINT resID)
  84. {
  85. LPTSTR lpString = NULL;
  86. int cChars=0;
  87. lpString = (LPTSTR) LocalAlloc(LPTR, (MAX_USAGE_LEN + 1) * sizeof(TCHAR) );//add one for null char
  88. if (!lpString) {
  89. printLastError();
  90. return NULL;
  91. }
  92. cChars = LoadString( hModule, resID, lpString, (MAX_USAGE_LEN + 1) * sizeof(TCHAR)); //could pass in NULL for hModule here.
  93. if (cChars > 0) {
  94. //we alloc'ed a big string before, realloc the string to only the needed size
  95. lpString = (LPTSTR) LocalReAlloc(lpString, (cChars + 1) * sizeof(TCHAR) , 0);
  96. return lpString; //will be NULL on LocalReAlloc error
  97. } else {
  98. return NULL;
  99. }
  100. }
  101. //caller must free string with LocalFree
  102. LPTSTR AllocAndLoadString(UINT resID)
  103. {
  104. return AllocAndLoadStringFromModule(hModule, resID);
  105. }
  106. void IDS_printString(UINT resID)
  107. {
  108. LPTSTR lpString = NULL;
  109. lpString = AllocAndLoadString(resID);
  110. if (lpString) {
  111. _putts(lpString);
  112. } else {
  113. _tprintf(TEXT("[String resource not found: 0x%x (%d)]\n"), resID, resID);
  114. }
  115. if (lpString) LocalFree(lpString);
  116. return;
  117. }
  118. void __cdecl IDS_tprintf(UINT resID, ...)
  119. {
  120. va_list ap;
  121. LPTSTR lpString;
  122. STACKMARK(0xAABB0000);
  123. lpString = AllocAndLoadString(resID);
  124. va_start(ap, resID);
  125. if (lpString) {
  126. _vtprintf(lpString, ap);
  127. } else {
  128. _tprintf(TEXT("[String resource not found: 0x%x (%d)]\n"), resID, resID);
  129. }
  130. if (lpString) LocalFree (lpString);
  131. va_end(ap);
  132. }
  133. void __cdecl printLastErrorWithIDSMessage(UINT resID)
  134. {
  135. LPTSTR message = NULL;
  136. LPTSTR lpString = NULL;
  137. long err = GetLastError();
  138. message = getSystemMessage(err);
  139. lpString = AllocAndLoadString(resID);
  140. if (lpString) {
  141. _tprintf(TEXT("%s: 0x%X %s\n"), lpString, err, message);
  142. } else {
  143. _tprintf(TEXT("[String resource not found: 0x%x (%d)]\n"), resID, resID);
  144. _tprintf(TEXT("0x%X %s\n"), err, message);
  145. }
  146. if (message) LocalFree (message);
  147. if (lpString) LocalFree (lpString);
  148. }
  149. void printLastErrorWithMessage(LPTSTR lpErrorMessage)
  150. {
  151. LPTSTR message;
  152. long err = GetLastError();
  153. message = getSystemMessage(err);
  154. _tprintf(TEXT("%s : 0x%X %s\n"), lpErrorMessage, err, message);
  155. if (message) LocalFree (message);
  156. }
  157. void printLastError(void)
  158. {
  159. LPTSTR message;
  160. message = getSystemMessage(GetLastError());
  161. _tprintf(TEXT("Error (%d) %s\n"), GetLastError(), message);
  162. if (message) LocalFree(message);
  163. }
  164. /*++
  165. Routine Description:
  166. Displays a simple command line syntax help screen.
  167. Arguments:
  168. nothing
  169. Return Value:
  170. always returns 1.
  171. --*/
  172. int DisplaySyntax( void )
  173. {
  174. IDS_tprintf(IDS_USAGE_SYNTAX);
  175. return 1;
  176. }
  177. BOOL GetSignedFileHash(
  178. IN LPCTSTR lpzFilename,
  179. OUT BYTE rgbFileHash[SAFER_MAX_HASH_SIZE],
  180. OUT DWORD *pcbFileHash,
  181. OUT ALG_ID *pHashAlgid
  182. )
  183. {
  184. BOOL retval = TRUE;
  185. HRESULT hr;
  186. const DWORD SHA1_HASH_LEN = 20;
  187. const DWORD MD5_HASH_LEN = 16;
  188. if ( !lpzFilename || !rgbFileHash || !pcbFileHash || !pHashAlgid )
  189. return FALSE;
  190. //
  191. // Call WTHelperGetFileHash
  192. //
  193. *pcbFileHash = SAFER_MAX_HASH_SIZE;
  194. STACKMARK(0xBBBB0000);
  195. hr = WTHelperGetFileHash(
  196. (LPWSTR)lpzFilename, //TODO: convert from ANSI to UNICODE. WTHelperGetFileHash doesn't support ANSI
  197. 0,
  198. NULL,
  199. rgbFileHash,
  200. pcbFileHash,
  201. pHashAlgid);
  202. if ( SUCCEEDED (hr) )
  203. {
  204. if ( SHA1_HASH_LEN == *pcbFileHash )
  205. *pHashAlgid = CALG_SHA;
  206. else if ( MD5_HASH_LEN == *pcbFileHash )
  207. *pHashAlgid = CALG_MD5;
  208. } else {
  209. retval = FALSE;
  210. }
  211. return retval;
  212. }
  213. /*++
  214. Routine Description:
  215. Computes the MD5 hash of a given file's contents and prints the
  216. resulting hash value to the screen.
  217. Arguments:
  218. szFilename - filename to compute hash of.
  219. Return Value:
  220. Returns 0 on success, or a non-zero exit code on failure.
  221. --*/
  222. BOOL ComputeMD5Hash(IN HANDLE hFile, OUT BYTE* hashResult, OUT DWORD* pdwHashSize)
  223. {
  224. BOOL retval = TRUE;
  225. //
  226. // Open the specified file and map it into memory.
  227. //
  228. if (hFile != NULL) {
  229. HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  230. if ( hMapping ) {
  231. DWORD dwDataLen = GetFileSize (hFile, NULL);
  232. if (dwDataLen != -1) {
  233. LPBYTE pbData = (LPBYTE) MapViewOfFile (hMapping, FILE_MAP_READ, 0, 0, dwDataLen);
  234. if ( pbData ) {
  235. //
  236. // Generate the hash value of the specified file.
  237. //
  238. HCRYPTPROV hProvider = 0;
  239. if ( CryptAcquireContext(&hProvider, NULL, NULL,
  240. PROV_RSA_SIG, CRYPT_VERIFYCONTEXT) ||
  241. CryptAcquireContext(&hProvider, NULL, NULL,
  242. PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) )
  243. {
  244. HCRYPTHASH hHash = 0;
  245. if ( CryptCreateHash(hProvider, CALG_MD5, 0, 0, &hHash) ) {
  246. if ( CryptHashData (hHash, pbData, dwDataLen, 0) ) {
  247. *pdwHashSize = SAFER_MAX_HASH_SIZE;
  248. if (!CryptGetHashParam(hHash, HP_HASHVAL, hashResult, pdwHashSize, 0)) {
  249. *pdwHashSize = 0;
  250. retval = FALSE;
  251. }
  252. } else {
  253. retval = FALSE;
  254. }
  255. CryptDestroyHash(hHash);
  256. } else {
  257. retval = FALSE;
  258. }
  259. CryptReleaseContext(hProvider, 0);
  260. } else {
  261. retval = FALSE;
  262. }
  263. } else {
  264. retval = FALSE;
  265. }
  266. }
  267. CloseHandle(hMapping);
  268. }
  269. }
  270. return retval;
  271. }
  272. /*++
  273. Routine Description:
  274. Arguments:
  275. szFilename - filename to compute hash of.
  276. Return Value:
  277. Returns TRUE on success, or FALSE on failure.
  278. --*/
  279. BOOL ComputeHash( IN LPCTSTR szFilename)
  280. {
  281. BYTE hashResult[SAFER_MAX_HASH_SIZE];
  282. DWORD dwHashsize = 0;
  283. DWORD dwFilesize = 0;
  284. HANDLE hFile = NULL;
  285. BOOL retval = FALSE;
  286. ALG_ID algId = 0;
  287. BOOL result = FALSE;
  288. hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ,
  289. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  290. if (hFile) {
  291. dwFilesize= GetFileSize(hFile, NULL);
  292. result = GetSignedFileHash(szFilename, hashResult, &dwHashsize, &algId);
  293. if (!result &&
  294. (GetLastError() != TRUST_E_NOSIGNATURE) && //a recognized format, but no sig
  295. (GetLastError() != TRUST_E_SUBJECT_FORM_UNKNOWN)) //unrecognized format, don't know how to get sig
  296. {
  297. printLastError();
  298. retval = FALSE;
  299. goto ExitHandler;
  300. } else if (!result) {
  301. if (!ComputeMD5Hash(hFile, hashResult, &dwHashsize)) {
  302. printLastError();
  303. retval = FALSE;
  304. goto ExitHandler;
  305. }
  306. algId = CALG_MD5;
  307. } else {
  308. _tprintf(TEXT("This file is signed.\n"));
  309. }
  310. //
  311. // Print out the results.
  312. //
  313. if (dwHashsize != 0)
  314. {
  315. DWORD Index;
  316. _tprintf(TEXT("%s:\n"), szFilename);
  317. _tprintf(TEXT("Hash Algorithm: "));
  318. if (algId == CALG_MD5) {
  319. _tprintf(TEXT("MD5\n"));
  320. } else if (algId == CALG_SHA) {
  321. _tprintf(TEXT("SHA\n"));
  322. }
  323. _tprintf(TEXT("Hash: "));
  324. for (Index = 0; Index < dwHashsize; Index++)
  325. printf("%02X", hashResult[Index]);
  326. _tprintf(TEXT("\nFile size: "));
  327. _tprintf(TEXT("%d\n"), dwFilesize);
  328. retval = TRUE;
  329. goto ExitHandler;
  330. } else {
  331. printLastError();
  332. retval = FALSE;
  333. goto ExitHandler;
  334. }
  335. } else {
  336. printLastError();
  337. retval = FALSE;
  338. goto ExitHandler;
  339. }
  340. ExitHandler:
  341. if (hFile) CloseHandle(hFile);
  342. return retval;
  343. }
  344. /*++
  345. Routine Description:
  346. Creates the process with a given WinSafer restriction Level.
  347. Arguments:
  348. hAuthzLevel - an opened WinSafer Level handle that specifies how
  349. the specified program should be launched.
  350. appname - filename of the program to be launched.
  351. cmdline - command line supplied to the program that is launched.
  352. pi - pointer to a structure that will be filled with information
  353. about the process that is created.
  354. bStartSuspended - if this argument is TRUE, then the process will
  355. be started in a suspended state, and its primary thread must
  356. be explicitly resumed by the calling program in order to
  357. begin execution.
  358. Return Value:
  359. returns 0 on success, or a non-zero exit code on failure.
  360. --*/
  361. int CreateProcessRestricted(
  362. IN SAFER_LEVEL_HANDLE hAuthzLevel,
  363. IN LPCTSTR appname,
  364. IN LPTSTR cmdline,
  365. OUT PROCESS_INFORMATION *pi,
  366. IN BOOL bStartSuspended)
  367. {
  368. HANDLE hToken;
  369. STARTUPINFO si;
  370. // Generate the restricted token that we will use.
  371. if (!SaferComputeTokenFromLevel(
  372. hAuthzLevel, // Safer Level handle
  373. NULL, // source token
  374. &hToken, // target token
  375. 0, // no flags
  376. NULL)) // reserved
  377. {
  378. _tprintf(TEXT("Failed to compute restricted access token.\n"));
  379. return 2;
  380. }
  381. // Prepare the startup info structure.
  382. ZeroMemory(&si, sizeof(STARTUPINFO));
  383. si.cb = sizeof(STARTUPINFO);
  384. // Launch the child process under the context of the restricted token.
  385. if (!CreateProcessAsUser(
  386. hToken, // token representing the user
  387. appname, // name of executable module
  388. cmdline, // command-line string
  389. NULL, // process security attributes
  390. NULL, // thread security attributes
  391. FALSE, // if process inherits handles
  392. (bStartSuspended ? CREATE_SUSPENDED : 0), // creation flags
  393. NULL, // new environment block
  394. NULL, // current directory name
  395. &si, // startup information
  396. pi // process information
  397. ))
  398. {
  399. _tprintf(TEXT("Failed to execute child.\n"));
  400. CloseHandle(hToken);
  401. return 3;
  402. }
  403. // success.
  404. CloseHandle(hToken);
  405. return 0;
  406. }
  407. /*++
  408. Routine Description:
  409. Prints the description and friendly name associated with an
  410. opened WinSafer Level handle.
  411. Arguments:
  412. hAuthzLevel - the opened WinSafer Level handle to analyze.
  413. Return Value:
  414. does not return a value.
  415. --*/
  416. void PrintLevelNameDescription( IN SAFER_LEVEL_HANDLE hAuthzLevel, BOOL bPrintDescription)
  417. {
  418. WCHAR namebuffer[200];
  419. DWORD dwordbuffer;
  420. if (SaferGetLevelInformation(
  421. hAuthzLevel, SaferObjectLevelId,
  422. &dwordbuffer, sizeof(DWORD), NULL))
  423. {
  424. if (SaferGetLevelInformation(
  425. hAuthzLevel, SaferObjectFriendlyName,
  426. namebuffer, sizeof(namebuffer), NULL)) {
  427. IDS_tprintf(IDS_SECURITYLEVEL, namebuffer, dwordbuffer, dwordbuffer);
  428. } else {
  429. printLastErrorWithMessage(TEXT("Error getting level friendly name"));
  430. }
  431. if (bPrintDescription) {
  432. if (SaferGetLevelInformation(
  433. hAuthzLevel, SaferObjectDescription,
  434. namebuffer, sizeof(namebuffer), NULL)) {
  435. IDS_tprintf(IDS_SECURITYLEVELDESC, namebuffer);
  436. } else {
  437. printLastErrorWithMessage(TEXT("Error getting level description"));
  438. }
  439. }
  440. } else {
  441. printLastErrorWithMessage(TEXT("Error retrieving level information"));
  442. }
  443. }
  444. BOOL
  445. ListSingleIdentity(
  446. IN SAFER_LEVEL_HANDLE hAuthzLevel,
  447. IN REFGUID rEntryGuid
  448. )
  449. /*++
  450. Routine Description:
  451. Prints out details about a specific already existing Code Identity
  452. that has been defined for a WinSafer Level.
  453. Arguments:
  454. hAuthzLevel - handle of the WinSafer Level to which the indicated
  455. Code Identity GUID belongs.
  456. rEntryGuid - pointer to the GUID of the Code Identity requested.
  457. Return Value:
  458. returns TRUE on success, FALSE on failure.
  459. --*/
  460. {
  461. BOOL bRVal;
  462. DWORD dwBufferSize;
  463. SAFER_IDENTIFICATION_HEADER caiCommon;
  464. #if 0 // just testing
  465. SAFER_PATHNAME_IDENTIFICATION newimageid;
  466. ZeroMemory(&newimageid, sizeof(SAFER_PATHNAME_IDENTIFICATION));
  467. newimageid.header.cbStructSize = sizeof(SAFER_PATHNAME_IDENTIFICATION);
  468. newimageid.header.dwIdentificationType = SaferIdentityTypeImageName;
  469. CopyMemory(&newimageid.header.IdentificationGuid, rEntryGuid, sizeof(GUID));
  470. newimageid.bOnlyExeFiles = TRUE;
  471. lstrcpyW(newimageid.Description, L"new sample identity");
  472. newimageid.dwUIFlags = 42;
  473. lstrcpyW(newimageid.ImageName, L"c:\\temp\\foo\\bar.txt");
  474. bRVal = SetInformationCodeAuthzLevelW (
  475. hAuthzLevel,
  476. SaferObjectSingleIdentification,
  477. &newimageid,
  478. sizeof(newimageid));
  479. if (!bRVal) {
  480. printf("SetInformationCodeAuthzLevelW failed with error %d\n", GetLastError());
  481. } else {
  482. printf("SetInformationCodeAuthzLevelW was successful\n");
  483. }
  484. #endif
  485. #if 0 // just testing
  486. dwBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  487. ZeroMemory(&caiCommon, sizeof(SAFER_IDENTIFICATION_HEADER));
  488. caiCommon.cbStructSize = dwBufferSize;
  489. caiCommon.dwIdentificationType = 0;
  490. memcpy(&caiCommon.IdentificationGuid, rEntryGuid, sizeof(GUID));
  491. bRVal = SetInformationCodeAuthzLevelW (hAuthzLevel,
  492. SaferObjectSingleIdentification,
  493. &caiCommon,
  494. dwBufferSize);
  495. if (!bRVal) {
  496. printf("Failed to delete identity (error=%d)\n", GetLastError());
  497. } else {
  498. printf("Identity successfully deleted.\n");
  499. }
  500. #endif
  501. dwBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  502. ZeroMemory (&caiCommon, sizeof(SAFER_IDENTIFICATION_HEADER));
  503. caiCommon.cbStructSize = dwBufferSize;
  504. memcpy (&caiCommon.IdentificationGuid, rEntryGuid, sizeof (GUID));
  505. bRVal = SaferGetLevelInformation (hAuthzLevel,
  506. SaferObjectSingleIdentification,
  507. &caiCommon,
  508. dwBufferSize,
  509. &dwBufferSize);
  510. if ( !bRVal && ERROR_INSUFFICIENT_BUFFER == GetLastError () )
  511. {
  512. PBYTE pBytes = (PBYTE) LocalAlloc (LPTR, dwBufferSize);
  513. if ( pBytes )
  514. {
  515. PSAFER_IDENTIFICATION_HEADER pCommon =
  516. (PSAFER_IDENTIFICATION_HEADER) pBytes;
  517. ZeroMemory(pCommon, dwBufferSize);
  518. pCommon->cbStructSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  519. memcpy (&pCommon->IdentificationGuid, rEntryGuid, sizeof (GUID));
  520. bRVal = SaferGetLevelInformation (hAuthzLevel,
  521. SaferObjectSingleIdentification,
  522. pBytes,
  523. dwBufferSize,
  524. &dwBufferSize);
  525. if ( bRVal ) {
  526. switch (pCommon->dwIdentificationType) {
  527. case SaferIdentityTypeImageName:
  528. {
  529. PSAFER_PATHNAME_IDENTIFICATION pImageName =
  530. (PSAFER_PATHNAME_IDENTIFICATION) pCommon;
  531. ASSERT(pCommon->cbStructSize ==
  532. sizeof(SAFER_PATHNAME_IDENTIFICATION));
  533. printf(" ImageName: %S\n", pImageName->ImageName);
  534. printf("Description: %S\n", pImageName->Description);
  535. #ifdef AUTHZPOL_SAFERFLAGS_ONLY_EXES
  536. printf(" SaferFlags: %d OnlyExecutables: %s\n\n",
  537. pImageName->dwSaferFlags,
  538. (pImageName->dwSaferFlags & AUTHZPOL_SAFERFLAGS_ONLY_EXES) != 0 ? "yes" : "no");
  539. #else
  540. printf(" SaferFlags: %d\n\n",
  541. pImageName->dwSaferFlags);
  542. #endif
  543. return TRUE;
  544. }
  545. case SaferIdentityTypeImageHash:
  546. {
  547. ULONG i;
  548. PSAFER_HASH_IDENTIFICATION pImageHash =
  549. (PSAFER_HASH_IDENTIFICATION) pCommon;
  550. ASSERT(pCommon->cbStructSize ==
  551. sizeof(SAFER_HASH_IDENTIFICATION));
  552. printf(" ImageHash: ");
  553. for (i = 0; i < pImageHash->HashSize; i++) {
  554. printf("%02X ", pImageHash->ImageHash[i]);
  555. }
  556. printf("(%d bytes, ImageSize=%d bytes)\n",
  557. pImageHash->HashSize, pImageHash->ImageSize.LowPart);
  558. printf("Description: %S\n", pImageHash->Description);
  559. printf(" SaferFlags: %d\n\n", pImageHash->dwSaferFlags);
  560. return TRUE;
  561. }
  562. case SaferIdentityTypeUrlZone:
  563. {
  564. PSAFER_URLZONE_IDENTIFICATION pUrlZone =
  565. (PSAFER_URLZONE_IDENTIFICATION) pCommon;
  566. ASSERT(pCommon->cbStructSize ==
  567. sizeof(SAFER_URLZONE_IDENTIFICATION));
  568. printf(" UrlZone: %d\n", pUrlZone->UrlZoneId);
  569. printf("SaferFlags: %d\n\n", pUrlZone->dwSaferFlags);
  570. return TRUE;
  571. }
  572. default:
  573. printf(" Unexpectedly encountered identity type %d\n",
  574. pCommon->dwIdentificationType);
  575. break;
  576. }
  577. } else {
  578. printf(" GetInfo failed with LastError=%d\n", GetLastError());
  579. }
  580. LocalFree(pBytes);
  581. } else {
  582. printf(" Failed to allocate memory for query.\n");
  583. }
  584. } else {
  585. printf(" First GetInfo failed with LastError=%d\n", GetLastError());
  586. }
  587. return FALSE;
  588. }
  589. /*++
  590. Routine Description:
  591. Prints all associated Code Identifiers for a given WinSafer Level.
  592. Arguments:
  593. hAuthzLevel - the WinSafer Level handle to analyze.
  594. Return Value:
  595. returns 0.
  596. --*/
  597. int ListAllIdentities( IN SAFER_LEVEL_HANDLE hAuthzLevel)
  598. {
  599. DWORD dwInfoBufferSize;
  600. GUID *pIdentGuids;
  601. if (!SaferGetLevelInformation(
  602. hAuthzLevel,
  603. SaferObjectAllIdentificationGuids,
  604. NULL,
  605. 0,
  606. &dwInfoBufferSize) &&
  607. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  608. dwInfoBufferSize != 0)
  609. {
  610. pIdentGuids = (GUID*) HeapAlloc(GetProcessHeap(),
  611. 0, dwInfoBufferSize);
  612. if (pIdentGuids != NULL) {
  613. DWORD dwFinalBufferSize;
  614. if (SaferGetLevelInformation(
  615. hAuthzLevel,
  616. SaferObjectAllIdentificationGuids,
  617. pIdentGuids,
  618. dwInfoBufferSize,
  619. &dwFinalBufferSize))
  620. {
  621. ULONG ulNumIdentities = dwFinalBufferSize / sizeof(GUID);
  622. ULONG i;
  623. ASSERT(dwFinalBufferSize == dwInfoBufferSize);
  624. _tprintf(TEXT(" Found %d identity GUIDs.\n"), ulNumIdentities);
  625. for (i = 0; i < ulNumIdentities; i++) {
  626. if (!ListSingleIdentity(hAuthzLevel, &pIdentGuids[i])) {
  627. _tprintf(TEXT(" Failed to retrieve details on identity.\n"));
  628. }
  629. }
  630. } else {
  631. _tprintf(TEXT(" Failed to retrieve ident guid list (error=%d).\n"),
  632. GetLastError());
  633. }
  634. HeapFree( GetProcessHeap(), 0, pIdentGuids);
  635. }
  636. } else {
  637. IDS_tprintf(IDS_NORULESFOUND);
  638. }
  639. return 0;
  640. }
  641. /*++
  642. Routine Description:
  643. Prints out a list of all defined WinSafer Levels, and optionally
  644. all Code Identifiers associated with them.
  645. Arguments:
  646. bDisplayIdentifier - if this argument is TRUE, then the list of
  647. associated Code Identifiers will also be listed along with
  648. each WinSafer Level as they are enumerated.
  649. Return Value:
  650. returns 0 on success, or a non-zero exit code on failure.
  651. --*/
  652. int ListAllLevels(DWORD dwScope, BOOL bDisplayIdentifiers)
  653. {
  654. DWORD dwInfoBufferSize;
  655. LPBYTE InfoBuffer = NULL;
  656. // Fetch the list of all WinSafer LevelIds.
  657. if (!SaferGetPolicyInformation(
  658. dwScope, SaferPolicyLevelList,
  659. 0, NULL, &dwInfoBufferSize, NULL) &&
  660. GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  661. {
  662. InfoBuffer = (LPBYTE) HeapAlloc(GetProcessHeap(), 0, dwInfoBufferSize);
  663. if (InfoBuffer != NULL)
  664. {
  665. DWORD dwInfoBufferSize2;
  666. if (!SaferGetPolicyInformation(
  667. dwScope, SaferPolicyLevelList,
  668. dwInfoBufferSize, InfoBuffer, &dwInfoBufferSize2, NULL))
  669. {
  670. _tprintf(TEXT("Failed to retrieve Level list (error=%d)\n"),
  671. GetLastError());
  672. HeapFree(GetProcessHeap(), 0, InfoBuffer);
  673. InfoBuffer = NULL;
  674. }
  675. ASSERTMSG("got different final size",
  676. dwInfoBufferSize2 == dwInfoBufferSize);
  677. ASSERTMSG("expecting whole number of DWORD values",
  678. dwInfoBufferSize % sizeof(DWORD) == 0);
  679. dwInfoBufferSize = dwInfoBufferSize2;
  680. } else {
  681. _tprintf(TEXT("Failed to allocate %d bytes of memory.\n"), dwInfoBufferSize);
  682. return 1;
  683. }
  684. }
  685. // Iterate through and add all of the items.
  686. if (InfoBuffer != NULL) {
  687. PDWORD pLevelIdList = (PDWORD) InfoBuffer;
  688. DWORD Index;
  689. for (Index = 0; Index < dwInfoBufferSize / sizeof(DWORD); Index++) {
  690. SAFER_LEVEL_HANDLE hAuthzLevel;
  691. WCHAR namebuffer[200];
  692. DWORD dwLevelId = pLevelIdList[Index];
  693. if (SaferCreateLevel(dwScope, dwLevelId,
  694. SAFER_LEVEL_OPEN, &hAuthzLevel, NULL))
  695. {
  696. _tprintf(TEXT("\n"));
  697. PrintLevelNameDescription(hAuthzLevel, !bDisplayIdentifiers);
  698. /*
  699. if (SaferGetLevelInformation(hAuthzLevel, SaferObjectFriendlyName,
  700. namebuffer, sizeof(namebuffer), NULL))
  701. _tprintf(TEXT("LevelId %d: \"%s\"\n"), dwLevelId, namebuffer);
  702. else
  703. _tprintf(TEXT("LevelId %d: unknown\n"), dwLevelId);
  704. */
  705. if (bDisplayIdentifiers) {
  706. ListAllIdentities(hAuthzLevel);
  707. }
  708. SaferCloseLevel(hAuthzLevel);
  709. } else {
  710. _tprintf(TEXT("LevelId %d: unknown\n"), dwLevelId);
  711. }
  712. }
  713. HeapFree(GetProcessHeap(), 0, InfoBuffer);
  714. // Fetch the default level
  715. //TODO: for some reason my default level isn't in the registry and this part returns NOT_FOUND
  716. dwInfoBufferSize=0;
  717. STACKMARK(0xAAAC0000);
  718. if (!SaferGetPolicyInformation(
  719. dwScope, SaferPolicyDefaultLevel,
  720. 0, NULL, &dwInfoBufferSize, NULL) &&
  721. GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  722. {
  723. SAFER_LEVEL_HANDLE hAuthzLevel;
  724. DWORD dwLevelId = 0;
  725. InfoBuffer = (LPBYTE) HeapAlloc(GetProcessHeap(), 0, dwInfoBufferSize);
  726. if (InfoBuffer != NULL)
  727. {
  728. if (!SaferGetPolicyInformation(
  729. dwScope, SaferPolicyDefaultLevel,
  730. dwInfoBufferSize, InfoBuffer, &dwInfoBufferSize, NULL))
  731. {
  732. _tprintf(TEXT("Failed to retrieve default level (error=%d)\n"), GetLastError());
  733. HeapFree(GetProcessHeap(), 0, InfoBuffer);
  734. InfoBuffer = NULL;
  735. return 1;
  736. } else {
  737. ASSERT(dwInfoBufferSize==sizeof(dwLevelId));
  738. memcpy(&dwLevelId,InfoBuffer, dwInfoBufferSize);
  739. if (SaferCreateLevel(dwScope, dwLevelId,
  740. SAFER_LEVEL_OPEN, &hAuthzLevel, NULL))
  741. {
  742. _tprintf(TEXT("\n"));
  743. IDS_tprintf(IDS_DEFAULTLEVEL);
  744. PrintLevelNameDescription(hAuthzLevel, FALSE);
  745. }
  746. }
  747. SaferCloseLevel(hAuthzLevel);
  748. } else {
  749. _tprintf(TEXT("Failed to allocate %d bytes of memory.\n"), dwInfoBufferSize);
  750. return 1;
  751. }
  752. } else {
  753. printLastErrorWithMessage(TEXT("Failed to retrieve default level"));
  754. return 1;
  755. }
  756. return 0;
  757. }
  758. _tprintf(TEXT("No Levels found in this scope.\n"));
  759. return 1;
  760. }
  761. BOOL PrintMatchingRule(
  762. IN SAFER_LEVEL_HANDLE hAuthzLevel)
  763. {
  764. DWORD dwBufferSize=0;
  765. UNICODE_STRING UnicodeTemp;
  766. WCHAR lpzGuid[200];
  767. PSAFER_IDENTIFICATION_HEADER lpQueryBuf=NULL;
  768. SAFER_IDENTIFICATION_HEADER comheader;
  769. STACKMARK(0xAAAB0000);
  770. memset(&comheader,0,sizeof(SAFER_IDENTIFICATION_HEADER));
  771. comheader.cbStructSize=sizeof(SAFER_IDENTIFICATION_HEADER);
  772. dwBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
  773. if (!SaferGetLevelInformation(
  774. hAuthzLevel, SaferObjectSingleIdentification, &comheader, dwBufferSize, &dwBufferSize)) {
  775. printLastError();
  776. return FALSE;
  777. }
  778. if (GetLastError() == ERROR_NOT_FOUND) {
  779. IDS_tprintf(IDS_USINGDEFAULTRULE);
  780. } else {
  781. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER &&
  782. GetLastError() != ERROR_SUCCESS) {
  783. printLastError();
  784. return FALSE;
  785. }
  786. ASSERT(dwBufferSize >= sizeof (SAFER_IDENTIFICATION_HEADER));
  787. lpQueryBuf = (PSAFER_IDENTIFICATION_HEADER)LocalAlloc(LPTR, dwBufferSize );
  788. if (!lpQueryBuf) {
  789. printLastError();
  790. return FALSE;
  791. }
  792. lpQueryBuf->cbStructSize = dwBufferSize;
  793. if (!SaferGetLevelInformation(hAuthzLevel, SaferObjectSingleIdentification, lpQueryBuf, dwBufferSize, &dwBufferSize) ) {
  794. printLastError();
  795. return FALSE;
  796. }
  797. UnicodeTemp.Buffer=(PWSTR)lpzGuid;
  798. UnicodeTemp.MaximumLength = sizeof(lpzGuid);
  799. RtlStringFromGUID (&(lpQueryBuf->IdentificationGuid),&UnicodeTemp);
  800. //TODO: could print out whether rule was from CU or LM
  801. if (lpQueryBuf->dwIdentificationType == SaferIdentityTypeImageName) {
  802. IDS_tprintf(IDS_MATCHPATH, ((PSAFER_PATHNAME_IDENTIFICATION)lpQueryBuf)->ImageName);
  803. } else if (lpQueryBuf->dwIdentificationType == SaferIdentityTypeImageHash ){
  804. IDS_tprintf(IDS_MATCHHASH);
  805. } else if (lpQueryBuf->dwIdentificationType == SaferIdentityTypeUrlZone ){
  806. IDS_tprintf(IDS_MATCHZONE);
  807. } else {
  808. //must be a publisher certificate rule.
  809. IDS_tprintf(IDS_MATCHCERTORDEFAULT);
  810. }
  811. IDS_tprintf(IDS_GUIDRULEIS,UnicodeTemp.Buffer);
  812. LocalFree(lpQueryBuf);
  813. }
  814. _tprintf(TEXT("\n"));
  815. PrintLevelNameDescription(hAuthzLevel, TRUE);
  816. return TRUE;
  817. }
  818. //VerifyVersionInfo
  819. BOOL IsMinimumVersion()
  820. {
  821. DWORD tmp;
  822. LPVOID lpVerInfo = NULL;
  823. LPVOID lpValue = NULL;
  824. LPTSTR lpFileToVersion = TEXT("advapi32.dll");
  825. UINT uLen;
  826. //must be at least post beta 1 of whistler
  827. const DWORD PROD_MAJOR = 5;
  828. const DWORD PROD_MINOR = 1;
  829. const DWORD BUILD_MAJOR = 2400;
  830. DWORD dwBuildMajor=0, dwProductMajor=0, dwProductMinor=0;
  831. DWORD dwSize = GetFileVersionInfoSize(lpFileToVersion, &tmp);
  832. if (!dwSize) {
  833. printLastErrorWithIDSMessage(IDS_ERR_GETVERERR);
  834. return FALSE;
  835. }
  836. lpVerInfo = (LPVOID) LocalAlloc(LPTR, dwSize);
  837. if (!lpVerInfo) {
  838. printLastError();
  839. return FALSE;
  840. }
  841. if (! GetFileVersionInfo(lpFileToVersion, 0, dwSize, lpVerInfo)) {
  842. printLastErrorWithIDSMessage(IDS_ERR_GETVERERR);
  843. if (lpVerInfo) LocalFree(lpVerInfo);
  844. return FALSE;
  845. }
  846. if (!VerQueryValue(lpVerInfo, TEXT("\\"), &lpValue, &uLen)) { // '\' indicates the root version info block
  847. printLastErrorWithIDSMessage(IDS_ERR_GETVERERR);
  848. if (lpVerInfo) LocalFree(lpVerInfo);
  849. return FALSE;
  850. }
  851. /*
  852. _tprintf(TEXT("dwFileVersionMS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwFileVersionMS) >> 16);
  853. _tprintf(TEXT("dwFileVersionMS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwFileVersionMS) & 0x0000FFFF);
  854. _tprintf(TEXT("dwFileVersionLS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwFileVersionLS) >> 16);
  855. _tprintf(TEXT("dwFileVersionLS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwFileVersionLS) & 0x0000FFFF);
  856. _tprintf(TEXT("dwProductVersionMS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionMS) >>16);
  857. _tprintf(TEXT("dwProductVersionMS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionMS) & 0x0000FFFF);
  858. _tprintf(TEXT("dwProductVersionLS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionLS) >>16);
  859. _tprintf(TEXT("dwProductVersionLS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionLS) & 0x0000FFFF);
  860. */
  861. dwProductMajor = (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionMS) >>16;
  862. dwProductMinor = (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionMS) & 0x0000FFFF;
  863. dwBuildMajor = (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionLS) >>16;
  864. if ((dwProductMajor < PROD_MAJOR) ||
  865. (dwProductMajor == PROD_MAJOR && dwProductMinor < PROD_MINOR ) ||
  866. (dwProductMinor == PROD_MAJOR && dwProductMinor == PROD_MINOR && dwBuildMajor < BUILD_MAJOR)) {
  867. IDS_tprintf(IDS_ERR_INCORRECTOSVER, dwProductMajor, dwProductMinor, dwBuildMajor, PROD_MAJOR, PROD_MINOR, BUILD_MAJOR);
  868. if (lpVerInfo) LocalFree(lpVerInfo);
  869. return FALSE;
  870. } else {
  871. if (lpVerInfo) LocalFree(lpVerInfo);
  872. return TRUE;
  873. }
  874. }
  875. BOOL GetPathFromKeyKey(LPCTSTR lpzRegKey)
  876. {
  877. HKEY hKey, hKeyHive;
  878. LPTSTR lpKeyname=NULL;
  879. LPCTSTR LP_CU_HIVE = TEXT("%HKEY_CURRENT_USER");
  880. LPCTSTR LP_LM_HIVE = TEXT("%HKEY_LOCAL_MACHINE");
  881. LPCTSTR lpLastPercentSign=NULL;
  882. BYTE buffer[MAX_PATH];
  883. LPTSTR lpValue;
  884. DWORD dwBufferSize = sizeof(buffer);
  885. LPTSTR lpHivename;
  886. LONG retval;
  887. memset(buffer, 0, dwBufferSize);
  888. lpHivename = _tcsstr(lpzRegKey, LP_CU_HIVE);
  889. if (lpHivename != NULL) {
  890. hKeyHive = HKEY_CURRENT_USER;
  891. lpKeyname = _tcsdup(&lpzRegKey[_tcslen(LP_CU_HIVE)+1]); //remove '\' char in front
  892. } else {
  893. lpHivename = _tcsstr(lpzRegKey, LP_LM_HIVE);
  894. if (lpHivename != NULL) {
  895. hKeyHive = HKEY_LOCAL_MACHINE;
  896. lpKeyname = _tcsdup(&lpzRegKey[_tcslen(LP_LM_HIVE)+1]); //remove '\' char in front
  897. } else {
  898. IDS_tprintf(IDS_ERR_REGNOTFOUND);
  899. return FALSE;
  900. }
  901. }
  902. lpLastPercentSign = wcsrchr(lpzRegKey,'%');
  903. if (lpLastPercentSign != &lpzRegKey[wcslen(lpzRegKey)-1]) {
  904. _tprintf(TEXT("bad substitution char.\n"));
  905. return FALSE;
  906. }
  907. lpValue = _tcsrchr(lpKeyname, '\\');
  908. if (lpValue==NULL) {
  909. IDS_tprintf(IDS_ERR_REGNOTFOUND);
  910. return FALSE;
  911. }
  912. *lpValue = '\0';
  913. lpValue = lpValue + 1;
  914. lpValue[wcslen(lpValue)-1] = '\0';
  915. if (retval = RegOpenKeyEx(hKeyHive,
  916. lpKeyname,
  917. 0,
  918. KEY_READ,
  919. &hKey))
  920. {
  921. SetLastError(retval);
  922. printLastError();
  923. return FALSE;
  924. } else {
  925. if (retval = RegQueryValueEx(hKey,
  926. lpValue,
  927. NULL,
  928. NULL,
  929. buffer,
  930. &dwBufferSize))
  931. {
  932. SetLastError(retval);
  933. printLastError();
  934. return FALSE;
  935. } else {
  936. _tprintf(TEXT("\n"));
  937. IDS_tprintf(IDS_REGVALUE);
  938. _tprintf(TEXT("%s"), buffer);
  939. }
  940. }
  941. free(lpKeyname);
  942. RegCloseKey(hKey);
  943. return TRUE;
  944. }
  945. void PrintAndRecurse(HKEY hkey, LPCWSTR lpParentKeyname)
  946. {
  947. DWORD cValue=MAX_PATH;
  948. DWORD cKey=MAX_PATH;
  949. DWORD cbData=100;
  950. LPWSTR lpValue[MAX_PATH * sizeof(WCHAR)];
  951. LPWSTR lpKey[MAX_PATH * sizeof(WCHAR)];
  952. LPWSTR lpFullKey[MAX_PATH * sizeof(WCHAR)];
  953. LPBYTE lpData=NULL;
  954. DWORD idx=0;
  955. DWORD dwType=0;
  956. DWORD retval=0;
  957. FILETIME filetime;
  958. BOOL bDone=FALSE;
  959. HKEY nextKey=NULL;
  960. DWORD dwNumSubKeys=0;
  961. DWORD dwNumValues=0;
  962. DWORD dwMaxValueLen=0;
  963. RegQueryInfoKey(hkey,NULL,NULL, NULL, &dwNumSubKeys, NULL, NULL, &dwNumValues,NULL, &dwMaxValueLen, NULL,NULL);
  964. do {
  965. lpValue[0]=L"\0";
  966. cbData = dwMaxValueLen;
  967. lpData = (LPBYTE)LocalAlloc(LPTR, dwMaxValueLen);
  968. if (!lpData) {
  969. printLastError();
  970. return;
  971. }
  972. cValue=MAX_PATH;
  973. retval = RegEnumValue(hkey,
  974. idx,
  975. (LPWSTR)lpValue,
  976. &cValue,
  977. NULL,
  978. &dwType,
  979. lpData,
  980. &cbData);
  981. if (retval==ERROR_NO_MORE_ITEMS) {
  982. bDone=TRUE;
  983. } else if (retval != ERROR_SUCCESS) {
  984. SetLastError(retval);
  985. bDone=TRUE;
  986. printLastError();
  987. }
  988. if (!bDone) {
  989. wprintf(L"\t%s",lpValue);
  990. switch (dwType)
  991. {
  992. case REG_DWORD:
  993. {
  994. DWORD dwValue;
  995. memcpy(&dwValue,lpData, sizeof(DWORD));
  996. wprintf(L" : 0x%08X\n", dwValue);
  997. }
  998. break;
  999. case REG_QWORD:
  1000. {
  1001. __int64 qwValue;
  1002. memcpy(&qwValue, lpData, sizeof(__int64));
  1003. wprintf(L" : 0x%I64x\n", qwValue);
  1004. }
  1005. break;
  1006. case REG_BINARY:
  1007. wprintf(L" : ");
  1008. { int i;
  1009. for (i=0;i<(int)cbData;i++) {
  1010. wprintf(L"%02X", *(lpData+i));
  1011. }
  1012. wprintf(L"\n");
  1013. }
  1014. break;
  1015. case REG_SZ:
  1016. case REG_EXPAND_SZ:
  1017. wprintf(L" : %s\n", lpData);
  1018. break;
  1019. case REG_MULTI_SZ:
  1020. {int idx=0;
  1021. LPWSTR lpMultiPtr=(LPWSTR)lpData;
  1022. WCHAR nullchar = L'\0';
  1023. wprintf(L" : ");
  1024. do {
  1025. wprintf(L" %s ", lpMultiPtr);
  1026. lpMultiPtr+=wcslen(lpMultiPtr)+1 ;
  1027. } while (*(lpMultiPtr+1)!=0);
  1028. wprintf(L"\n");
  1029. }
  1030. break;
  1031. default:
  1032. wprintf(L" ??????: 0x%X\n", lpData);
  1033. }
  1034. if (lpData) LocalFree(lpData);
  1035. idx++;
  1036. }
  1037. } while (!bDone);
  1038. if (dwNumSubKeys != 0) {
  1039. idx=0;
  1040. bDone=FALSE;
  1041. do {
  1042. lpKey[0]=L"\0";
  1043. cKey=MAX_PATH;
  1044. retval = RegEnumKeyEx(hkey,
  1045. idx,
  1046. (LPWSTR)lpKey,
  1047. &cKey,
  1048. NULL,
  1049. NULL,
  1050. NULL,
  1051. &filetime);
  1052. if (retval==ERROR_NO_MORE_ITEMS) {
  1053. bDone=TRUE;
  1054. } else if (retval != ERROR_SUCCESS) {
  1055. SetLastError(retval);
  1056. bDone=TRUE;
  1057. printLastError();
  1058. }
  1059. if (!bDone) {
  1060. wprintf(L"%s\\%s\n",lpParentKeyname,lpKey);
  1061. if (RegOpenKeyEx(hkey,
  1062. (LPWSTR)lpKey,
  1063. 0,
  1064. KEY_READ,
  1065. &nextKey))
  1066. {
  1067. bDone=TRUE;
  1068. printLastError();
  1069. return;
  1070. } else {
  1071. memset(lpFullKey,0,sizeof(lpFullKey));
  1072. wcscat((LPWSTR)lpFullKey, lpParentKeyname);
  1073. wcscat((LPWSTR)lpFullKey, L"\\");
  1074. wcscat((LPWSTR)lpFullKey, (LPWSTR)lpKey);
  1075. wcscat((LPWSTR)lpFullKey, L"\0");
  1076. PrintAndRecurse(nextKey, (LPWSTR)lpFullKey);
  1077. RegCloseKey(nextKey);
  1078. }
  1079. idx++;
  1080. }
  1081. } while (!bDone);
  1082. }
  1083. }
  1084. LONG DumpRegistry()
  1085. {
  1086. DWORD class,subkeys,maxsubkeylen, numvalues, maxvaluename, maxvaluedatalen;
  1087. const UNICODE_STRING HKLMSAFERKey = RTL_CONSTANT_STRING(SAFER_HKLM_REGBASE);
  1088. const UNICODE_STRING HKCUSAFERKey = RTL_CONSTANT_STRING(SAFER_HKCU_REGBASE);
  1089. const UNICODE_STRING HKPublisherKey = RTL_CONSTANT_STRING(L"Software\\Policies\\Microsoft\\SystemCertificates\\TrustedPublisher\\Certificates");
  1090. HKEY hkey;
  1091. int i;
  1092. if (!RegOpenKeyEx(HKEY_CURRENT_USER,
  1093. HKCUSAFERKey.Buffer,
  1094. 0,
  1095. KEY_READ,
  1096. &hkey))
  1097. {
  1098. IDS_tprintf(IDS_LISTING_HKCU);
  1099. wprintf(L"%s\n",HKCUSAFERKey.Buffer);
  1100. PrintAndRecurse(hkey, HKCUSAFERKey.Buffer);
  1101. RegCloseKey(hkey);
  1102. }
  1103. if (!RegOpenKeyEx(HKEY_CURRENT_USER,
  1104. HKPublisherKey.Buffer,
  1105. 0,
  1106. KEY_READ,
  1107. &hkey))
  1108. {
  1109. wprintf(L"%s\n",HKPublisherKey.Buffer);
  1110. PrintAndRecurse(hkey, HKPublisherKey.Buffer);
  1111. RegCloseKey(hkey);
  1112. }
  1113. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1114. HKLMSAFERKey.Buffer,
  1115. 0,
  1116. KEY_READ,
  1117. &hkey))
  1118. {
  1119. wprintf(L"\n");
  1120. IDS_tprintf(IDS_LISTING_HKLM);
  1121. wprintf(L"%s\n",HKLMSAFERKey.Buffer);
  1122. PrintAndRecurse(hkey, HKCUSAFERKey.Buffer);
  1123. RegCloseKey(hkey);
  1124. }
  1125. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1126. HKPublisherKey.Buffer,
  1127. 0,
  1128. KEY_READ,
  1129. &hkey))
  1130. {
  1131. wprintf(L"%s\n",HKPublisherKey.Buffer);
  1132. PrintAndRecurse(hkey, HKPublisherKey.Buffer);
  1133. RegCloseKey(hkey);
  1134. }
  1135. return ERROR_SUCCESS;
  1136. }
  1137. /*++
  1138. Routine Description:
  1139. Main entry point.
  1140. Arguments:
  1141. argc - count of command line arguments.
  1142. argv - pointers to command line arguments.
  1143. Return Value:
  1144. returns the program exit code.
  1145. --*/
  1146. int __cdecl _tmain(int argc, _TCHAR **argv, _TCHAR **envp)
  1147. {
  1148. PROCESS_INFORMATION pi;
  1149. DWORD dwLevelId = 0;
  1150. BOOL fLevelIdSupplied = FALSE;
  1151. _TCHAR appname[MAX_PATH];
  1152. _TCHAR cmdline[1024];
  1153. LPTSTR lpRegkey=NULL;
  1154. int nextarg;
  1155. SAFER_LEVEL_HANDLE hAuthzLevel;
  1156. int retval;
  1157. DWORD dwSuppliedCheckFlags=0;
  1158. DWORD dwScopeId=(DWORD)-1; //means check both LM + CU
  1159. BOOL useBreakMode = FALSE;
  1160. enum { CMD_RUN, CMD_QUERY, CMD_HASH, CMD_LIST, CMD_LISTRULES, CMD_REGKEY, CMD_DUMPREG }
  1161. commandMode = -1;
  1162. LPTSTR A_LP_CMD_QUERY = AllocAndLoadString(IDS_CMD_QUERY);
  1163. LPTSTR A_LP_CMD_RUN= AllocAndLoadString(IDS_CMD_RUN);
  1164. LPTSTR A_LP_CMD_HASH= AllocAndLoadString(IDS_CMD_HASH);
  1165. LPTSTR A_LP_CMD_LIST= AllocAndLoadString(IDS_CMD_LIST);
  1166. LPTSTR A_LP_CMD_LISTRULES= AllocAndLoadString(IDS_CMD_LISTRULES);
  1167. LPTSTR A_LP_CMD_REGKEY= AllocAndLoadString(IDS_CMD_REGKEY );
  1168. LPTSTR A_LP_CMD_DUMPREG= AllocAndLoadString(IDS_CMD_DUMPREG );
  1169. LPTSTR A_LP_FLAG_LEVELID= AllocAndLoadString(IDS_FLAG_LEVELID);
  1170. LPTSTR A_LP_FLAG_RULETYPES= AllocAndLoadString(IDS_FLAG_RULETYPES);
  1171. LPTSTR A_LP_RULETYPES_PATH= AllocAndLoadString(IDS_RULETYPES_PATH);
  1172. LPTSTR A_LP_RULETYPES_HASH= AllocAndLoadString(IDS_RULETYPES_HASH);
  1173. LPTSTR A_LP_RULETYPES_CERTIFICATE= AllocAndLoadString(IDS_RULETYPES_CERTIFICATE);
  1174. LPTSTR A_LP_FLAG_SCOPE= AllocAndLoadString(IDS_FLAG_SCOPE);
  1175. LPTSTR A_LP_SCOPE_HKLM= AllocAndLoadString(IDS_SCOPE_HKLM);
  1176. LPTSTR A_LP_SCOPE_HKCU= AllocAndLoadString(IDS_SCOPE_HKCU);
  1177. UNREFERENCED_PARAMETER(envp);
  1178. STACKMARK(0xAAAA0001);
  1179. //IDS_tprintf(IDS_TEST1,66,TEXT("hellow"),45456); //test string
  1180. //get the module handle
  1181. if(!InitModule()) {
  1182. return 1;
  1183. }
  1184. // if we are going to run in an altered registry
  1185. // scope, open and set it now.
  1186. /*
  1187. if (dwScopeId == SAFER_SCOPEID_REGISTRY) {
  1188. HKEY hkeyBase;
  1189. if (RegOpenKeyExW(HKEY_CURRENT_USER, L"TestKey",
  1190. 0, KEY_READ, &hkeyBase) != ERROR_SUCCESS) {
  1191. _tprintf(TEXT("Failed to open registry scope key (error=%d)\n"),
  1192. GetLastError());
  1193. return 1;
  1194. }
  1195. if (!CodeAuthzChangeRegistryScope(hkeyBase)) {
  1196. _tprintf(TEXT("Failed to change registry scope (error=%d)\n"),
  1197. GetLastError());
  1198. return 1;
  1199. }
  1200. RegCloseKey(hkeyBase);
  1201. }
  1202. */
  1203. if (!IsMinimumVersion()) {
  1204. return 1;
  1205. }
  1206. // quick check of command line length.
  1207. if (argc < 2) {
  1208. _tprintf(TEXT("No arguments.\n"));
  1209. return DisplaySyntax();
  1210. }
  1211. // Parse the command line.
  1212. appname[0] = '\0';
  1213. cmdline[0] = '\0';
  1214. for (nextarg = 1; nextarg < argc; nextarg++) {
  1215. if (_tcsicmp(argv[nextarg],A_LP_CMD_QUERY) == 0 ) {
  1216. commandMode = CMD_QUERY;
  1217. } else if (_tcsicmp(argv[nextarg],A_LP_CMD_RUN) == 0 ) {
  1218. commandMode = CMD_RUN;
  1219. } else if (_tcsicmp(argv[nextarg],A_LP_CMD_HASH) == 0 ) {
  1220. commandMode = CMD_HASH;
  1221. } else if (_tcsicmp(argv[nextarg],A_LP_CMD_DUMPREG) == 0 ) {
  1222. commandMode = CMD_DUMPREG;
  1223. } else if (_tcsicmp(argv[nextarg],A_LP_CMD_REGKEY) == 0 ) {
  1224. commandMode = CMD_REGKEY;
  1225. nextarg++;
  1226. if (nextarg!=argc) {
  1227. lpRegkey = argv[nextarg];
  1228. } else {
  1229. return DisplaySyntax();
  1230. }
  1231. } else if (_tcsicmp(argv[nextarg],A_LP_CMD_LIST) == 0 ) {
  1232. commandMode = CMD_LIST;
  1233. } else if (_tcsicmp(argv[nextarg],A_LP_CMD_LISTRULES) == 0 ) {
  1234. commandMode = CMD_LISTRULES;
  1235. } else if (argv[nextarg][0] == '-' || argv[nextarg][0] == '/') {
  1236. if (_tcsicmp(&argv[nextarg][1], A_LP_FLAG_LEVELID) == 0) {
  1237. STACKMARK(0xAAAA000D);
  1238. dwLevelId = _ttoi(argv[++nextarg]);
  1239. fLevelIdSupplied = TRUE;
  1240. } else if (_tcsicmp(&argv[nextarg][1], A_LP_FLAG_RULETYPES) == 0) {
  1241. STACKMARK(0xAAAA000B);
  1242. nextarg++;
  1243. if (nextarg >= argc) {
  1244. return DisplaySyntax();
  1245. }
  1246. //unknown rule types are ignored
  1247. if (_tcscspn(argv[nextarg], A_LP_RULETYPES_PATH) < _tcslen(argv[nextarg])) {
  1248. dwSuppliedCheckFlags = dwSuppliedCheckFlags | SAFER_CRITERIA_IMAGEPATH;
  1249. }
  1250. if (_tcscspn(argv[nextarg], A_LP_RULETYPES_HASH) < _tcslen(argv[nextarg])) {
  1251. dwSuppliedCheckFlags = dwSuppliedCheckFlags | SAFER_CRITERIA_IMAGEHASH;
  1252. }
  1253. if (_tcscspn(argv[nextarg], A_LP_RULETYPES_CERTIFICATE) < _tcslen(argv[nextarg] )) {
  1254. dwSuppliedCheckFlags = dwSuppliedCheckFlags | SAFER_CRITERIA_AUTHENTICODE;
  1255. }
  1256. } else if (_tcsicmp(&argv[nextarg][1], A_LP_FLAG_SCOPE) == 0) {
  1257. nextarg++;
  1258. if (nextarg >= argc) {
  1259. return DisplaySyntax();
  1260. }
  1261. STACKMARK(0xAAAA000F);
  1262. if (_tcscspn(argv[nextarg], A_LP_SCOPE_HKLM) < _tcslen(argv[nextarg])) {
  1263. dwScopeId = SAFER_SCOPEID_MACHINE;
  1264. } else if (_tcscspn(argv[nextarg], A_LP_SCOPE_HKCU) < _tcslen(argv[nextarg])) {
  1265. dwScopeId = SAFER_SCOPEID_USER;
  1266. } else {
  1267. return DisplaySyntax();
  1268. }
  1269. } else {
  1270. return DisplaySyntax();
  1271. }
  1272. } else if (commandMode==CMD_RUN || commandMode == CMD_QUERY || commandMode == CMD_HASH) {
  1273. LPTSTR fn;
  1274. STACKMARK(0xAAAA000C);
  1275. if (commandMode==CMD_RUN && !fLevelIdSupplied) {
  1276. IDS_tprintf(IDS_ERR_NOLEVELID);
  1277. return DisplaySyntax();
  1278. }
  1279. //
  1280. // This argument is an explicitly named application exe.
  1281. //
  1282. // if (!GetFullPathName(argv[nextarg],
  1283. // sizeof(appname) / sizeof(appname[0]),
  1284. // appname, &fn) &&
  1285. if (!SearchPath(NULL, argv[nextarg], NULL,
  1286. sizeof(appname) / sizeof(appname[0]),
  1287. appname, &fn)) {
  1288. STACKMARK(0xAAAA000A);
  1289. appname[0] = 0;
  1290. } else {
  1291. _tprintf(TEXT("Program to launch: %s\n"),appname);
  1292. }
  1293. if (commandMode == CMD_RUN) {
  1294. //
  1295. // All following arguments is the child's command line.
  1296. //
  1297. nextarg++;
  1298. if (nextarg > argc) {
  1299. return DisplaySyntax();
  1300. }
  1301. for (; nextarg < argc; nextarg++) {
  1302. if (_tcslen(cmdline) + _tcslen(argv[nextarg]) + 2 < sizeof(cmdline)) {
  1303. if (cmdline[0]) {
  1304. _tcscat(cmdline, TEXT(" "));
  1305. }
  1306. _tcscat(cmdline, argv[nextarg]);
  1307. } else {
  1308. IDS_tprintf(IDS_ERR_CMDLINETOOLONG);
  1309. return 0;
  1310. }
  1311. }
  1312. break;
  1313. }
  1314. } else {
  1315. // Unknown garbage encountered at the end of the line.
  1316. return DisplaySyntax();
  1317. }
  1318. }
  1319. STACKMARK(0xAAAA0002);
  1320. //
  1321. // Application exe must always be specified for some cases.
  1322. //
  1323. if (commandMode == CMD_RUN || commandMode == CMD_QUERY || commandMode == CMD_HASH) {
  1324. if (appname == NULL || appname[0] == '\0') {
  1325. IDS_tprintf(IDS_ERR_NOAPPNAME);
  1326. return DisplaySyntax();
  1327. }
  1328. }
  1329. switch (commandMode) {
  1330. case CMD_HASH:
  1331. return ComputeHash(appname);
  1332. break;
  1333. case CMD_DUMPREG:
  1334. return DumpRegistry();
  1335. break;
  1336. case CMD_REGKEY:
  1337. return GetPathFromKeyKey(lpRegkey);
  1338. break;
  1339. case CMD_LIST:
  1340. case CMD_LISTRULES:
  1341. if (dwScopeId == -1) {
  1342. _tprintf(TEXT("\n"));
  1343. IDS_tprintf(IDS_LISTING_HKCU);
  1344. retval = ListAllLevels(SAFER_SCOPEID_USER, commandMode == CMD_LISTRULES);
  1345. _tprintf(TEXT("\n"));
  1346. IDS_tprintf(IDS_LISTING_HKLM);
  1347. retval = ListAllLevels(SAFER_SCOPEID_MACHINE, commandMode == CMD_LISTRULES);
  1348. } else {
  1349. retval = ListAllLevels(dwScopeId, commandMode == CMD_LISTRULES);
  1350. }
  1351. break;
  1352. case CMD_QUERY:
  1353. {
  1354. SAFER_CODE_PROPERTIES codeproperties;
  1355. STACKMARK(0xAAAA0003);
  1356. ASSERT(appname != NULL);
  1357. // prepare the code properties struct.
  1358. memset(&codeproperties, 0, sizeof(codeproperties));
  1359. codeproperties.cbSize = sizeof(codeproperties);
  1360. codeproperties.dwCheckFlags = (!dwSuppliedCheckFlags) ? SAFER_CRITERIA_IMAGEPATH | SAFER_CRITERIA_IMAGEHASH | SAFER_CRITERIA_AUTHENTICODE : dwSuppliedCheckFlags;
  1361. codeproperties.ImagePath = appname;
  1362. codeproperties.dwWVTUIChoice = WTD_UI_ALL; //ignored if SAFER_CRITERIA_AUTHENTICODE is not passed in
  1363. // Ask the system to find the authorization Level that classifies it.
  1364. if (!SaferIdentifyLevel(1, &codeproperties, &hAuthzLevel, NULL))
  1365. {
  1366. if (GetLastError() == ERROR_NOT_FOUND) {
  1367. IDS_tprintf(IDS_ERR_NOLEVELSFOUND);
  1368. } else {
  1369. printLastErrorWithIDSMessage(IDS_ERR_IMGACCESSERR);
  1370. }
  1371. return 1;
  1372. }
  1373. //print information about the rule that matched the program
  1374. if (!PrintMatchingRule(hAuthzLevel)) {
  1375. printLastErrorWithIDSMessage(IDS_ERR_ERRMATCHRULE);
  1376. return 1;
  1377. }
  1378. SaferCloseLevel(hAuthzLevel);
  1379. }
  1380. break;
  1381. case CMD_RUN:
  1382. // Launch the process with the specified WinSafer Level restrictions.
  1383. STACKMARK(0xAAAA0005);
  1384. if (dwLevelId == SAFER_LEVELID_DISALLOWED) {
  1385. IDS_tprintf(IDS_ERR_PROCESSNOLAUNCH);
  1386. return 0;
  1387. }
  1388. if (dwScopeId == -1) {
  1389. dwScopeId = SAFER_SCOPEID_USER; //user didn't pass in a scope, so set it for them
  1390. }
  1391. if (!SaferCreateLevel(dwScopeId, dwLevelId, SAFER_LEVEL_OPEN, &hAuthzLevel, NULL))
  1392. {
  1393. printLastError();
  1394. IDS_tprintf(IDS_ERR_LEVELOPENERR, dwLevelId);
  1395. return 1;
  1396. }
  1397. PrintLevelNameDescription(hAuthzLevel, FALSE);
  1398. if (!CreateProcessRestricted(hAuthzLevel, appname, cmdline, &pi, useBreakMode)) {
  1399. if (useBreakMode) {
  1400. INPUT_RECORD inputrec;
  1401. DWORD dwNum;
  1402. IDS_tprintf(IDS_PROCSUSPENDED, pi.dwProcessId);
  1403. for (;;) {
  1404. if (ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE),
  1405. &inputrec, 1, &dwNum) &&
  1406. inputrec.EventType == KEY_EVENT &&
  1407. inputrec.Event.KeyEvent.bKeyDown)
  1408. break;
  1409. }
  1410. ResumeThread(pi.hThread);
  1411. IDS_tprintf(IDS_THREADRESUMED);
  1412. }
  1413. // Close the unnecessary handle
  1414. CloseHandle(pi.hThread);
  1415. // Wait for the process to terminate and then cleanup.
  1416. WaitForSingleObject(pi.hProcess, INFINITE);
  1417. CloseHandle(pi.hProcess);
  1418. } else {
  1419. printLastErrorWithIDSMessage(IDS_ERR_PROCESSLAUNCHERR);
  1420. }
  1421. SaferCloseLevel(hAuthzLevel);
  1422. break;
  1423. /*
  1424. // Compare or execute as appropriate.
  1425. if (commandMode == CMD_QUERY) {
  1426. // Compare the Authorization Level with the current access token.
  1427. DWORD dwResult;
  1428. if (!SaferComputeTokenFromLevel(
  1429. hAuthzLevel, NULL, NULL, AUTHZTOKEN_COMPARE_ONLY, (LPVOID) &dwResult))
  1430. {
  1431. _tprintf(TEXT("Authorization comparison failed (lasterror=%d)\n"), GetLastError());
  1432. } else if (dwResult != -1) {
  1433. _tprintf(TEXT("Authorization comparison equal or greater privileged.\n"), GetLastError());
  1434. } else {
  1435. _tprintf(TEXT("Authorization comparison less privileged.\n"), GetLastError());
  1436. }
  1437. return 0;
  1438. } else {
  1439. // Launch the process with the specified WinSafer Level restrictions.
  1440. ASSERT(commandMode == CMD_RUN);
  1441. if (!CreateProcessRestricted(hAuthzLevel, appname, cmdline, &pi, useBreakMode)) {
  1442. if (useBreakMode) {
  1443. INPUT_RECORD inputrec;
  1444. DWORD dwNum;
  1445. _tprintf(TEXT("Process %d launched and suspended. Attach a debugger and then\n")
  1446. TEXT("strike any key to resume the thread and allow debugging."),
  1447. pi.dwProcessId);
  1448. for (;;) {
  1449. if (ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE),
  1450. &inputrec, 1, &dwNum) &&
  1451. inputrec.EventType == KEY_EVENT &&
  1452. inputrec.Event.KeyEvent.bKeyDown)
  1453. break;
  1454. }
  1455. ResumeThread(pi.hThread);
  1456. _tprintf(TEXT("Thread resumed.\n"));
  1457. }
  1458. // Close the unnecessary handle
  1459. CloseHandle(pi.hThread);
  1460. // Wait for the process to terminate and then cleanup.
  1461. WaitForSingleObject(pi.hProcess, INFINITE);
  1462. CloseHandle(pi.hProcess);
  1463. // close the Authorization Level handle.
  1464. SaferCloseLevel(hAuthzLevel);
  1465. retval = 0;
  1466. }
  1467. }
  1468. _tprintf(TEXT("Could not launch process (error=%d).\n"), GetLastError());
  1469. retval = 1;
  1470. */
  1471. }
  1472. if (A_LP_CMD_QUERY) LocalFree(A_LP_CMD_QUERY);
  1473. if (A_LP_CMD_RUN) LocalFree(A_LP_CMD_RUN);
  1474. if (A_LP_CMD_HASH) LocalFree(A_LP_CMD_HASH);
  1475. if (A_LP_CMD_LIST) LocalFree(A_LP_CMD_LIST);
  1476. if (A_LP_CMD_LISTRULES) LocalFree(A_LP_CMD_LISTRULES);
  1477. if (A_LP_FLAG_LEVELID) LocalFree(A_LP_FLAG_LEVELID);
  1478. if (A_LP_FLAG_RULETYPES) LocalFree(A_LP_FLAG_RULETYPES);
  1479. if (A_LP_RULETYPES_PATH) LocalFree(A_LP_RULETYPES_PATH);
  1480. if (A_LP_RULETYPES_HASH) LocalFree(A_LP_RULETYPES_HASH);
  1481. if (A_LP_RULETYPES_CERTIFICATE) LocalFree(A_LP_RULETYPES_CERTIFICATE);
  1482. return TRUE;
  1483. }