/* ** 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 #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)); }