1150 lines
36 KiB
C++
1150 lines
36 KiB
C++
//+---------------------------------------------------------------------------
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 2000-2001.
|
|
//
|
|
// File: SaferEntryHashPropertyPage.cpp
|
|
//
|
|
// Contents: Implementation of CSaferEntryHashPropertyPage
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// SaferEntryHashPropertyPage.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include <gpedit.h>
|
|
#include "certmgr.h"
|
|
#include "compdata.h"
|
|
#include "SaferEntryHashPropertyPage.h"
|
|
#include "SaferUtil.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
PCWSTR pcszNEWLINE = L"\x00d\x00a";
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSaferEntryHashPropertyPage property page
|
|
|
|
CSaferEntryHashPropertyPage::CSaferEntryHashPropertyPage(
|
|
CSaferEntry& rSaferEntry,
|
|
LONG_PTR lNotifyHandle,
|
|
LPDATAOBJECT pDataObject,
|
|
bool bReadOnly,
|
|
CCertMgrComponentData* pCompData,
|
|
bool bIsMachine)
|
|
: CHelpPropertyPage(CSaferEntryHashPropertyPage::IDD),
|
|
m_rSaferEntry (rSaferEntry),
|
|
m_bDirty (false),
|
|
m_cbFileHash (0),
|
|
m_lNotifyHandle (lNotifyHandle),
|
|
m_pDataObject (pDataObject),
|
|
m_bReadOnly (bReadOnly),
|
|
m_bIsMachine (bIsMachine),
|
|
m_hashAlgid (0),
|
|
m_bFirst (true),
|
|
m_pCompData (pCompData)
|
|
{
|
|
::ZeroMemory (&m_nFileSize, sizeof (__int64));
|
|
::ZeroMemory (m_rgbFileHash, SAFER_MAX_HASH_SIZE);
|
|
|
|
//{{AFX_DATA_INIT(CSaferEntryHashPropertyPage)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
m_rSaferEntry.AddRef ();
|
|
m_rSaferEntry.IncrementOpenPageCount ();
|
|
|
|
m_rSaferEntry.GetHash (m_rgbFileHash, m_cbFileHash, m_nFileSize,
|
|
m_hashAlgid);
|
|
}
|
|
|
|
CSaferEntryHashPropertyPage::~CSaferEntryHashPropertyPage()
|
|
{
|
|
if ( m_lNotifyHandle )
|
|
MMCFreeNotifyHandle (m_lNotifyHandle);
|
|
m_rSaferEntry.DecrementOpenPageCount ();
|
|
m_rSaferEntry.Release ();
|
|
}
|
|
|
|
void CSaferEntryHashPropertyPage::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CHelpPropertyPage::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CSaferEntryHashPropertyPage)
|
|
DDX_Control(pDX, IDC_HASH_ENTRY_HASHFILE_DETAILS, m_hashFileDetailsEdit);
|
|
DDX_Control(pDX, IDC_HASH_ENTRY_DESCRIPTION, m_descriptionEdit);
|
|
DDX_Control(pDX, IDC_HASH_ENTRY_SECURITY_LEVEL, m_securityLevelCombo);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CSaferEntryHashPropertyPage, CHelpPropertyPage)
|
|
//{{AFX_MSG_MAP(CSaferEntryHashPropertyPage)
|
|
ON_BN_CLICKED(IDC_HASH_ENTRY_BROWSE, OnHashEntryBrowse)
|
|
ON_EN_CHANGE(IDC_HASH_ENTRY_DESCRIPTION, OnChangeHashEntryDescription)
|
|
ON_CBN_SELCHANGE(IDC_HASH_ENTRY_SECURITY_LEVEL, OnSelchangeHashEntrySecurityLevel)
|
|
ON_EN_CHANGE(IDC_HASH_HASHED_FILE_PATH, OnChangeHashHashedFilePath)
|
|
ON_EN_SETFOCUS(IDC_HASH_HASHED_FILE_PATH, OnSetfocusHashHashedFilePath)
|
|
ON_EN_CHANGE(IDC_HASH_ENTRY_HASHFILE_DETAILS, OnChangeHashEntryHashfileDetails)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSaferEntryHashPropertyPage message handlers
|
|
void CSaferEntryHashPropertyPage::DoContextHelp (HWND hWndControl)
|
|
{
|
|
_TRACE (1, L"Entering CSaferEntryHashPropertyPage::DoContextHelp\n");
|
|
static const DWORD help_map[] =
|
|
{
|
|
IDC_HASH_ENTRY_HASHFILE_DETAILS, IDH_HASH_ENTRY_APPLICATION_NAME,
|
|
IDC_HASH_ENTRY_BROWSE, IDH_HASH_ENTRY_BROWSE,
|
|
IDC_HASH_ENTRY_DESCRIPTION, IDH_HASH_ENTRY_DESCRIPTION,
|
|
IDC_HASH_ENTRY_LAST_MODIFIED, IDH_HASH_ENTRY_LAST_MODIFIED,
|
|
IDC_HASH_HASHED_FILE_PATH, IDH_HASH_HASHED_FILE_PATH,
|
|
IDC_HASH_ENTRY_SECURITY_LEVEL, IDH_HASH_ENTRY_SECURITY_LEVEL,
|
|
0, 0
|
|
};
|
|
|
|
switch (::GetDlgCtrlID (hWndControl))
|
|
{
|
|
case IDC_HASH_ENTRY_HASHFILE_DETAILS:
|
|
case IDC_HASH_ENTRY_BROWSE:
|
|
case IDC_HASH_ENTRY_DESCRIPTION:
|
|
case IDC_HASH_ENTRY_LAST_MODIFIED:
|
|
case IDC_HASH_HASHED_FILE_PATH:
|
|
case IDC_HASH_ENTRY_SECURITY_LEVEL:
|
|
if ( !::WinHelp (
|
|
hWndControl,
|
|
GetF1HelpFilename(),
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR) help_map) )
|
|
{
|
|
_TRACE (0, L"WinHelp () failed: 0x%x\n", GetLastError ());
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
_TRACE (-1, L"Leaving CSaferEntryHashPropertyPage::DoContextHelp\n");
|
|
}
|
|
|
|
BOOL CSaferEntryHashPropertyPage::OnInitDialog()
|
|
{
|
|
CHelpPropertyPage::OnInitDialog();
|
|
|
|
DWORD dwFlags = 0;
|
|
m_rSaferEntry.GetFlags (dwFlags);
|
|
|
|
ASSERT (m_pCompData);
|
|
if ( m_pCompData )
|
|
{
|
|
CPolicyKey policyKey (m_pCompData->m_pGPEInformation,
|
|
SAFER_HKLM_REGBASE,
|
|
m_bIsMachine);
|
|
InitializeSecurityLevelComboBox (m_securityLevelCombo, false,
|
|
m_rSaferEntry.GetLevel (), policyKey.GetKey (),
|
|
m_pCompData->m_pdwSaferLevels,
|
|
m_bIsMachine);
|
|
|
|
m_hashFileDetailsEdit.SetWindowText (m_rSaferEntry.GetHashFriendlyName ());
|
|
m_descriptionEdit.LimitText (SAFER_MAX_DESCRIPTION_SIZE);
|
|
m_descriptionEdit.SetWindowText (m_rSaferEntry.GetDescription ());
|
|
|
|
SetDlgItemText (IDC_HASH_ENTRY_LAST_MODIFIED, m_rSaferEntry.GetLongLastModified ());
|
|
|
|
SendDlgItemMessage (IDC_HASH_HASHED_FILE_PATH, EM_LIMITTEXT, 64);
|
|
|
|
if ( m_bReadOnly )
|
|
{
|
|
SendDlgItemMessage (IDC_HASH_HASHED_FILE_PATH, EM_SETREADONLY, TRUE);
|
|
|
|
m_securityLevelCombo.EnableWindow (FALSE);
|
|
GetDlgItem (IDC_HASH_ENTRY_BROWSE)->EnableWindow (FALSE);
|
|
|
|
m_descriptionEdit.SendMessage (EM_SETREADONLY, TRUE);
|
|
|
|
m_hashFileDetailsEdit.SendMessage (EM_SETREADONLY, TRUE);
|
|
}
|
|
|
|
if ( m_cbFileHash )
|
|
{
|
|
// Only allow editing on the creation of a new hash
|
|
SendDlgItemMessage (IDC_HASH_HASHED_FILE_PATH, EM_SETREADONLY, TRUE);
|
|
|
|
FormatAndDisplayHash ();
|
|
|
|
CString szText;
|
|
|
|
VERIFY (szText.LoadString (IDS_HASH_TITLE));
|
|
SetDlgItemText (IDC_HASH_TITLE, szText);
|
|
SetDlgItemText (IDC_HASH_INSTRUCTIONS, L"");
|
|
}
|
|
else
|
|
SetDlgItemText (IDC_DATE_LAST_MODIFIED_LABEL, L"");
|
|
}
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
typedef struct tagVERHEAD {
|
|
WORD wTotLen;
|
|
WORD wValLen;
|
|
WORD wType; /* always 0 */
|
|
WCHAR szKey[(sizeof("VS_VERSION_INFO")+3)&~03];
|
|
VS_FIXEDFILEINFO vsf;
|
|
} VERHEAD ;
|
|
|
|
/*
|
|
* [alanau]
|
|
*
|
|
* MyGetFileVersionInfo: Maps a file directly without using LoadLibrary. This ensures
|
|
* that the right version of the file is examined without regard to where the loaded image
|
|
* is. Since this is a local function, it allocates the memory which is freed by the caller.
|
|
* This makes it slightly more efficient than a GetFileVersionInfoSize/GetFileVersionInfo pair.
|
|
*/
|
|
BOOL CSaferEntryHashPropertyPage::MyGetFileVersionInfo(LPTSTR lpszFilename, LPVOID *lpVersionInfo)
|
|
{
|
|
// VS_FIXEDFILEINFO *pvsFFI = NULL;
|
|
// UINT uiBytes = 0;
|
|
HINSTANCE hinst = 0;
|
|
HRSRC hVerRes = 0;
|
|
HANDLE FileHandle = NULL;
|
|
HANDLE MappingHandle = NULL;
|
|
LPVOID DllBase = NULL;
|
|
VERHEAD *pVerHead = 0;
|
|
BOOL bResult = FALSE;
|
|
DWORD dwHandle = 0;
|
|
DWORD dwLength = 0;
|
|
|
|
if (!lpVersionInfo)
|
|
return FALSE;
|
|
|
|
*lpVersionInfo = NULL;
|
|
|
|
FileHandle = CreateFile( lpszFilename,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if (FileHandle == INVALID_HANDLE_VALUE)
|
|
goto Cleanup;
|
|
|
|
MappingHandle = CreateFileMapping( FileHandle,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if (MappingHandle == NULL)
|
|
goto Cleanup;
|
|
|
|
DllBase = MapViewOfFileEx( MappingHandle,
|
|
FILE_MAP_READ,
|
|
0,
|
|
0,
|
|
0,
|
|
NULL
|
|
);
|
|
if (DllBase == NULL)
|
|
goto Cleanup;
|
|
|
|
hinst = (HMODULE)((ULONG_PTR)DllBase | 0x00000001);
|
|
__try {
|
|
|
|
hVerRes = FindResource(hinst, MAKEINTRESOURCE(VS_VERSION_INFO), VS_FILE_INFO);
|
|
if (hVerRes == NULL)
|
|
{
|
|
// Probably a 16-bit file. Fall back to system APIs.
|
|
dwLength = GetFileVersionInfoSize(lpszFilename, &dwHandle);
|
|
if( !dwLength )
|
|
{
|
|
if(!GetLastError())
|
|
SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
|
|
__leave;
|
|
}
|
|
|
|
*lpVersionInfo = ::LocalAlloc (LPTR, dwLength);
|
|
if ( !(*lpVersionInfo) )
|
|
__leave;
|
|
|
|
if(!GetFileVersionInfo(lpszFilename, 0, dwLength, *lpVersionInfo))
|
|
__leave;
|
|
|
|
bResult = TRUE;
|
|
__leave;
|
|
}
|
|
|
|
pVerHead = (VERHEAD*)LoadResource(hinst, hVerRes);
|
|
if (pVerHead == NULL)
|
|
__leave;
|
|
|
|
*lpVersionInfo = ::LocalAlloc (LPTR, pVerHead->wTotLen + pVerHead->wTotLen/2);
|
|
if (*lpVersionInfo == NULL)
|
|
__leave;
|
|
|
|
memcpy(*lpVersionInfo, (PVOID)pVerHead, pVerHead->wTotLen);
|
|
bResult = TRUE;
|
|
} __except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
|
|
Cleanup:
|
|
if (FileHandle)
|
|
CloseHandle(FileHandle);
|
|
if (MappingHandle)
|
|
CloseHandle(MappingHandle);
|
|
if (DllBase)
|
|
UnmapViewOfFile(DllBase);
|
|
if (*lpVersionInfo && bResult == FALSE)
|
|
::LocalFree (*lpVersionInfo);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Method: OnHashEntryBrowse
|
|
//
|
|
// Purpose: Allow the user to browse for a file, then create a hash and an
|
|
// output string for use as the friendly name, using the following
|
|
// rules:
|
|
//
|
|
// If either the product name or description information is found in
|
|
// the version resource, provide the following (in order):
|
|
//
|
|
// Description
|
|
// Product name
|
|
// Company name
|
|
// File name
|
|
// Fixed file version
|
|
//
|
|
// Details:
|
|
// 1) Use the fixed file version, since that is what is shown in the
|
|
// Windows Explorer properties.
|
|
// 2) Prefer the long file name to the 8.3 name.
|
|
// 3) Delimit the fields with '\n'.
|
|
// 4) If the field is missing, don't output the field or the delimiter
|
|
// 5) Instead of displaying the file version on a new line, display
|
|
// it after the file name in parens, as in "Filename (1.0.0.0)"
|
|
// 6) Since we are limited to 256 TCHARs, we have to accomodate long
|
|
// text. First, format the text as described above to determine
|
|
// its length. If it is too long, truncate one field at a time in
|
|
// the following order: Company name, Description, Product name.
|
|
// To truncate a field, set it to a maximum of 60 TCHARs, then
|
|
// append a "...\n" to visually indicate that the field was
|
|
// truncated. Lastly, if the text is still to long, use the 8.3
|
|
// file name instead of the long filename.
|
|
//
|
|
// If neither the product name nor description information is found,
|
|
// provide the following (in order):
|
|
//
|
|
// File name
|
|
// File size
|
|
// File last modified date
|
|
//
|
|
// Details:
|
|
// 1) If the file size is < 1 KB, display the number in bytes, as in
|
|
// "123 bytes". If the file size is >= 1 KB, display in KB, as in
|
|
// "123 KB". Of course, 1 KB is 1024 bytes. Note that the older
|
|
// style format "123K" is no longer used in Windows.
|
|
// 2) For the last modified date, use the short format version in the
|
|
// user's current locale.
|
|
// 3) Delimit the fields with '\n'.
|
|
// 4) If the field is missing, don't output the field or the delimiter
|
|
//
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CSaferEntryHashPropertyPage::OnHashEntryBrowse()
|
|
{
|
|
CString szFileFilter;
|
|
VERIFY (szFileFilter.LoadString (IDS_SAFER_PATH_ENTRY_FILE_FILTER));
|
|
|
|
// replace "|" with 0;
|
|
const size_t nFilterLen = wcslen (szFileFilter) + 1;
|
|
PWSTR pszFileFilter = new WCHAR [nFilterLen];
|
|
if ( pszFileFilter )
|
|
{
|
|
wcscpy (pszFileFilter, szFileFilter);
|
|
for (int nIndex = 0; nIndex < nFilterLen; nIndex++)
|
|
{
|
|
if ( L'|' == pszFileFilter[nIndex] )
|
|
pszFileFilter[nIndex] = 0;
|
|
}
|
|
|
|
WCHAR szFile[MAX_PATH];
|
|
::ZeroMemory (szFile, MAX_PATH * sizeof (WCHAR));
|
|
wcscpy (szFile, m_szLastOpenedFile);
|
|
|
|
OPENFILENAME ofn;
|
|
::ZeroMemory (&ofn, sizeof (OPENFILENAME));
|
|
|
|
ofn.lStructSize = sizeof (OPENFILENAME);
|
|
ofn.hwndOwner = m_hWnd;
|
|
ofn.lpstrFilter = (PCWSTR) pszFileFilter;
|
|
ofn.lpstrFile = szFile;
|
|
ofn.nMaxFile = MAX_PATH;
|
|
ofn.Flags = OFN_DONTADDTORECENT |
|
|
OFN_FORCESHOWHIDDEN | OFN_HIDEREADONLY;
|
|
|
|
|
|
CThemeContextActivator activator;
|
|
BOOL bResult = ::GetOpenFileName (&ofn);
|
|
if ( bResult )
|
|
{
|
|
m_szLastOpenedFile = ofn.lpstrFile;
|
|
HANDLE hFile = ::CreateFile(
|
|
ofn.lpstrFile, // file name
|
|
GENERIC_READ, // access mode
|
|
FILE_SHARE_READ, // share mode
|
|
0, // SD
|
|
OPEN_EXISTING, // how to create
|
|
FILE_ATTRIBUTE_NORMAL, // file attributes
|
|
0 ); // handle to template file
|
|
if ( INVALID_HANDLE_VALUE != hFile )
|
|
{
|
|
bResult = GetFileSizeEx(
|
|
hFile, // handle to file
|
|
(PLARGE_INTEGER) &m_nFileSize); // file size
|
|
if ( !bResult )
|
|
{
|
|
DWORD dwErr = GetLastError ();
|
|
CloseHandle (hFile);
|
|
_TRACE (0, L"GetFileSizeEx () failed: 0x%x\n", dwErr);
|
|
CString text;
|
|
CString caption;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
text.FormatMessage (IDS_CANNOT_GET_FILESIZE, ofn.lpstrFile,
|
|
GetSystemMessage (dwErr));
|
|
|
|
MessageBox (text, caption, MB_OK);
|
|
|
|
return;
|
|
}
|
|
|
|
if ( 0 == m_nFileSize )
|
|
{
|
|
CString text;
|
|
CString caption;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
text.FormatMessage (IDS_ZERO_BYTE_FILE_CANNOT_HASH, ofn.lpstrFile);
|
|
|
|
MessageBox (text, caption, MB_OK);
|
|
|
|
return;
|
|
}
|
|
|
|
FILETIME ftLastModified;
|
|
|
|
|
|
bResult = ::GetFileTime (hFile, // handle to file
|
|
0, // creation time
|
|
0, // last access time
|
|
&ftLastModified); // last write time
|
|
|
|
::ZeroMemory (m_rgbFileHash, SAFER_MAX_HASH_SIZE);
|
|
HRESULT hr = GetSignedFileHash (ofn.lpstrFile, m_rgbFileHash,
|
|
&m_cbFileHash, &m_hashAlgid);
|
|
if ( FAILED (hr) )
|
|
{
|
|
m_hashAlgid = 0;
|
|
hr = ComputeMD5Hash (hFile, m_rgbFileHash, m_cbFileHash);
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
if ( SHA1_HASH_LEN == m_cbFileHash )
|
|
m_hashAlgid = CALG_SHA;
|
|
else if ( MD5_HASH_LEN == m_cbFileHash )
|
|
m_hashAlgid = CALG_MD5;
|
|
else
|
|
{
|
|
ASSERT (0);
|
|
}
|
|
}
|
|
}
|
|
|
|
VERIFY (CloseHandle (hFile));
|
|
hFile = 0;
|
|
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
FormatAndDisplayHash ();
|
|
|
|
PBYTE pData = 0;
|
|
bResult = MyGetFileVersionInfo (ofn.lpstrFile, (LPVOID*) &pData);
|
|
if ( bResult )
|
|
{
|
|
CString infoString = BuildHashFileInfoString (pData);
|
|
m_hashFileDetailsEdit.SetWindowText (infoString);
|
|
|
|
|
|
m_bDirty = true;
|
|
SetModified ();
|
|
}
|
|
else
|
|
{
|
|
CString infoString (wcsrchr(ofn.lpstrFile, L'\\') + 1);
|
|
CString szDate;
|
|
|
|
infoString += pcszNEWLINE;
|
|
WCHAR szBuffer[32];
|
|
CString szText;
|
|
if ( m_nFileSize < 1024 )
|
|
{
|
|
wsprintf (szBuffer, L"%u", m_nFileSize);
|
|
infoString += szBuffer;
|
|
VERIFY (szText.LoadString (IDS_BYTES));
|
|
infoString += L" ";
|
|
infoString += szText;
|
|
}
|
|
else
|
|
{
|
|
__int64 nFileSize = m_nFileSize;
|
|
nFileSize += 1024; // this causes us to round up
|
|
nFileSize /= 1024;
|
|
wsprintf (szBuffer, L"%u ", nFileSize);
|
|
infoString += szBuffer;
|
|
VERIFY (szText.LoadString (IDS_KB));
|
|
infoString += L" ";
|
|
infoString += szText;
|
|
}
|
|
|
|
hr = FormatDate (ftLastModified, szDate,
|
|
DATE_SHORTDATE, true);
|
|
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
infoString += pcszNEWLINE;
|
|
infoString += szDate;
|
|
}
|
|
|
|
m_hashFileDetailsEdit.SetWindowText (infoString);
|
|
m_bDirty = true;
|
|
SetModified ();
|
|
}
|
|
::LocalFree (pData);
|
|
}
|
|
else
|
|
{
|
|
CString text;
|
|
CString caption;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
text.FormatMessage (IDS_CANNOT_HASH_FILE, ofn.lpstrFile,
|
|
GetSystemMessage (hr));
|
|
|
|
MessageBox (text, caption, MB_OK);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD dwErr = GetLastError ();
|
|
_TRACE (0, L"CreateFile (%s, OPEN_EXISTING) failed: 0x%x\n",
|
|
ofn.lpstrFile, dwErr);
|
|
|
|
CString text;
|
|
CString caption;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
text.FormatMessage (IDS_FILE_CANNOT_BE_READ, ofn.lpstrFile,
|
|
GetSystemMessage (dwErr));
|
|
|
|
MessageBox (text, caption, MB_OK);
|
|
}
|
|
}
|
|
|
|
delete [] pszFileFilter;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* BuildHashFileInfoString()
|
|
*
|
|
* Given a file name, GetVersion retrieves the version
|
|
* information from the specified file.
|
|
*
|
|
*
|
|
\***************************************************************************/
|
|
const PWSTR VERSION_INFO_KEY_ROOT = L"\\StringFileInfo\\";
|
|
|
|
CString CSaferEntryHashPropertyPage::BuildHashFileInfoString (PVOID pData)
|
|
{
|
|
CString szInfoString;
|
|
PVOID lpInfo = 0;
|
|
UINT cch = 0;
|
|
CString key;
|
|
WCHAR szBuffer[10];
|
|
CString keyBase;
|
|
|
|
wsprintf (szBuffer, L"%04X", GetUserDefaultLangID ());
|
|
wcscat (szBuffer, L"04B0");
|
|
|
|
keyBase = VERSION_INFO_KEY_ROOT;
|
|
keyBase += szBuffer;
|
|
keyBase += L"\\";
|
|
|
|
CString productName;
|
|
CString description;
|
|
CString companyName;
|
|
CString fileName;
|
|
CString fileVersion;
|
|
|
|
|
|
key = keyBase + L"ProductName";
|
|
if ( VerQueryValue (pData, const_cast <PWSTR>((PCWSTR) key), &lpInfo, &cch) )
|
|
{
|
|
productName = (PWSTR) lpInfo;
|
|
}
|
|
|
|
key = keyBase + L"FileDescription";
|
|
if ( VerQueryValue (pData, const_cast <PWSTR>((PCWSTR) key), &lpInfo, &cch) )
|
|
{
|
|
description = (PWSTR) lpInfo;
|
|
}
|
|
|
|
key = keyBase + L"CompanyName";
|
|
if ( VerQueryValue (pData, const_cast <PWSTR>((PCWSTR) key), &lpInfo, &cch) )
|
|
{
|
|
companyName = (PWSTR) lpInfo;
|
|
}
|
|
|
|
key = keyBase + L"OriginalFilename";
|
|
if ( VerQueryValue (pData, const_cast <PWSTR>((PCWSTR) key), &lpInfo, &cch) )
|
|
{
|
|
fileName = (PWSTR) lpInfo;
|
|
}
|
|
|
|
// Get Fixedlength fileInfo
|
|
VS_FIXEDFILEINFO *pFixedFileInfo = 0;
|
|
if ( VerQueryValue (pData, L"\\", (PVOID*) &pFixedFileInfo, &cch) )
|
|
{
|
|
WCHAR szFileVer[32];
|
|
|
|
wsprintf(szFileVer, L"%u.%u.%u.%u",
|
|
HIWORD(pFixedFileInfo->dwFileVersionMS),
|
|
LOWORD(pFixedFileInfo->dwFileVersionMS),
|
|
HIWORD(pFixedFileInfo->dwFileVersionLS),
|
|
LOWORD(pFixedFileInfo->dwFileVersionLS));
|
|
fileVersion = szFileVer;
|
|
}
|
|
|
|
int nLen = 0;
|
|
do {
|
|
szInfoString = ConcatStrings (productName, description, companyName, fileName, fileVersion);
|
|
nLen = szInfoString.GetLength ();
|
|
if ( nLen >= SAFER_MAX_FRIENDLYNAME_SIZE )
|
|
{
|
|
if ( CheckLengthAndTruncateToken (companyName) )
|
|
continue;
|
|
|
|
if ( CheckLengthAndTruncateToken (description) )
|
|
continue;
|
|
|
|
if ( CheckLengthAndTruncateToken (productName) )
|
|
continue;
|
|
|
|
szInfoString.SetAt (SAFER_MAX_FRIENDLYNAME_SIZE-4, 0);
|
|
szInfoString += L"...";
|
|
}
|
|
} while (nLen >= SAFER_MAX_FRIENDLYNAME_SIZE);
|
|
|
|
return szInfoString;
|
|
}
|
|
|
|
bool CSaferEntryHashPropertyPage::CheckLengthAndTruncateToken (CString& token)
|
|
{
|
|
bool bResult = false;
|
|
const int nMAX_ITEM_LEN = 60;
|
|
|
|
int nItemLen = token.GetLength ();
|
|
if ( nItemLen > nMAX_ITEM_LEN )
|
|
{
|
|
token.SetAt (nMAX_ITEM_LEN-5, 0);
|
|
token += L"...";
|
|
token += pcszNEWLINE;
|
|
bResult = true;
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
CString CSaferEntryHashPropertyPage::ConcatStrings (
|
|
const CString& productName,
|
|
const CString& description,
|
|
const CString& companyName,
|
|
const CString& fileName,
|
|
const CString& fileVersion)
|
|
{
|
|
CString szInfoString;
|
|
|
|
if ( !description.IsEmpty () )
|
|
szInfoString += description + pcszNEWLINE;
|
|
|
|
if ( !productName.IsEmpty () )
|
|
szInfoString += productName + pcszNEWLINE;
|
|
|
|
if ( !companyName.IsEmpty () )
|
|
szInfoString += companyName + pcszNEWLINE;
|
|
|
|
if ( !fileName.IsEmpty () )
|
|
szInfoString += fileName;
|
|
|
|
if ( !fileVersion.IsEmpty () )
|
|
{
|
|
szInfoString += L" (";
|
|
szInfoString += fileVersion + L")";;
|
|
}
|
|
|
|
return szInfoString;
|
|
}
|
|
|
|
BOOL CSaferEntryHashPropertyPage::OnApply()
|
|
{
|
|
CString szText;
|
|
CThemeContextActivator activator;
|
|
|
|
GetDlgItemText (IDC_HASH_HASHED_FILE_PATH, szText);
|
|
|
|
if ( szText.IsEmpty () )
|
|
{
|
|
CString szCaption;
|
|
|
|
VERIFY (szCaption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
VERIFY (szText.LoadString (IDS_USER_MUST_ENTER_HASH));
|
|
|
|
MessageBox (szText, szCaption, MB_OK);
|
|
|
|
GetDlgItem (IDC_HASH_HASHED_FILE_PATH)->SetFocus ();
|
|
return FALSE;
|
|
}
|
|
|
|
if ( !m_bReadOnly && m_bDirty )
|
|
{
|
|
if ( !ConvertStringToHash ((PCWSTR) szText) )
|
|
{
|
|
GetDlgItem (IDC_HASH_HASHED_FILE_PATH)->SetFocus ();
|
|
return FALSE;
|
|
}
|
|
|
|
// Get image size and hash type
|
|
bool bBadFormat = false;
|
|
int nFirstColon = szText.Find (L":", 0);
|
|
if ( -1 != nFirstColon )
|
|
{
|
|
int nSecondColon = szText.Find (L":", nFirstColon+1);
|
|
if ( -1 != nSecondColon )
|
|
{
|
|
CString szImageSize = szText.Mid (nFirstColon+1, nSecondColon - (nFirstColon + 1));
|
|
CString szHashType = szText.Right (((int) wcslen (szText)) - (nSecondColon + 1));
|
|
|
|
|
|
m_nFileSize = wcstol (szImageSize, 0, 10);
|
|
m_hashAlgid = wcstol (szHashType, 0, 10);
|
|
}
|
|
else
|
|
bBadFormat = true;
|
|
}
|
|
else
|
|
bBadFormat = true;
|
|
|
|
if ( bBadFormat )
|
|
{
|
|
CString caption;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
VERIFY (szText.LoadString (IDS_HASH_STRING_BAD_FORMAT));
|
|
|
|
MessageBox (szText, caption, MB_OK);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( !m_cbFileHash )
|
|
{
|
|
CString caption;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
VERIFY (szText.LoadString (IDS_NO_APPLICATION_SELECTED));
|
|
|
|
MessageBox (szText, caption, MB_OK);
|
|
GetDlgItem (IDC_HASH_ENTRY_BROWSE)->SetFocus ();
|
|
return FALSE;
|
|
}
|
|
|
|
if ( m_bDirty )
|
|
{
|
|
// Set the level
|
|
int nCurSel = m_securityLevelCombo.GetCurSel ();
|
|
ASSERT (CB_ERR != nCurSel);
|
|
m_rSaferEntry.SetLevel ((DWORD) m_securityLevelCombo.GetItemData (nCurSel));
|
|
|
|
// Set description
|
|
m_descriptionEdit.GetWindowText (szText);
|
|
m_rSaferEntry.SetDescription (szText);
|
|
|
|
// Set friendly name
|
|
m_hashFileDetailsEdit.GetWindowText (szText);
|
|
m_rSaferEntry.SetHashFriendlyName (szText);
|
|
|
|
// Get and save flags
|
|
DWORD dwFlags = 0;
|
|
|
|
m_rSaferEntry.SetFlags (dwFlags);
|
|
|
|
m_rSaferEntry.SetHash (m_rgbFileHash, m_cbFileHash, m_nFileSize, m_hashAlgid);
|
|
HRESULT hr = m_rSaferEntry.Save ();
|
|
if ( SUCCEEDED (hr) )
|
|
{
|
|
if ( m_lNotifyHandle )
|
|
MMCPropertyChangeNotify (
|
|
m_lNotifyHandle, // handle to a notification
|
|
(LPARAM) m_pDataObject); // unique identifier
|
|
|
|
m_bDirty = false;
|
|
}
|
|
else
|
|
{
|
|
CString caption;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
if ( HRESULT_FROM_WIN32 (ERROR_INVALID_PARAMETER) != hr )
|
|
szText.FormatMessage (IDS_ERROR_SAVING_ENTRY, GetSystemMessage (hr));
|
|
else
|
|
VERIFY (szText.LoadString (IDS_HASH_STRING_BAD_FORMAT));
|
|
|
|
MessageBox (szText, caption, MB_OK);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return CHelpPropertyPage::OnApply();
|
|
}
|
|
|
|
void CSaferEntryHashPropertyPage::OnChangeHashEntryDescription()
|
|
{
|
|
m_bDirty = true;
|
|
SetModified ();
|
|
}
|
|
|
|
void CSaferEntryHashPropertyPage::OnSelchangeHashEntrySecurityLevel()
|
|
{
|
|
m_bDirty = true;
|
|
SetModified ();
|
|
}
|
|
|
|
void CSaferEntryHashPropertyPage::OnChangeHashHashedFilePath()
|
|
{
|
|
m_bDirty = true;
|
|
SetModified ();
|
|
}
|
|
|
|
bool CSaferEntryHashPropertyPage::FormatMemBufToString(PWSTR *ppString, PBYTE pbData, DWORD cbData)
|
|
{
|
|
const WCHAR RgwchHex[] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
|
|
|
DWORD i = 0;
|
|
PBYTE pb;
|
|
|
|
*ppString = (LPWSTR) LocalAlloc (LPTR, ((cbData * 3) * sizeof(WCHAR)));
|
|
if ( !*ppString )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// copy to the buffer
|
|
//
|
|
pb = pbData;
|
|
while (pb <= &(pbData[cbData-1]))
|
|
{
|
|
(*ppString)[i++] = RgwchHex[(*pb & 0xf0) >> 4];
|
|
(*ppString)[i++] = RgwchHex[*pb & 0x0f];
|
|
pb++;
|
|
}
|
|
(*ppString)[i] = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CSaferEntryHashPropertyPage::ConvertStringToHash (PCWSTR pszString)
|
|
{
|
|
_TRACE (1, L"Entering CSaferEntryHashPropertyPage::ConvertStringToHash (%s)\n", pszString);
|
|
bool bRetVal = true;
|
|
BYTE rgbFileHash[SAFER_MAX_HASH_SIZE];
|
|
::ZeroMemory (rgbFileHash, SAFER_MAX_HASH_SIZE);
|
|
|
|
DWORD cbFileHash = 0;
|
|
DWORD dwNumHashChars = 0;
|
|
bool bFirst = true;
|
|
bool bEndOfHash = false;
|
|
CThemeContextActivator activator;
|
|
|
|
for (int nIndex = 0; !bEndOfHash && pszString[nIndex] && bRetVal; nIndex++)
|
|
{
|
|
if ( cbFileHash >= SAFER_MAX_HASH_SIZE )
|
|
{
|
|
CString caption;
|
|
CString text;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
text.FormatMessage (IDS_HASH_STRING_TOO_LONG, SAFER_MAX_HASH_SIZE, SAFER_MAX_HASH_SIZE/4);
|
|
_TRACE (0, L"%s", (PCWSTR) text);
|
|
|
|
VERIFY (text.LoadString (IDS_HASH_STRING_BAD_FORMAT));
|
|
MessageBox (text, caption, MB_ICONWARNING | MB_OK);
|
|
bRetVal = false;
|
|
break;
|
|
}
|
|
dwNumHashChars++;
|
|
|
|
switch (pszString[nIndex])
|
|
{
|
|
case L'0':
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'1':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x10;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x01;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'2':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x20;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x02;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'3':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x30;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x03;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'4':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x40;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x04;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'5':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x50;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x05;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'6':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x60;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x06;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'7':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x70;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x07;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'8':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x80;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x08;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'9':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0x90;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x09;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'a':
|
|
case L'A':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0xA0;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x0A;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'b':
|
|
case L'B':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0xB0;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x0B;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'c':
|
|
case L'C':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0xC0;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x0C;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'd':
|
|
case L'D':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0xD0;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x0D;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'e':
|
|
case L'E':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0xE0;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x0E;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L'f':
|
|
case L'F':
|
|
if ( bFirst )
|
|
rgbFileHash[cbFileHash] |= 0xF0;
|
|
else
|
|
rgbFileHash[cbFileHash] |= 0x0F;
|
|
bFirst = !bFirst;
|
|
break;
|
|
|
|
case L':':
|
|
// end of hash
|
|
bEndOfHash = true;
|
|
bFirst = !bFirst;
|
|
dwNumHashChars--; // ':' already counted, subtract it
|
|
break;
|
|
|
|
default:
|
|
bRetVal = false;
|
|
{
|
|
CString caption;
|
|
CString text;
|
|
WCHAR szChar[2];
|
|
|
|
szChar[0] = pszString[nIndex];
|
|
szChar[1] = 0;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
text.FormatMessage (IDS_HASH_STRING_INVALID_CHAR, szChar);
|
|
_TRACE (0, L"%s", (PCWSTR) text);
|
|
|
|
VERIFY (text.LoadString (IDS_HASH_STRING_BAD_FORMAT));
|
|
|
|
MessageBox (text, caption, MB_ICONWARNING | MB_OK);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ( bFirst )
|
|
cbFileHash++;
|
|
}
|
|
|
|
if ( bRetVal )
|
|
{
|
|
// 2 characters map to 1 each byte in the hash
|
|
if ( MD5_HASH_LEN != dwNumHashChars/2 && SHA1_HASH_LEN != dwNumHashChars/2 )
|
|
{
|
|
CString caption;
|
|
CString text;
|
|
|
|
VERIFY (caption.LoadString (IDS_SAFER_WINDOWS_NODE_NAME));
|
|
VERIFY (text.LoadString (IDS_HASH_INVALID_LENGTH));
|
|
_TRACE (0, L"%s", (PCWSTR) text);
|
|
|
|
VERIFY (text.LoadString (IDS_HASH_STRING_BAD_FORMAT));
|
|
|
|
MessageBox (text, caption, MB_ICONWARNING | MB_OK);
|
|
bRetVal = false;
|
|
}
|
|
else
|
|
{
|
|
m_cbFileHash = cbFileHash;
|
|
memcpy (m_rgbFileHash, rgbFileHash, SAFER_MAX_HASH_SIZE);
|
|
}
|
|
}
|
|
|
|
_TRACE (-1, L"Leaving CSaferEntryHashPropertyPage::ConvertStringToHash (): %s\n",
|
|
bRetVal ? L"true" : L"false");
|
|
return bRetVal;
|
|
}
|
|
|
|
void CSaferEntryHashPropertyPage::OnSetfocusHashHashedFilePath()
|
|
{
|
|
if ( m_bFirst )
|
|
{
|
|
if ( true == m_bReadOnly )
|
|
SendDlgItemMessage (IDC_HASH_HASHED_FILE_PATH, EM_SETSEL, (WPARAM) 0, 0);
|
|
m_bFirst = false;
|
|
}
|
|
}
|
|
|
|
void CSaferEntryHashPropertyPage::FormatAndDisplayHash ()
|
|
{
|
|
PWSTR pwszText = 0;
|
|
|
|
if ( FormatMemBufToString (&pwszText, m_rgbFileHash, m_cbFileHash) )
|
|
{
|
|
WCHAR szAlgID[10];
|
|
_ltow (m_hashAlgid, szAlgID, 10);
|
|
|
|
PWSTR pszFormattedText = new WCHAR[wcslen (pwszText) + 50];
|
|
if ( pszFormattedText )
|
|
{
|
|
|
|
wsprintf (pszFormattedText, L"%s:%ld:", pwszText,
|
|
m_nFileSize);
|
|
wcscat (pszFormattedText, szAlgID);
|
|
SetDlgItemText (IDC_HASH_HASHED_FILE_PATH,
|
|
pszFormattedText);
|
|
delete [] pszFormattedText;
|
|
}
|
|
LocalFree (pwszText);
|
|
}
|
|
}
|
|
|
|
void CSaferEntryHashPropertyPage::OnChangeHashEntryHashfileDetails()
|
|
{
|
|
SetModified ();
|
|
m_bDirty = true;
|
|
}
|