You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
11 KiB
334 lines
11 KiB
/*
|
|
** m i m e d e m . c p p
|
|
**
|
|
** Purpose: implement the loader functions for defer/demand -loaded libraries
|
|
**
|
|
** Creators: yst
|
|
** Created: 2/10/99
|
|
**
|
|
** Copyright (C) Microsoft Corp. 1999
|
|
*/
|
|
|
|
|
|
#include "pch.hxx"
|
|
#include "imnact.h"
|
|
#include <acctimp.h>
|
|
#include "resource.h"
|
|
|
|
|
|
// W4 stuff
|
|
#pragma warning(disable: 4201) // nameless struct/union
|
|
#pragma warning(disable: 4514) // unreferenced inline function removed
|
|
|
|
#define IMPLEMENT_LOADER_FUNCTIONS
|
|
#include "mimedem.h"
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// CRIT_GET_PROC_ADDR
|
|
// --------------------------------------------------------------------------------
|
|
#define CRIT_GET_PROC_ADDR(h, fn, temp) \
|
|
temp = (TYP_##fn) GetProcAddress(h, #fn); \
|
|
if (temp) \
|
|
VAR_##fn = temp; \
|
|
else \
|
|
{ \
|
|
AssertSz(0, VAR_##fn" failed to load"); \
|
|
goto error; \
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// RESET
|
|
// --------------------------------------------------------------------------------
|
|
#define RESET(fn) VAR_##fn = LOADER_##fn;
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// GET_PROC_ADDR
|
|
// --------------------------------------------------------------------------------
|
|
#define GET_PROC_ADDR(h, fn) \
|
|
VAR_##fn = (TYP_##fn) GetProcAddress(h, #fn); \
|
|
Assert(VAR_##fn != NULL); \
|
|
if(NULL == VAR_##fn ) { \
|
|
VAR_##fn = LOADER_##fn; \
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// GET_PROC_ADDR_ORDINAL
|
|
// --------------------------------------------------------------------------------
|
|
#define GET_PROC_ADDR_ORDINAL(h, fn, ord) \
|
|
VAR_##fn = (TYP_##fn) GetProcAddress(h, MAKEINTRESOURCE(ord)); \
|
|
Assert(VAR_##fn != NULL); \
|
|
if(NULL == VAR_##fn ) { \
|
|
VAR_##fn = LOADER_##fn; \
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// GET_PROC_ADDR3
|
|
// --------------------------------------------------------------------------------
|
|
#define GET_PROC_ADDR3(h, fn, varname) \
|
|
VAR_##varname = (TYP_##varname) GetProcAddress(h, #fn); \
|
|
Assert(VAR_##varname != NULL);
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Variables
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
static HMODULE s_hMimeOle = 0;
|
|
|
|
static CRITICAL_SECTION g_csDefMimeLoad = {0};
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// InitDemandLoadedLibs
|
|
// --------------------------------------------------------------------------------
|
|
void InitDemandMimeole(void)
|
|
{
|
|
InitializeCriticalSection(&g_csDefMimeLoad);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// FreeDemandLoadedLibs
|
|
// --------------------------------------------------------------------------------
|
|
void FreeDemandMimeOle(void)
|
|
{
|
|
EnterCriticalSection(&g_csDefMimeLoad);
|
|
|
|
SafeFreeLibrary(s_hMimeOle);
|
|
|
|
LeaveCriticalSection(&g_csDefMimeLoad);
|
|
DeleteCriticalSection(&g_csDefMimeLoad);
|
|
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// DemandLoadCrypt32
|
|
// --------------------------------------------------------------------------------
|
|
BOOL DemandLoadMimeOle(void)
|
|
{
|
|
BOOL fRet = TRUE;
|
|
|
|
EnterCriticalSection(&g_csDefMimeLoad);
|
|
|
|
if (0 == s_hMimeOle)
|
|
{
|
|
s_hMimeOle = LoadLibrary("INETCOMM.DLL");
|
|
AssertSz((NULL != s_hMimeOle), TEXT("LoadLibrary failed on INETCOMM.DLL"));
|
|
|
|
if (0 == s_hMimeOle)
|
|
fRet = FALSE;
|
|
else
|
|
{
|
|
GET_PROC_ADDR(s_hMimeOle, MimeOleSMimeCapsToDlg);
|
|
GET_PROC_ADDR(s_hMimeOle, MimeOleSMimeCapsFromDlg);
|
|
GET_PROC_ADDR(s_hMimeOle, MimeOleSMimeCapsFull);
|
|
GET_PROC_ADDR(s_hMimeOle, MimeOleSMimeCapInit);
|
|
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&g_csDefMimeLoad);
|
|
return fRet;
|
|
}
|
|
|
|
HRESULT HrGetHighestSymcaps(LPBYTE * ppbSymcap, ULONG *pcbSymcap);
|
|
|
|
|
|
const BYTE c_RC2_40_ALGORITHM_ID[] =
|
|
{0x30, 0x0F, 0x30, 0x0D, 0x06, 0x08, 0x2A, 0x86,
|
|
0x48, 0x86, 0xF7, 0x0D, 0x03, 0x02, 0x02, 0x01,
|
|
0x28};
|
|
const ULONG cbRC2_40_ALGORITHM_ID = 0x11; // Must be 11 hex to match size!
|
|
|
|
BOOL AdvSec_FillEncAlgCombo(HWND hwnd, IImnAccount *pAcct, PCCERT_CONTEXT * prgCerts)
|
|
{
|
|
HRESULT hr;
|
|
THUMBBLOB tb = {0,0};
|
|
|
|
// Get the default caps blob from the registry
|
|
// hr = poi->pOpt->GetProperty(MAKEPROPSTRING(OPT_MAIL_DEFENCRYPTSYMCAPS), &var, 0);
|
|
if (SUCCEEDED(hr = pAcct->GetProp(AP_SMTP_ENCRYPT_ALGTH, NULL, &tb.cbSize)))
|
|
{
|
|
if (!MemAlloc((void**)&tb.pBlobData, tb.cbSize))
|
|
tb.pBlobData = NULL;
|
|
else
|
|
hr = pAcct->GetProp(AP_SMTP_ENCRYPT_ALGTH, tb.pBlobData, &tb.cbSize);
|
|
}
|
|
|
|
if (FAILED(hr) || ! tb.cbSize || ! tb.pBlobData)
|
|
{
|
|
HrGetHighestSymcaps(&tb.pBlobData, &tb.cbSize);
|
|
}
|
|
|
|
if (tb.pBlobData && tb.cbSize)
|
|
{
|
|
// Init the caps->dlg engine
|
|
if (FAILED(hr = MimeOleSMimeCapsToDlg(
|
|
tb.pBlobData,
|
|
tb.cbSize,
|
|
(prgCerts ? 1 : 0),
|
|
prgCerts,
|
|
hwnd,
|
|
IDC_ALGCOMBO, // combo box for encryption algorithms
|
|
0, // combo box for signing algorithms (we combine encrypt and signing)
|
|
0))) // id of checkbox for pkcs7-opaque. We handle this elsewhere.
|
|
{
|
|
DOUTL(1024, "MimeOleSMimeCapsToDlg -> %x\n", hr);
|
|
}
|
|
|
|
SafeMemFree(tb.pBlobData);
|
|
}
|
|
|
|
return(SUCCEEDED(hr));
|
|
}
|
|
|
|
// Largest symcap is currently 0x4E with 3DES, RC2/128, RC2/64, DES, RC2/40 and SHA-1.
|
|
// You may want to bump up the size when FORTEZZA algorithms are supported.
|
|
#define CCH_BEST_SYMCAP 0x50
|
|
|
|
HRESULT HrGetHighestSymcaps(LPBYTE * ppbSymcap, ULONG *pcbSymcap)
|
|
{
|
|
HRESULT hr=S_OK;
|
|
LPVOID pvSymCapsCookie = NULL;
|
|
LPBYTE pbEncode = NULL;
|
|
ULONG cbEncode = 0;
|
|
DWORD dwBits;
|
|
// The MimeOleSMimeCapsFull call is quite expensive. The results are always
|
|
// the same during a session. (They can only change with software upgrade.)
|
|
// Cache the results here for better performance.
|
|
static BYTE szSaveBestSymcap[CCH_BEST_SYMCAP];
|
|
static ULONG cbSaveBestSymcap = 0;
|
|
|
|
if (cbSaveBestSymcap == 0)
|
|
{
|
|
// Init with no symcap gives max allowed by providers
|
|
hr = MimeOleSMimeCapInit(NULL, NULL, &pvSymCapsCookie);
|
|
if (FAILED(hr))
|
|
goto exit;
|
|
|
|
if (pvSymCapsCookie)
|
|
{
|
|
// Finish up with SymCaps
|
|
MimeOleSMimeCapsFull(pvSymCapsCookie, TRUE, FALSE, pbEncode, &cbEncode);
|
|
|
|
if (cbEncode)
|
|
{
|
|
if (! MemAlloc((LPVOID *)&pbEncode, cbEncode))
|
|
cbEncode = 0;
|
|
else
|
|
{
|
|
hr = MimeOleSMimeCapsFull(pvSymCapsCookie, TRUE, FALSE, pbEncode, &cbEncode);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// Save this symcap in the static array for next time
|
|
// Only if we have room!
|
|
if (cbEncode <= CCH_BEST_SYMCAP)
|
|
{
|
|
memcpy(szSaveBestSymcap, pbEncode, cbEncode);
|
|
cbSaveBestSymcap = cbEncode;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SafeMemFree(pvSymCapsCookie);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// We have saved the best in the static array. Avoid the time intensive
|
|
// MimeOle query.
|
|
cbEncode = cbSaveBestSymcap;
|
|
if (! MemAlloc((LPVOID *)&pbEncode, cbEncode))
|
|
cbEncode = 0;
|
|
else
|
|
memcpy(pbEncode, szSaveBestSymcap, cbEncode);
|
|
}
|
|
|
|
exit:
|
|
if (! pbEncode)
|
|
{
|
|
// Hey, there should ALWAYS be at least RC2 (40 bit). What happened?
|
|
AssertSz(cbEncode, "MimeOleSMimeCapGetEncAlg gave us no encoding algorithm");
|
|
|
|
// Try to fix it up as best you can. Stick in the RC2 value.
|
|
cbEncode = cbRC2_40_ALGORITHM_ID;
|
|
if (MemAlloc((LPVOID *)&pbEncode, cbEncode))
|
|
{
|
|
memcpy(pbEncode, (LPBYTE)c_RC2_40_ALGORITHM_ID, cbEncode);
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
if (cbEncode && pbEncode)
|
|
{
|
|
*pcbSymcap = cbEncode;
|
|
*ppbSymcap = pbEncode;
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
BOOL AdvSec_GetEncryptAlgCombo(HWND hwnd, IImnAccount *pAcct)
|
|
{
|
|
HRESULT hr;
|
|
LPBYTE pbSymCaps = NULL;
|
|
ULONG cbSymCaps = 0;
|
|
|
|
// How big a buffer do I need?
|
|
hr = MimeOleSMimeCapsFromDlg(hwnd,
|
|
IDC_ALGCOMBO, // idEncryptAlgs
|
|
0, // idSignAlgs,
|
|
0, // idBlob,
|
|
NULL,
|
|
&cbSymCaps);
|
|
|
|
// Never mind the hr, it's screwy. Do we have a size?
|
|
if (cbSymCaps)
|
|
{
|
|
if (MemAlloc((void **)&pbSymCaps, cbSymCaps))
|
|
{
|
|
if (hr = MimeOleSMimeCapsFromDlg(hwnd,
|
|
IDC_ALGCOMBO, // idEncryptAlgs
|
|
0, // idSignAlgs,
|
|
0, // idBlob,
|
|
pbSymCaps, &cbSymCaps))
|
|
{
|
|
DOUTL(1024, "MimeOleSMimeCapsFromDlg -> %x", hr);
|
|
}
|
|
else
|
|
{
|
|
LPBYTE pbBestSymcaps = NULL;
|
|
ULONG cbBestSymcaps = 0;
|
|
|
|
// Compare symcaps to highest available.
|
|
if (SUCCEEDED(HrGetHighestSymcaps(&pbBestSymcaps, &cbBestSymcaps)) &&
|
|
(cbBestSymcaps == cbSymCaps && (0 == memcmp(pbBestSymcaps, pbSymCaps, cbBestSymcaps)))) {
|
|
// Best available symcaps. Set it to default value of NULL (which should delete the prop.)
|
|
SafeMemFree(pbSymCaps);
|
|
cbSymCaps = 0;
|
|
pbSymCaps = NULL;
|
|
}
|
|
SafeMemFree(pbBestSymcaps);
|
|
|
|
pAcct->SetProp(AP_SMTP_ENCRYPT_ALGTH, pbSymCaps, cbSymCaps);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DOUTL(1024, "MemAlloc of SymCaps blob failed");
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DOUTL(1024, "BAD NEWS: First MimeOleSMimeCapsFromDlg didn't return size", hr);
|
|
Assert(hr); // Weird, maybe there isn't a symcaps?
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
SafeMemFree(pbSymCaps);
|
|
|
|
return(SUCCEEDED(hr));
|
|
}
|
|
|
|
|