windows-nt/Source/XPSP1/NT/admin/snapin/certmgr/saferentryhashpropertypage.cpp
2020-09-26 16:20:57 +08:00

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;
}