windows-nt/Source/XPSP1/NT/ds/security/winsafer/test/saferbox/saferbox.c
2020-09-26 16:20:57 +08:00

1701 lines
52 KiB
C

/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
saferbox.c (WinSafer Test application)
Abstract:
This module implements a utility program that tests some of the
major child-execution and restricted token functionality.
Author:
Jeffrey Lawson (JLawson) - Nov 1999
John Lambert (johnla) - Nov 2000
Environment:
User mode only.
Revision History:
Created - Nov 1999
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <wincrypt.h>
#include <aclapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <wintrust.h>
#include <winsafer.h>
#include <winsaferp.h>
#include <tchar.h>
#include <winuser.h>
#include "resource.h"
#include <crypto\wintrustp.h>
#include <softpub.h> // WINTRUST_ACTION_GENERIC_VERIFY_V2
HMODULE hModule=NULL;
#ifdef DBG
//this is some bogus stuff to help when debugging in assembly
//To use this:
// run cdb saferbox args
//type: bp saferbox!_STACKMARK
//type g (this will break when the stackmark function is called.
//type t after it breaks
//look at eax to know what the stackmarker is
//type t two more times to exit the function
DWORD _S=0;
int _fastcall _STACKMARK(int a)
{
_S=a;
return _S;
}
#define STACKMARK(X) _STACKMARK(X)
#else
#define STACKMARK(X) {}
#endif
//some forward declarations
void __cdecl printLastErrorWithIDSMessage(UINT resID);
void printLastErrorWithMessage(LPTSTR lpErrorMessage);
void printLastError(void);
LPTSTR getSystemMessage(long error_code)
{
LPVOID message;
const LPTSTR defaultMessage = TEXT("Format Message failed");
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
error_code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &message,
0,
NULL)) {
message = (LPTSTR) LocalAlloc(LPTR, (_tcslen(defaultMessage) +1)* sizeof(TCHAR));
_tcscpy(message, defaultMessage);
return message;
} else {
return message;
}
}
BOOL InitModule(void)
{
if(!(hModule=GetModuleHandle(NULL)))
return FALSE;
return TRUE;
}
//caller must free string with LocalFree
LPTSTR AllocAndLoadStringFromModule(HINSTANCE hModule, UINT resID)
{
LPTSTR lpString = NULL;
int cChars=0;
lpString = (LPTSTR) LocalAlloc(LPTR, (MAX_USAGE_LEN + 1) * sizeof(TCHAR) );//add one for null char
if (!lpString) {
printLastError();
return NULL;
}
cChars = LoadString( hModule, resID, lpString, (MAX_USAGE_LEN + 1) * sizeof(TCHAR)); //could pass in NULL for hModule here.
if (cChars > 0) {
//we alloc'ed a big string before, realloc the string to only the needed size
lpString = (LPTSTR) LocalReAlloc(lpString, (cChars + 1) * sizeof(TCHAR) , 0);
return lpString; //will be NULL on LocalReAlloc error
} else {
return NULL;
}
}
//caller must free string with LocalFree
LPTSTR AllocAndLoadString(UINT resID)
{
return AllocAndLoadStringFromModule(hModule, resID);
}
void IDS_printString(UINT resID)
{
LPTSTR lpString = NULL;
lpString = AllocAndLoadString(resID);
if (lpString) {
_putts(lpString);
} else {
_tprintf(TEXT("[String resource not found: 0x%x (%d)]\n"), resID, resID);
}
if (lpString) LocalFree(lpString);
return;
}
void __cdecl IDS_tprintf(UINT resID, ...)
{
va_list ap;
LPTSTR lpString;
STACKMARK(0xAABB0000);
lpString = AllocAndLoadString(resID);
va_start(ap, resID);
if (lpString) {
_vtprintf(lpString, ap);
} else {
_tprintf(TEXT("[String resource not found: 0x%x (%d)]\n"), resID, resID);
}
if (lpString) LocalFree (lpString);
va_end(ap);
}
void __cdecl printLastErrorWithIDSMessage(UINT resID)
{
LPTSTR message = NULL;
LPTSTR lpString = NULL;
long err = GetLastError();
message = getSystemMessage(err);
lpString = AllocAndLoadString(resID);
if (lpString) {
_tprintf(TEXT("%s: 0x%X %s\n"), lpString, err, message);
} else {
_tprintf(TEXT("[String resource not found: 0x%x (%d)]\n"), resID, resID);
_tprintf(TEXT("0x%X %s\n"), err, message);
}
if (message) LocalFree (message);
if (lpString) LocalFree (lpString);
}
void printLastErrorWithMessage(LPTSTR lpErrorMessage)
{
LPTSTR message;
long err = GetLastError();
message = getSystemMessage(err);
_tprintf(TEXT("%s : 0x%X %s\n"), lpErrorMessage, err, message);
if (message) LocalFree (message);
}
void printLastError(void)
{
LPTSTR message;
message = getSystemMessage(GetLastError());
_tprintf(TEXT("Error (%d) %s\n"), GetLastError(), message);
if (message) LocalFree(message);
}
/*++
Routine Description:
Displays a simple command line syntax help screen.
Arguments:
nothing
Return Value:
always returns 1.
--*/
int DisplaySyntax( void )
{
IDS_tprintf(IDS_USAGE_SYNTAX);
return 1;
}
BOOL GetSignedFileHash(
IN LPCTSTR lpzFilename,
OUT BYTE rgbFileHash[SAFER_MAX_HASH_SIZE],
OUT DWORD *pcbFileHash,
OUT ALG_ID *pHashAlgid
)
{
BOOL retval = TRUE;
HRESULT hr;
const DWORD SHA1_HASH_LEN = 20;
const DWORD MD5_HASH_LEN = 16;
if ( !lpzFilename || !rgbFileHash || !pcbFileHash || !pHashAlgid )
return FALSE;
//
// Call WTHelperGetFileHash
//
*pcbFileHash = SAFER_MAX_HASH_SIZE;
STACKMARK(0xBBBB0000);
hr = WTHelperGetFileHash(
(LPWSTR)lpzFilename, //TODO: convert from ANSI to UNICODE. WTHelperGetFileHash doesn't support ANSI
0,
NULL,
rgbFileHash,
pcbFileHash,
pHashAlgid);
if ( SUCCEEDED (hr) )
{
if ( SHA1_HASH_LEN == *pcbFileHash )
*pHashAlgid = CALG_SHA;
else if ( MD5_HASH_LEN == *pcbFileHash )
*pHashAlgid = CALG_MD5;
} else {
retval = FALSE;
}
return retval;
}
/*++
Routine Description:
Computes the MD5 hash of a given file's contents and prints the
resulting hash value to the screen.
Arguments:
szFilename - filename to compute hash of.
Return Value:
Returns 0 on success, or a non-zero exit code on failure.
--*/
BOOL ComputeMD5Hash(IN HANDLE hFile, OUT BYTE* hashResult, OUT DWORD* pdwHashSize)
{
BOOL retval = TRUE;
//
// Open the specified file and map it into memory.
//
if (hFile != NULL) {
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if ( hMapping ) {
DWORD dwDataLen = GetFileSize (hFile, NULL);
if (dwDataLen != -1) {
LPBYTE pbData = (LPBYTE) MapViewOfFile (hMapping, FILE_MAP_READ, 0, 0, dwDataLen);
if ( pbData ) {
//
// Generate the hash value of the specified file.
//
HCRYPTPROV hProvider = 0;
if ( CryptAcquireContext(&hProvider, NULL, NULL,
PROV_RSA_SIG, CRYPT_VERIFYCONTEXT) ||
CryptAcquireContext(&hProvider, NULL, NULL,
PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) )
{
HCRYPTHASH hHash = 0;
if ( CryptCreateHash(hProvider, CALG_MD5, 0, 0, &hHash) ) {
if ( CryptHashData (hHash, pbData, dwDataLen, 0) ) {
*pdwHashSize = SAFER_MAX_HASH_SIZE;
if (!CryptGetHashParam(hHash, HP_HASHVAL, hashResult, pdwHashSize, 0)) {
*pdwHashSize = 0;
retval = FALSE;
}
} else {
retval = FALSE;
}
CryptDestroyHash(hHash);
} else {
retval = FALSE;
}
CryptReleaseContext(hProvider, 0);
} else {
retval = FALSE;
}
} else {
retval = FALSE;
}
}
CloseHandle(hMapping);
}
}
return retval;
}
/*++
Routine Description:
Arguments:
szFilename - filename to compute hash of.
Return Value:
Returns TRUE on success, or FALSE on failure.
--*/
BOOL ComputeHash( IN LPCTSTR szFilename)
{
BYTE hashResult[SAFER_MAX_HASH_SIZE];
DWORD dwHashsize = 0;
DWORD dwFilesize = 0;
HANDLE hFile = NULL;
BOOL retval = FALSE;
ALG_ID algId = 0;
BOOL result = FALSE;
hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile) {
dwFilesize= GetFileSize(hFile, NULL);
result = GetSignedFileHash(szFilename, hashResult, &dwHashsize, &algId);
if (!result &&
(GetLastError() != TRUST_E_NOSIGNATURE) && //a recognized format, but no sig
(GetLastError() != TRUST_E_SUBJECT_FORM_UNKNOWN)) //unrecognized format, don't know how to get sig
{
printLastError();
retval = FALSE;
goto ExitHandler;
} else if (!result) {
if (!ComputeMD5Hash(hFile, hashResult, &dwHashsize)) {
printLastError();
retval = FALSE;
goto ExitHandler;
}
algId = CALG_MD5;
} else {
_tprintf(TEXT("This file is signed.\n"));
}
//
// Print out the results.
//
if (dwHashsize != 0)
{
DWORD Index;
_tprintf(TEXT("%s:\n"), szFilename);
_tprintf(TEXT("Hash Algorithm: "));
if (algId == CALG_MD5) {
_tprintf(TEXT("MD5\n"));
} else if (algId == CALG_SHA) {
_tprintf(TEXT("SHA\n"));
}
_tprintf(TEXT("Hash: "));
for (Index = 0; Index < dwHashsize; Index++)
printf("%02X", hashResult[Index]);
_tprintf(TEXT("\nFile size: "));
_tprintf(TEXT("%d\n"), dwFilesize);
retval = TRUE;
goto ExitHandler;
} else {
printLastError();
retval = FALSE;
goto ExitHandler;
}
} else {
printLastError();
retval = FALSE;
goto ExitHandler;
}
ExitHandler:
if (hFile) CloseHandle(hFile);
return retval;
}
/*++
Routine Description:
Creates the process with a given WinSafer restriction Level.
Arguments:
hAuthzLevel - an opened WinSafer Level handle that specifies how
the specified program should be launched.
appname - filename of the program to be launched.
cmdline - command line supplied to the program that is launched.
pi - pointer to a structure that will be filled with information
about the process that is created.
bStartSuspended - if this argument is TRUE, then the process will
be started in a suspended state, and its primary thread must
be explicitly resumed by the calling program in order to
begin execution.
Return Value:
returns 0 on success, or a non-zero exit code on failure.
--*/
int CreateProcessRestricted(
IN SAFER_LEVEL_HANDLE hAuthzLevel,
IN LPCTSTR appname,
IN LPTSTR cmdline,
OUT PROCESS_INFORMATION *pi,
IN BOOL bStartSuspended)
{
HANDLE hToken;
STARTUPINFO si;
// Generate the restricted token that we will use.
if (!SaferComputeTokenFromLevel(
hAuthzLevel, // Safer Level handle
NULL, // source token
&hToken, // target token
0, // no flags
NULL)) // reserved
{
_tprintf(TEXT("Failed to compute restricted access token.\n"));
return 2;
}
// Prepare the startup info structure.
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
// Launch the child process under the context of the restricted token.
if (!CreateProcessAsUser(
hToken, // token representing the user
appname, // name of executable module
cmdline, // command-line string
NULL, // process security attributes
NULL, // thread security attributes
FALSE, // if process inherits handles
(bStartSuspended ? CREATE_SUSPENDED : 0), // creation flags
NULL, // new environment block
NULL, // current directory name
&si, // startup information
pi // process information
))
{
_tprintf(TEXT("Failed to execute child.\n"));
CloseHandle(hToken);
return 3;
}
// success.
CloseHandle(hToken);
return 0;
}
/*++
Routine Description:
Prints the description and friendly name associated with an
opened WinSafer Level handle.
Arguments:
hAuthzLevel - the opened WinSafer Level handle to analyze.
Return Value:
does not return a value.
--*/
void PrintLevelNameDescription( IN SAFER_LEVEL_HANDLE hAuthzLevel, BOOL bPrintDescription)
{
WCHAR namebuffer[200];
DWORD dwordbuffer;
if (SaferGetLevelInformation(
hAuthzLevel, SaferObjectLevelId,
&dwordbuffer, sizeof(DWORD), NULL))
{
if (SaferGetLevelInformation(
hAuthzLevel, SaferObjectFriendlyName,
namebuffer, sizeof(namebuffer), NULL)) {
IDS_tprintf(IDS_SECURITYLEVEL, namebuffer, dwordbuffer, dwordbuffer);
} else {
printLastErrorWithMessage(TEXT("Error getting level friendly name"));
}
if (bPrintDescription) {
if (SaferGetLevelInformation(
hAuthzLevel, SaferObjectDescription,
namebuffer, sizeof(namebuffer), NULL)) {
IDS_tprintf(IDS_SECURITYLEVELDESC, namebuffer);
} else {
printLastErrorWithMessage(TEXT("Error getting level description"));
}
}
} else {
printLastErrorWithMessage(TEXT("Error retrieving level information"));
}
}
BOOL
ListSingleIdentity(
IN SAFER_LEVEL_HANDLE hAuthzLevel,
IN REFGUID rEntryGuid
)
/*++
Routine Description:
Prints out details about a specific already existing Code Identity
that has been defined for a WinSafer Level.
Arguments:
hAuthzLevel - handle of the WinSafer Level to which the indicated
Code Identity GUID belongs.
rEntryGuid - pointer to the GUID of the Code Identity requested.
Return Value:
returns TRUE on success, FALSE on failure.
--*/
{
BOOL bRVal;
DWORD dwBufferSize;
SAFER_IDENTIFICATION_HEADER caiCommon;
#if 0 // just testing
SAFER_PATHNAME_IDENTIFICATION newimageid;
ZeroMemory(&newimageid, sizeof(SAFER_PATHNAME_IDENTIFICATION));
newimageid.header.cbStructSize = sizeof(SAFER_PATHNAME_IDENTIFICATION);
newimageid.header.dwIdentificationType = SaferIdentityTypeImageName;
CopyMemory(&newimageid.header.IdentificationGuid, rEntryGuid, sizeof(GUID));
newimageid.bOnlyExeFiles = TRUE;
lstrcpyW(newimageid.Description, L"new sample identity");
newimageid.dwUIFlags = 42;
lstrcpyW(newimageid.ImageName, L"c:\\temp\\foo\\bar.txt");
bRVal = SetInformationCodeAuthzLevelW (
hAuthzLevel,
SaferObjectSingleIdentification,
&newimageid,
sizeof(newimageid));
if (!bRVal) {
printf("SetInformationCodeAuthzLevelW failed with error %d\n", GetLastError());
} else {
printf("SetInformationCodeAuthzLevelW was successful\n");
}
#endif
#if 0 // just testing
dwBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
ZeroMemory(&caiCommon, sizeof(SAFER_IDENTIFICATION_HEADER));
caiCommon.cbStructSize = dwBufferSize;
caiCommon.dwIdentificationType = 0;
memcpy(&caiCommon.IdentificationGuid, rEntryGuid, sizeof(GUID));
bRVal = SetInformationCodeAuthzLevelW (hAuthzLevel,
SaferObjectSingleIdentification,
&caiCommon,
dwBufferSize);
if (!bRVal) {
printf("Failed to delete identity (error=%d)\n", GetLastError());
} else {
printf("Identity successfully deleted.\n");
}
#endif
dwBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
ZeroMemory (&caiCommon, sizeof(SAFER_IDENTIFICATION_HEADER));
caiCommon.cbStructSize = dwBufferSize;
memcpy (&caiCommon.IdentificationGuid, rEntryGuid, sizeof (GUID));
bRVal = SaferGetLevelInformation (hAuthzLevel,
SaferObjectSingleIdentification,
&caiCommon,
dwBufferSize,
&dwBufferSize);
if ( !bRVal && ERROR_INSUFFICIENT_BUFFER == GetLastError () )
{
PBYTE pBytes = (PBYTE) LocalAlloc (LPTR, dwBufferSize);
if ( pBytes )
{
PSAFER_IDENTIFICATION_HEADER pCommon =
(PSAFER_IDENTIFICATION_HEADER) pBytes;
ZeroMemory(pCommon, dwBufferSize);
pCommon->cbStructSize = sizeof(SAFER_IDENTIFICATION_HEADER);
memcpy (&pCommon->IdentificationGuid, rEntryGuid, sizeof (GUID));
bRVal = SaferGetLevelInformation (hAuthzLevel,
SaferObjectSingleIdentification,
pBytes,
dwBufferSize,
&dwBufferSize);
if ( bRVal ) {
switch (pCommon->dwIdentificationType) {
case SaferIdentityTypeImageName:
{
PSAFER_PATHNAME_IDENTIFICATION pImageName =
(PSAFER_PATHNAME_IDENTIFICATION) pCommon;
ASSERT(pCommon->cbStructSize ==
sizeof(SAFER_PATHNAME_IDENTIFICATION));
printf(" ImageName: %S\n", pImageName->ImageName);
printf("Description: %S\n", pImageName->Description);
#ifdef AUTHZPOL_SAFERFLAGS_ONLY_EXES
printf(" SaferFlags: %d OnlyExecutables: %s\n\n",
pImageName->dwSaferFlags,
(pImageName->dwSaferFlags & AUTHZPOL_SAFERFLAGS_ONLY_EXES) != 0 ? "yes" : "no");
#else
printf(" SaferFlags: %d\n\n",
pImageName->dwSaferFlags);
#endif
return TRUE;
}
case SaferIdentityTypeImageHash:
{
ULONG i;
PSAFER_HASH_IDENTIFICATION pImageHash =
(PSAFER_HASH_IDENTIFICATION) pCommon;
ASSERT(pCommon->cbStructSize ==
sizeof(SAFER_HASH_IDENTIFICATION));
printf(" ImageHash: ");
for (i = 0; i < pImageHash->HashSize; i++) {
printf("%02X ", pImageHash->ImageHash[i]);
}
printf("(%d bytes, ImageSize=%d bytes)\n",
pImageHash->HashSize, pImageHash->ImageSize.LowPart);
printf("Description: %S\n", pImageHash->Description);
printf(" SaferFlags: %d\n\n", pImageHash->dwSaferFlags);
return TRUE;
}
case SaferIdentityTypeUrlZone:
{
PSAFER_URLZONE_IDENTIFICATION pUrlZone =
(PSAFER_URLZONE_IDENTIFICATION) pCommon;
ASSERT(pCommon->cbStructSize ==
sizeof(SAFER_URLZONE_IDENTIFICATION));
printf(" UrlZone: %d\n", pUrlZone->UrlZoneId);
printf("SaferFlags: %d\n\n", pUrlZone->dwSaferFlags);
return TRUE;
}
default:
printf(" Unexpectedly encountered identity type %d\n",
pCommon->dwIdentificationType);
break;
}
} else {
printf(" GetInfo failed with LastError=%d\n", GetLastError());
}
LocalFree(pBytes);
} else {
printf(" Failed to allocate memory for query.\n");
}
} else {
printf(" First GetInfo failed with LastError=%d\n", GetLastError());
}
return FALSE;
}
/*++
Routine Description:
Prints all associated Code Identifiers for a given WinSafer Level.
Arguments:
hAuthzLevel - the WinSafer Level handle to analyze.
Return Value:
returns 0.
--*/
int ListAllIdentities( IN SAFER_LEVEL_HANDLE hAuthzLevel)
{
DWORD dwInfoBufferSize;
GUID *pIdentGuids;
if (!SaferGetLevelInformation(
hAuthzLevel,
SaferObjectAllIdentificationGuids,
NULL,
0,
&dwInfoBufferSize) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
dwInfoBufferSize != 0)
{
pIdentGuids = (GUID*) HeapAlloc(GetProcessHeap(),
0, dwInfoBufferSize);
if (pIdentGuids != NULL) {
DWORD dwFinalBufferSize;
if (SaferGetLevelInformation(
hAuthzLevel,
SaferObjectAllIdentificationGuids,
pIdentGuids,
dwInfoBufferSize,
&dwFinalBufferSize))
{
ULONG ulNumIdentities = dwFinalBufferSize / sizeof(GUID);
ULONG i;
ASSERT(dwFinalBufferSize == dwInfoBufferSize);
_tprintf(TEXT(" Found %d identity GUIDs.\n"), ulNumIdentities);
for (i = 0; i < ulNumIdentities; i++) {
if (!ListSingleIdentity(hAuthzLevel, &pIdentGuids[i])) {
_tprintf(TEXT(" Failed to retrieve details on identity.\n"));
}
}
} else {
_tprintf(TEXT(" Failed to retrieve ident guid list (error=%d).\n"),
GetLastError());
}
HeapFree( GetProcessHeap(), 0, pIdentGuids);
}
} else {
IDS_tprintf(IDS_NORULESFOUND);
}
return 0;
}
/*++
Routine Description:
Prints out a list of all defined WinSafer Levels, and optionally
all Code Identifiers associated with them.
Arguments:
bDisplayIdentifier - if this argument is TRUE, then the list of
associated Code Identifiers will also be listed along with
each WinSafer Level as they are enumerated.
Return Value:
returns 0 on success, or a non-zero exit code on failure.
--*/
int ListAllLevels(DWORD dwScope, BOOL bDisplayIdentifiers)
{
DWORD dwInfoBufferSize;
LPBYTE InfoBuffer = NULL;
// Fetch the list of all WinSafer LevelIds.
if (!SaferGetPolicyInformation(
dwScope, SaferPolicyLevelList,
0, NULL, &dwInfoBufferSize, NULL) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
InfoBuffer = (LPBYTE) HeapAlloc(GetProcessHeap(), 0, dwInfoBufferSize);
if (InfoBuffer != NULL)
{
DWORD dwInfoBufferSize2;
if (!SaferGetPolicyInformation(
dwScope, SaferPolicyLevelList,
dwInfoBufferSize, InfoBuffer, &dwInfoBufferSize2, NULL))
{
_tprintf(TEXT("Failed to retrieve Level list (error=%d)\n"),
GetLastError());
HeapFree(GetProcessHeap(), 0, InfoBuffer);
InfoBuffer = NULL;
}
ASSERTMSG("got different final size",
dwInfoBufferSize2 == dwInfoBufferSize);
ASSERTMSG("expecting whole number of DWORD values",
dwInfoBufferSize % sizeof(DWORD) == 0);
dwInfoBufferSize = dwInfoBufferSize2;
} else {
_tprintf(TEXT("Failed to allocate %d bytes of memory.\n"), dwInfoBufferSize);
return 1;
}
}
// Iterate through and add all of the items.
if (InfoBuffer != NULL) {
PDWORD pLevelIdList = (PDWORD) InfoBuffer;
DWORD Index;
for (Index = 0; Index < dwInfoBufferSize / sizeof(DWORD); Index++) {
SAFER_LEVEL_HANDLE hAuthzLevel;
WCHAR namebuffer[200];
DWORD dwLevelId = pLevelIdList[Index];
if (SaferCreateLevel(dwScope, dwLevelId,
SAFER_LEVEL_OPEN, &hAuthzLevel, NULL))
{
_tprintf(TEXT("\n"));
PrintLevelNameDescription(hAuthzLevel, !bDisplayIdentifiers);
/*
if (SaferGetLevelInformation(hAuthzLevel, SaferObjectFriendlyName,
namebuffer, sizeof(namebuffer), NULL))
_tprintf(TEXT("LevelId %d: \"%s\"\n"), dwLevelId, namebuffer);
else
_tprintf(TEXT("LevelId %d: unknown\n"), dwLevelId);
*/
if (bDisplayIdentifiers) {
ListAllIdentities(hAuthzLevel);
}
SaferCloseLevel(hAuthzLevel);
} else {
_tprintf(TEXT("LevelId %d: unknown\n"), dwLevelId);
}
}
HeapFree(GetProcessHeap(), 0, InfoBuffer);
// Fetch the default level
//TODO: for some reason my default level isn't in the registry and this part returns NOT_FOUND
dwInfoBufferSize=0;
STACKMARK(0xAAAC0000);
if (!SaferGetPolicyInformation(
dwScope, SaferPolicyDefaultLevel,
0, NULL, &dwInfoBufferSize, NULL) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
SAFER_LEVEL_HANDLE hAuthzLevel;
DWORD dwLevelId = 0;
InfoBuffer = (LPBYTE) HeapAlloc(GetProcessHeap(), 0, dwInfoBufferSize);
if (InfoBuffer != NULL)
{
if (!SaferGetPolicyInformation(
dwScope, SaferPolicyDefaultLevel,
dwInfoBufferSize, InfoBuffer, &dwInfoBufferSize, NULL))
{
_tprintf(TEXT("Failed to retrieve default level (error=%d)\n"), GetLastError());
HeapFree(GetProcessHeap(), 0, InfoBuffer);
InfoBuffer = NULL;
return 1;
} else {
ASSERT(dwInfoBufferSize==sizeof(dwLevelId));
memcpy(&dwLevelId,InfoBuffer, dwInfoBufferSize);
if (SaferCreateLevel(dwScope, dwLevelId,
SAFER_LEVEL_OPEN, &hAuthzLevel, NULL))
{
_tprintf(TEXT("\n"));
IDS_tprintf(IDS_DEFAULTLEVEL);
PrintLevelNameDescription(hAuthzLevel, FALSE);
}
}
SaferCloseLevel(hAuthzLevel);
} else {
_tprintf(TEXT("Failed to allocate %d bytes of memory.\n"), dwInfoBufferSize);
return 1;
}
} else {
printLastErrorWithMessage(TEXT("Failed to retrieve default level"));
return 1;
}
return 0;
}
_tprintf(TEXT("No Levels found in this scope.\n"));
return 1;
}
BOOL PrintMatchingRule(
IN SAFER_LEVEL_HANDLE hAuthzLevel)
{
DWORD dwBufferSize=0;
UNICODE_STRING UnicodeTemp;
WCHAR lpzGuid[200];
PSAFER_IDENTIFICATION_HEADER lpQueryBuf=NULL;
SAFER_IDENTIFICATION_HEADER comheader;
STACKMARK(0xAAAB0000);
memset(&comheader,0,sizeof(SAFER_IDENTIFICATION_HEADER));
comheader.cbStructSize=sizeof(SAFER_IDENTIFICATION_HEADER);
dwBufferSize = sizeof(SAFER_IDENTIFICATION_HEADER);
if (!SaferGetLevelInformation(
hAuthzLevel, SaferObjectSingleIdentification, &comheader, dwBufferSize, &dwBufferSize)) {
printLastError();
return FALSE;
}
if (GetLastError() == ERROR_NOT_FOUND) {
IDS_tprintf(IDS_USINGDEFAULTRULE);
} else {
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER &&
GetLastError() != ERROR_SUCCESS) {
printLastError();
return FALSE;
}
ASSERT(dwBufferSize >= sizeof (SAFER_IDENTIFICATION_HEADER));
lpQueryBuf = (PSAFER_IDENTIFICATION_HEADER)LocalAlloc(LPTR, dwBufferSize );
if (!lpQueryBuf) {
printLastError();
return FALSE;
}
lpQueryBuf->cbStructSize = dwBufferSize;
if (!SaferGetLevelInformation(hAuthzLevel, SaferObjectSingleIdentification, lpQueryBuf, dwBufferSize, &dwBufferSize) ) {
printLastError();
return FALSE;
}
UnicodeTemp.Buffer=(PWSTR)lpzGuid;
UnicodeTemp.MaximumLength = sizeof(lpzGuid);
RtlStringFromGUID (&(lpQueryBuf->IdentificationGuid),&UnicodeTemp);
//TODO: could print out whether rule was from CU or LM
if (lpQueryBuf->dwIdentificationType == SaferIdentityTypeImageName) {
IDS_tprintf(IDS_MATCHPATH, ((PSAFER_PATHNAME_IDENTIFICATION)lpQueryBuf)->ImageName);
} else if (lpQueryBuf->dwIdentificationType == SaferIdentityTypeImageHash ){
IDS_tprintf(IDS_MATCHHASH);
} else if (lpQueryBuf->dwIdentificationType == SaferIdentityTypeUrlZone ){
IDS_tprintf(IDS_MATCHZONE);
} else {
//must be a publisher certificate rule.
IDS_tprintf(IDS_MATCHCERTORDEFAULT);
}
IDS_tprintf(IDS_GUIDRULEIS,UnicodeTemp.Buffer);
LocalFree(lpQueryBuf);
}
_tprintf(TEXT("\n"));
PrintLevelNameDescription(hAuthzLevel, TRUE);
return TRUE;
}
//VerifyVersionInfo
BOOL IsMinimumVersion()
{
DWORD tmp;
LPVOID lpVerInfo = NULL;
LPVOID lpValue = NULL;
LPTSTR lpFileToVersion = TEXT("advapi32.dll");
UINT uLen;
//must be at least post beta 1 of whistler
const DWORD PROD_MAJOR = 5;
const DWORD PROD_MINOR = 1;
const DWORD BUILD_MAJOR = 2400;
DWORD dwBuildMajor=0, dwProductMajor=0, dwProductMinor=0;
DWORD dwSize = GetFileVersionInfoSize(lpFileToVersion, &tmp);
if (!dwSize) {
printLastErrorWithIDSMessage(IDS_ERR_GETVERERR);
return FALSE;
}
lpVerInfo = (LPVOID) LocalAlloc(LPTR, dwSize);
if (!lpVerInfo) {
printLastError();
return FALSE;
}
if (! GetFileVersionInfo(lpFileToVersion, 0, dwSize, lpVerInfo)) {
printLastErrorWithIDSMessage(IDS_ERR_GETVERERR);
if (lpVerInfo) LocalFree(lpVerInfo);
return FALSE;
}
if (!VerQueryValue(lpVerInfo, TEXT("\\"), &lpValue, &uLen)) { // '\' indicates the root version info block
printLastErrorWithIDSMessage(IDS_ERR_GETVERERR);
if (lpVerInfo) LocalFree(lpVerInfo);
return FALSE;
}
/*
_tprintf(TEXT("dwFileVersionMS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwFileVersionMS) >> 16);
_tprintf(TEXT("dwFileVersionMS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwFileVersionMS) & 0x0000FFFF);
_tprintf(TEXT("dwFileVersionLS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwFileVersionLS) >> 16);
_tprintf(TEXT("dwFileVersionLS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwFileVersionLS) & 0x0000FFFF);
_tprintf(TEXT("dwProductVersionMS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionMS) >>16);
_tprintf(TEXT("dwProductVersionMS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionMS) & 0x0000FFFF);
_tprintf(TEXT("dwProductVersionLS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionLS) >>16);
_tprintf(TEXT("dwProductVersionLS is %d\n"), (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionLS) & 0x0000FFFF);
*/
dwProductMajor = (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionMS) >>16;
dwProductMinor = (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionMS) & 0x0000FFFF;
dwBuildMajor = (((VS_FIXEDFILEINFO*)lpValue)->dwProductVersionLS) >>16;
if ((dwProductMajor < PROD_MAJOR) ||
(dwProductMajor == PROD_MAJOR && dwProductMinor < PROD_MINOR ) ||
(dwProductMinor == PROD_MAJOR && dwProductMinor == PROD_MINOR && dwBuildMajor < BUILD_MAJOR)) {
IDS_tprintf(IDS_ERR_INCORRECTOSVER, dwProductMajor, dwProductMinor, dwBuildMajor, PROD_MAJOR, PROD_MINOR, BUILD_MAJOR);
if (lpVerInfo) LocalFree(lpVerInfo);
return FALSE;
} else {
if (lpVerInfo) LocalFree(lpVerInfo);
return TRUE;
}
}
BOOL GetPathFromKeyKey(LPCTSTR lpzRegKey)
{
HKEY hKey, hKeyHive;
LPTSTR lpKeyname=NULL;
LPCTSTR LP_CU_HIVE = TEXT("%HKEY_CURRENT_USER");
LPCTSTR LP_LM_HIVE = TEXT("%HKEY_LOCAL_MACHINE");
LPCTSTR lpLastPercentSign=NULL;
BYTE buffer[MAX_PATH];
LPTSTR lpValue;
DWORD dwBufferSize = sizeof(buffer);
LPTSTR lpHivename;
LONG retval;
memset(buffer, 0, dwBufferSize);
lpHivename = _tcsstr(lpzRegKey, LP_CU_HIVE);
if (lpHivename != NULL) {
hKeyHive = HKEY_CURRENT_USER;
lpKeyname = _tcsdup(&lpzRegKey[_tcslen(LP_CU_HIVE)+1]); //remove '\' char in front
} else {
lpHivename = _tcsstr(lpzRegKey, LP_LM_HIVE);
if (lpHivename != NULL) {
hKeyHive = HKEY_LOCAL_MACHINE;
lpKeyname = _tcsdup(&lpzRegKey[_tcslen(LP_LM_HIVE)+1]); //remove '\' char in front
} else {
IDS_tprintf(IDS_ERR_REGNOTFOUND);
return FALSE;
}
}
lpLastPercentSign = wcsrchr(lpzRegKey,'%');
if (lpLastPercentSign != &lpzRegKey[wcslen(lpzRegKey)-1]) {
_tprintf(TEXT("bad substitution char.\n"));
return FALSE;
}
lpValue = _tcsrchr(lpKeyname, '\\');
if (lpValue==NULL) {
IDS_tprintf(IDS_ERR_REGNOTFOUND);
return FALSE;
}
*lpValue = '\0';
lpValue = lpValue + 1;
lpValue[wcslen(lpValue)-1] = '\0';
if (retval = RegOpenKeyEx(hKeyHive,
lpKeyname,
0,
KEY_READ,
&hKey))
{
SetLastError(retval);
printLastError();
return FALSE;
} else {
if (retval = RegQueryValueEx(hKey,
lpValue,
NULL,
NULL,
buffer,
&dwBufferSize))
{
SetLastError(retval);
printLastError();
return FALSE;
} else {
_tprintf(TEXT("\n"));
IDS_tprintf(IDS_REGVALUE);
_tprintf(TEXT("%s"), buffer);
}
}
free(lpKeyname);
RegCloseKey(hKey);
return TRUE;
}
void PrintAndRecurse(HKEY hkey, LPCWSTR lpParentKeyname)
{
DWORD cValue=MAX_PATH;
DWORD cKey=MAX_PATH;
DWORD cbData=100;
LPWSTR lpValue[MAX_PATH * sizeof(WCHAR)];
LPWSTR lpKey[MAX_PATH * sizeof(WCHAR)];
LPWSTR lpFullKey[MAX_PATH * sizeof(WCHAR)];
LPBYTE lpData=NULL;
DWORD idx=0;
DWORD dwType=0;
DWORD retval=0;
FILETIME filetime;
BOOL bDone=FALSE;
HKEY nextKey=NULL;
DWORD dwNumSubKeys=0;
DWORD dwNumValues=0;
DWORD dwMaxValueLen=0;
RegQueryInfoKey(hkey,NULL,NULL, NULL, &dwNumSubKeys, NULL, NULL, &dwNumValues,NULL, &dwMaxValueLen, NULL,NULL);
do {
lpValue[0]=L"\0";
cbData = dwMaxValueLen;
lpData = (LPBYTE)LocalAlloc(LPTR, dwMaxValueLen);
if (!lpData) {
printLastError();
return;
}
cValue=MAX_PATH;
retval = RegEnumValue(hkey,
idx,
(LPWSTR)lpValue,
&cValue,
NULL,
&dwType,
lpData,
&cbData);
if (retval==ERROR_NO_MORE_ITEMS) {
bDone=TRUE;
} else if (retval != ERROR_SUCCESS) {
SetLastError(retval);
bDone=TRUE;
printLastError();
}
if (!bDone) {
wprintf(L"\t%s",lpValue);
switch (dwType)
{
case REG_DWORD:
{
DWORD dwValue;
memcpy(&dwValue,lpData, sizeof(DWORD));
wprintf(L" : 0x%08X\n", dwValue);
}
break;
case REG_QWORD:
{
__int64 qwValue;
memcpy(&qwValue, lpData, sizeof(__int64));
wprintf(L" : 0x%I64x\n", qwValue);
}
break;
case REG_BINARY:
wprintf(L" : ");
{ int i;
for (i=0;i<(int)cbData;i++) {
wprintf(L"%02X", *(lpData+i));
}
wprintf(L"\n");
}
break;
case REG_SZ:
case REG_EXPAND_SZ:
wprintf(L" : %s\n", lpData);
break;
case REG_MULTI_SZ:
{int idx=0;
LPWSTR lpMultiPtr=(LPWSTR)lpData;
WCHAR nullchar = L'\0';
wprintf(L" : ");
do {
wprintf(L" %s ", lpMultiPtr);
lpMultiPtr+=wcslen(lpMultiPtr)+1 ;
} while (*(lpMultiPtr+1)!=0);
wprintf(L"\n");
}
break;
default:
wprintf(L" ??????: 0x%X\n", lpData);
}
if (lpData) LocalFree(lpData);
idx++;
}
} while (!bDone);
if (dwNumSubKeys != 0) {
idx=0;
bDone=FALSE;
do {
lpKey[0]=L"\0";
cKey=MAX_PATH;
retval = RegEnumKeyEx(hkey,
idx,
(LPWSTR)lpKey,
&cKey,
NULL,
NULL,
NULL,
&filetime);
if (retval==ERROR_NO_MORE_ITEMS) {
bDone=TRUE;
} else if (retval != ERROR_SUCCESS) {
SetLastError(retval);
bDone=TRUE;
printLastError();
}
if (!bDone) {
wprintf(L"%s\\%s\n",lpParentKeyname,lpKey);
if (RegOpenKeyEx(hkey,
(LPWSTR)lpKey,
0,
KEY_READ,
&nextKey))
{
bDone=TRUE;
printLastError();
return;
} else {
memset(lpFullKey,0,sizeof(lpFullKey));
wcscat((LPWSTR)lpFullKey, lpParentKeyname);
wcscat((LPWSTR)lpFullKey, L"\\");
wcscat((LPWSTR)lpFullKey, (LPWSTR)lpKey);
wcscat((LPWSTR)lpFullKey, L"\0");
PrintAndRecurse(nextKey, (LPWSTR)lpFullKey);
RegCloseKey(nextKey);
}
idx++;
}
} while (!bDone);
}
}
LONG DumpRegistry()
{
DWORD class,subkeys,maxsubkeylen, numvalues, maxvaluename, maxvaluedatalen;
const UNICODE_STRING HKLMSAFERKey = RTL_CONSTANT_STRING(SAFER_HKLM_REGBASE);
const UNICODE_STRING HKCUSAFERKey = RTL_CONSTANT_STRING(SAFER_HKCU_REGBASE);
const UNICODE_STRING HKPublisherKey = RTL_CONSTANT_STRING(L"Software\\Policies\\Microsoft\\SystemCertificates\\TrustedPublisher\\Certificates");
HKEY hkey;
int i;
if (!RegOpenKeyEx(HKEY_CURRENT_USER,
HKCUSAFERKey.Buffer,
0,
KEY_READ,
&hkey))
{
IDS_tprintf(IDS_LISTING_HKCU);
wprintf(L"%s\n",HKCUSAFERKey.Buffer);
PrintAndRecurse(hkey, HKCUSAFERKey.Buffer);
RegCloseKey(hkey);
}
if (!RegOpenKeyEx(HKEY_CURRENT_USER,
HKPublisherKey.Buffer,
0,
KEY_READ,
&hkey))
{
wprintf(L"%s\n",HKPublisherKey.Buffer);
PrintAndRecurse(hkey, HKPublisherKey.Buffer);
RegCloseKey(hkey);
}
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
HKLMSAFERKey.Buffer,
0,
KEY_READ,
&hkey))
{
wprintf(L"\n");
IDS_tprintf(IDS_LISTING_HKLM);
wprintf(L"%s\n",HKLMSAFERKey.Buffer);
PrintAndRecurse(hkey, HKCUSAFERKey.Buffer);
RegCloseKey(hkey);
}
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE,
HKPublisherKey.Buffer,
0,
KEY_READ,
&hkey))
{
wprintf(L"%s\n",HKPublisherKey.Buffer);
PrintAndRecurse(hkey, HKPublisherKey.Buffer);
RegCloseKey(hkey);
}
return ERROR_SUCCESS;
}
/*++
Routine Description:
Main entry point.
Arguments:
argc - count of command line arguments.
argv - pointers to command line arguments.
Return Value:
returns the program exit code.
--*/
int __cdecl _tmain(int argc, _TCHAR **argv, _TCHAR **envp)
{
PROCESS_INFORMATION pi;
DWORD dwLevelId = 0;
BOOL fLevelIdSupplied = FALSE;
_TCHAR appname[MAX_PATH];
_TCHAR cmdline[1024];
LPTSTR lpRegkey=NULL;
int nextarg;
SAFER_LEVEL_HANDLE hAuthzLevel;
int retval;
DWORD dwSuppliedCheckFlags=0;
DWORD dwScopeId=(DWORD)-1; //means check both LM + CU
BOOL useBreakMode = FALSE;
enum { CMD_RUN, CMD_QUERY, CMD_HASH, CMD_LIST, CMD_LISTRULES, CMD_REGKEY, CMD_DUMPREG }
commandMode = -1;
LPTSTR A_LP_CMD_QUERY = AllocAndLoadString(IDS_CMD_QUERY);
LPTSTR A_LP_CMD_RUN= AllocAndLoadString(IDS_CMD_RUN);
LPTSTR A_LP_CMD_HASH= AllocAndLoadString(IDS_CMD_HASH);
LPTSTR A_LP_CMD_LIST= AllocAndLoadString(IDS_CMD_LIST);
LPTSTR A_LP_CMD_LISTRULES= AllocAndLoadString(IDS_CMD_LISTRULES);
LPTSTR A_LP_CMD_REGKEY= AllocAndLoadString(IDS_CMD_REGKEY );
LPTSTR A_LP_CMD_DUMPREG= AllocAndLoadString(IDS_CMD_DUMPREG );
LPTSTR A_LP_FLAG_LEVELID= AllocAndLoadString(IDS_FLAG_LEVELID);
LPTSTR A_LP_FLAG_RULETYPES= AllocAndLoadString(IDS_FLAG_RULETYPES);
LPTSTR A_LP_RULETYPES_PATH= AllocAndLoadString(IDS_RULETYPES_PATH);
LPTSTR A_LP_RULETYPES_HASH= AllocAndLoadString(IDS_RULETYPES_HASH);
LPTSTR A_LP_RULETYPES_CERTIFICATE= AllocAndLoadString(IDS_RULETYPES_CERTIFICATE);
LPTSTR A_LP_FLAG_SCOPE= AllocAndLoadString(IDS_FLAG_SCOPE);
LPTSTR A_LP_SCOPE_HKLM= AllocAndLoadString(IDS_SCOPE_HKLM);
LPTSTR A_LP_SCOPE_HKCU= AllocAndLoadString(IDS_SCOPE_HKCU);
UNREFERENCED_PARAMETER(envp);
STACKMARK(0xAAAA0001);
//IDS_tprintf(IDS_TEST1,66,TEXT("hellow"),45456); //test string
//get the module handle
if(!InitModule()) {
return 1;
}
// if we are going to run in an altered registry
// scope, open and set it now.
/*
if (dwScopeId == SAFER_SCOPEID_REGISTRY) {
HKEY hkeyBase;
if (RegOpenKeyExW(HKEY_CURRENT_USER, L"TestKey",
0, KEY_READ, &hkeyBase) != ERROR_SUCCESS) {
_tprintf(TEXT("Failed to open registry scope key (error=%d)\n"),
GetLastError());
return 1;
}
if (!CodeAuthzChangeRegistryScope(hkeyBase)) {
_tprintf(TEXT("Failed to change registry scope (error=%d)\n"),
GetLastError());
return 1;
}
RegCloseKey(hkeyBase);
}
*/
if (!IsMinimumVersion()) {
return 1;
}
// quick check of command line length.
if (argc < 2) {
_tprintf(TEXT("No arguments.\n"));
return DisplaySyntax();
}
// Parse the command line.
appname[0] = '\0';
cmdline[0] = '\0';
for (nextarg = 1; nextarg < argc; nextarg++) {
if (_tcsicmp(argv[nextarg],A_LP_CMD_QUERY) == 0 ) {
commandMode = CMD_QUERY;
} else if (_tcsicmp(argv[nextarg],A_LP_CMD_RUN) == 0 ) {
commandMode = CMD_RUN;
} else if (_tcsicmp(argv[nextarg],A_LP_CMD_HASH) == 0 ) {
commandMode = CMD_HASH;
} else if (_tcsicmp(argv[nextarg],A_LP_CMD_DUMPREG) == 0 ) {
commandMode = CMD_DUMPREG;
} else if (_tcsicmp(argv[nextarg],A_LP_CMD_REGKEY) == 0 ) {
commandMode = CMD_REGKEY;
nextarg++;
if (nextarg!=argc) {
lpRegkey = argv[nextarg];
} else {
return DisplaySyntax();
}
} else if (_tcsicmp(argv[nextarg],A_LP_CMD_LIST) == 0 ) {
commandMode = CMD_LIST;
} else if (_tcsicmp(argv[nextarg],A_LP_CMD_LISTRULES) == 0 ) {
commandMode = CMD_LISTRULES;
} else if (argv[nextarg][0] == '-' || argv[nextarg][0] == '/') {
if (_tcsicmp(&argv[nextarg][1], A_LP_FLAG_LEVELID) == 0) {
STACKMARK(0xAAAA000D);
dwLevelId = _ttoi(argv[++nextarg]);
fLevelIdSupplied = TRUE;
} else if (_tcsicmp(&argv[nextarg][1], A_LP_FLAG_RULETYPES) == 0) {
STACKMARK(0xAAAA000B);
nextarg++;
if (nextarg >= argc) {
return DisplaySyntax();
}
//unknown rule types are ignored
if (_tcscspn(argv[nextarg], A_LP_RULETYPES_PATH) < _tcslen(argv[nextarg])) {
dwSuppliedCheckFlags = dwSuppliedCheckFlags | SAFER_CRITERIA_IMAGEPATH;
}
if (_tcscspn(argv[nextarg], A_LP_RULETYPES_HASH) < _tcslen(argv[nextarg])) {
dwSuppliedCheckFlags = dwSuppliedCheckFlags | SAFER_CRITERIA_IMAGEHASH;
}
if (_tcscspn(argv[nextarg], A_LP_RULETYPES_CERTIFICATE) < _tcslen(argv[nextarg] )) {
dwSuppliedCheckFlags = dwSuppliedCheckFlags | SAFER_CRITERIA_AUTHENTICODE;
}
} else if (_tcsicmp(&argv[nextarg][1], A_LP_FLAG_SCOPE) == 0) {
nextarg++;
if (nextarg >= argc) {
return DisplaySyntax();
}
STACKMARK(0xAAAA000F);
if (_tcscspn(argv[nextarg], A_LP_SCOPE_HKLM) < _tcslen(argv[nextarg])) {
dwScopeId = SAFER_SCOPEID_MACHINE;
} else if (_tcscspn(argv[nextarg], A_LP_SCOPE_HKCU) < _tcslen(argv[nextarg])) {
dwScopeId = SAFER_SCOPEID_USER;
} else {
return DisplaySyntax();
}
} else {
return DisplaySyntax();
}
} else if (commandMode==CMD_RUN || commandMode == CMD_QUERY || commandMode == CMD_HASH) {
LPTSTR fn;
STACKMARK(0xAAAA000C);
if (commandMode==CMD_RUN && !fLevelIdSupplied) {
IDS_tprintf(IDS_ERR_NOLEVELID);
return DisplaySyntax();
}
//
// This argument is an explicitly named application exe.
//
// if (!GetFullPathName(argv[nextarg],
// sizeof(appname) / sizeof(appname[0]),
// appname, &fn) &&
if (!SearchPath(NULL, argv[nextarg], NULL,
sizeof(appname) / sizeof(appname[0]),
appname, &fn)) {
STACKMARK(0xAAAA000A);
appname[0] = 0;
} else {
_tprintf(TEXT("Program to launch: %s\n"),appname);
}
if (commandMode == CMD_RUN) {
//
// All following arguments is the child's command line.
//
nextarg++;
if (nextarg > argc) {
return DisplaySyntax();
}
for (; nextarg < argc; nextarg++) {
if (_tcslen(cmdline) + _tcslen(argv[nextarg]) + 2 < sizeof(cmdline)) {
if (cmdline[0]) {
_tcscat(cmdline, TEXT(" "));
}
_tcscat(cmdline, argv[nextarg]);
} else {
IDS_tprintf(IDS_ERR_CMDLINETOOLONG);
return 0;
}
}
break;
}
} else {
// Unknown garbage encountered at the end of the line.
return DisplaySyntax();
}
}
STACKMARK(0xAAAA0002);
//
// Application exe must always be specified for some cases.
//
if (commandMode == CMD_RUN || commandMode == CMD_QUERY || commandMode == CMD_HASH) {
if (appname == NULL || appname[0] == '\0') {
IDS_tprintf(IDS_ERR_NOAPPNAME);
return DisplaySyntax();
}
}
switch (commandMode) {
case CMD_HASH:
return ComputeHash(appname);
break;
case CMD_DUMPREG:
return DumpRegistry();
break;
case CMD_REGKEY:
return GetPathFromKeyKey(lpRegkey);
break;
case CMD_LIST:
case CMD_LISTRULES:
if (dwScopeId == -1) {
_tprintf(TEXT("\n"));
IDS_tprintf(IDS_LISTING_HKCU);
retval = ListAllLevels(SAFER_SCOPEID_USER, commandMode == CMD_LISTRULES);
_tprintf(TEXT("\n"));
IDS_tprintf(IDS_LISTING_HKLM);
retval = ListAllLevels(SAFER_SCOPEID_MACHINE, commandMode == CMD_LISTRULES);
} else {
retval = ListAllLevels(dwScopeId, commandMode == CMD_LISTRULES);
}
break;
case CMD_QUERY:
{
SAFER_CODE_PROPERTIES codeproperties;
STACKMARK(0xAAAA0003);
ASSERT(appname != NULL);
// prepare the code properties struct.
memset(&codeproperties, 0, sizeof(codeproperties));
codeproperties.cbSize = sizeof(codeproperties);
codeproperties.dwCheckFlags = (!dwSuppliedCheckFlags) ? SAFER_CRITERIA_IMAGEPATH | SAFER_CRITERIA_IMAGEHASH | SAFER_CRITERIA_AUTHENTICODE : dwSuppliedCheckFlags;
codeproperties.ImagePath = appname;
codeproperties.dwWVTUIChoice = WTD_UI_ALL; //ignored if SAFER_CRITERIA_AUTHENTICODE is not passed in
// Ask the system to find the authorization Level that classifies it.
if (!SaferIdentifyLevel(1, &codeproperties, &hAuthzLevel, NULL))
{
if (GetLastError() == ERROR_NOT_FOUND) {
IDS_tprintf(IDS_ERR_NOLEVELSFOUND);
} else {
printLastErrorWithIDSMessage(IDS_ERR_IMGACCESSERR);
}
return 1;
}
//print information about the rule that matched the program
if (!PrintMatchingRule(hAuthzLevel)) {
printLastErrorWithIDSMessage(IDS_ERR_ERRMATCHRULE);
return 1;
}
SaferCloseLevel(hAuthzLevel);
}
break;
case CMD_RUN:
// Launch the process with the specified WinSafer Level restrictions.
STACKMARK(0xAAAA0005);
if (dwLevelId == SAFER_LEVELID_DISALLOWED) {
IDS_tprintf(IDS_ERR_PROCESSNOLAUNCH);
return 0;
}
if (dwScopeId == -1) {
dwScopeId = SAFER_SCOPEID_USER; //user didn't pass in a scope, so set it for them
}
if (!SaferCreateLevel(dwScopeId, dwLevelId, SAFER_LEVEL_OPEN, &hAuthzLevel, NULL))
{
printLastError();
IDS_tprintf(IDS_ERR_LEVELOPENERR, dwLevelId);
return 1;
}
PrintLevelNameDescription(hAuthzLevel, FALSE);
if (!CreateProcessRestricted(hAuthzLevel, appname, cmdline, &pi, useBreakMode)) {
if (useBreakMode) {
INPUT_RECORD inputrec;
DWORD dwNum;
IDS_tprintf(IDS_PROCSUSPENDED, pi.dwProcessId);
for (;;) {
if (ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE),
&inputrec, 1, &dwNum) &&
inputrec.EventType == KEY_EVENT &&
inputrec.Event.KeyEvent.bKeyDown)
break;
}
ResumeThread(pi.hThread);
IDS_tprintf(IDS_THREADRESUMED);
}
// Close the unnecessary handle
CloseHandle(pi.hThread);
// Wait for the process to terminate and then cleanup.
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
} else {
printLastErrorWithIDSMessage(IDS_ERR_PROCESSLAUNCHERR);
}
SaferCloseLevel(hAuthzLevel);
break;
/*
// Compare or execute as appropriate.
if (commandMode == CMD_QUERY) {
// Compare the Authorization Level with the current access token.
DWORD dwResult;
if (!SaferComputeTokenFromLevel(
hAuthzLevel, NULL, NULL, AUTHZTOKEN_COMPARE_ONLY, (LPVOID) &dwResult))
{
_tprintf(TEXT("Authorization comparison failed (lasterror=%d)\n"), GetLastError());
} else if (dwResult != -1) {
_tprintf(TEXT("Authorization comparison equal or greater privileged.\n"), GetLastError());
} else {
_tprintf(TEXT("Authorization comparison less privileged.\n"), GetLastError());
}
return 0;
} else {
// Launch the process with the specified WinSafer Level restrictions.
ASSERT(commandMode == CMD_RUN);
if (!CreateProcessRestricted(hAuthzLevel, appname, cmdline, &pi, useBreakMode)) {
if (useBreakMode) {
INPUT_RECORD inputrec;
DWORD dwNum;
_tprintf(TEXT("Process %d launched and suspended. Attach a debugger and then\n")
TEXT("strike any key to resume the thread and allow debugging."),
pi.dwProcessId);
for (;;) {
if (ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE),
&inputrec, 1, &dwNum) &&
inputrec.EventType == KEY_EVENT &&
inputrec.Event.KeyEvent.bKeyDown)
break;
}
ResumeThread(pi.hThread);
_tprintf(TEXT("Thread resumed.\n"));
}
// Close the unnecessary handle
CloseHandle(pi.hThread);
// Wait for the process to terminate and then cleanup.
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
// close the Authorization Level handle.
SaferCloseLevel(hAuthzLevel);
retval = 0;
}
}
_tprintf(TEXT("Could not launch process (error=%d).\n"), GetLastError());
retval = 1;
*/
}
if (A_LP_CMD_QUERY) LocalFree(A_LP_CMD_QUERY);
if (A_LP_CMD_RUN) LocalFree(A_LP_CMD_RUN);
if (A_LP_CMD_HASH) LocalFree(A_LP_CMD_HASH);
if (A_LP_CMD_LIST) LocalFree(A_LP_CMD_LIST);
if (A_LP_CMD_LISTRULES) LocalFree(A_LP_CMD_LISTRULES);
if (A_LP_FLAG_LEVELID) LocalFree(A_LP_FLAG_LEVELID);
if (A_LP_FLAG_RULETYPES) LocalFree(A_LP_FLAG_RULETYPES);
if (A_LP_RULETYPES_PATH) LocalFree(A_LP_RULETYPES_PATH);
if (A_LP_RULETYPES_HASH) LocalFree(A_LP_RULETYPES_HASH);
if (A_LP_RULETYPES_CERTIFICATE) LocalFree(A_LP_RULETYPES_CERTIFICATE);
return TRUE;
}