//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: exit.cpp // // Contents: CCertExit implementation // //--------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop #include #include #include #include #include #include "cainfop.h" #include "csdisp.h" #include "cspelog.h" #include "exitlog.h" #include "exit.h" #include "cdosys_i.c" #include #include // begin_sdksample #ifndef DBG_CERTSRV #error -- DBG_CERTSRV not defined! #endif #define myEXITEVENTS \ EXITEVENT_CERTISSUED | \ EXITEVENT_CERTPENDING | \ EXITEVENT_CERTDENIED | \ EXITEVENT_CERTREVOKED | \ EXITEVENT_CERTRETRIEVEPENDING | \ EXITEVENT_CRLISSUED | \ EXITEVENT_SHUTDOWN #define CERTTYPE_ATTR_NAME TEXT("CertificateTemplate") #define MAX_CRL_PROP (32 + 10) #define cbVALUEZEROPAD (3 * sizeof(WCHAR)) extern HINSTANCE g_hInstance; HRESULT GetServerCallbackInterface( OUT ICertServerExit** ppServer, IN LONG Context) { HRESULT hr; if (NULL == ppServer) { hr = E_POINTER; _JumpError(hr, error, "Exit:NULL pointer"); } hr = CoCreateInstance( CLSID_CCertServerExit, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertServerExit, (VOID **) ppServer); _JumpIfError(hr, error, "Exit:CoCreateInstance"); if (*ppServer == NULL) { hr = E_UNEXPECTED; _JumpError(hr, error, "Exit:NULL *ppServer"); } // only set context if nonzero if (0 != Context) { hr = (*ppServer)->SetContext(Context); _JumpIfError(hr, error, "Exit: SetContext"); } error: return(hr); } //+-------------------------------------------------------------------------- // CCertExit::~CCertExit -- destructor // // free memory associated with this instance //+-------------------------------------------------------------------------- CCertExit::~CCertExit() { if (NULL != m_strCAName) { SysFreeString(m_strCAName); } if (NULL != m_pwszRegStorageLoc) { LocalFree(m_pwszRegStorageLoc); } if (NULL != m_hExitKey) { RegCloseKey(m_hExitKey); } if (NULL != m_strDescription) { SysFreeString(m_strDescription); } VariantClear(&m_varFrom); VariantClear(&m_varCC); VariantClear(&m_varSubject); if(m_pICDOConfig) { m_pICDOConfig->Release(); } } //+-------------------------------------------------------------------------- // CCertExit::Initialize -- initialize for a CA & return interesting Event Mask // // Returns S_OK on success. //+-------------------------------------------------------------------------- STDMETHODIMP CCertExit::Initialize( /* [in] */ BSTR const strConfig, /* [retval][out] */ LONG __RPC_FAR *pEventMask) { HRESULT hr = S_OK; HKEY hkey = NULL; DWORD cbbuf; DWORD dwType; ENUM_CATYPES CAType; LPWSTR pwszCLSIDCertExit = NULL; ICertServerExit* pServer = NULL; VARIANT varValue; WCHAR sz[MAX_PATH]; VariantInit(&varValue); #ifdef IDS_MODULE_NAME // no_sdksample LoadString(g_hInstance, IDS_MODULE_NAME, sz, ARRAYSIZE(sz));// no_sdksample #else // no_sdksample CSASSERT(wcslen(wsz_SAMPLE_DESCRIPTION) < ARRAYSIZE(sz)); wcscpy(sz, wsz_SAMPLE_DESCRIPTION); #endif // no_sdksample m_strDescription = SysAllocString(sz); if (NULL == m_strDescription) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:SysAllocString"); } m_strCAName = SysAllocString(strConfig); if (NULL == m_strCAName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:SysAllocString"); } *pEventMask = myEXITEVENTS; DBGPRINT((DBG_SS_CERTEXIT, "Exit:Initialize(%ws) ==> %x\n", m_strCAName, *pEventMask)); // get server callbacks hr = GetServerCallbackInterface(&pServer, 0); _JumpIfError(hr, error, "Exit:GetServerCallbackInterface"); // get storage location hr = pServer->GetCertificateProperty(wszPROPMODULEREGLOC, PROPTYPE_STRING, &varValue); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszPROPMODULEREGLOC); m_pwszRegStorageLoc = (LPWSTR)LocalAlloc(LMEM_FIXED, (wcslen(varValue.bstrVal)+1) *sizeof(WCHAR)); if (NULL == m_pwszRegStorageLoc) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:LocalAlloc"); } wcscpy(m_pwszRegStorageLoc, varValue.bstrVal); VariantClear(&varValue); // get CA type hr = pServer->GetCertificateProperty(wszPROPCATYPE, PROPTYPE_LONG, &varValue); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszPROPCATYPE); CAType = (ENUM_CATYPES) varValue.lVal; VariantClear(&varValue); hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, m_pwszRegStorageLoc, 0, // dwReserved KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_QUERY_VALUE, &m_hExitKey); if (S_OK != hr) { if ((HRESULT) ERROR_FILE_NOT_FOUND == hr) { hr = S_OK; goto error; } _JumpError(hr, error, "Exit:RegOpenKeyEx"); } hr = pServer->GetCertificateProperty(wszPROPCERTCOUNT, PROPTYPE_LONG, &varValue); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszPROPCERTCOUNT); m_cCACert = varValue.lVal; cbbuf = sizeof(m_dwExitPublishFlags); hr = RegQueryValueEx( m_hExitKey, wszREGCERTPUBLISHFLAGS, NULL, // lpdwReserved &dwType, (BYTE *) &m_dwExitPublishFlags, &cbbuf); if (S_OK != hr) { m_dwExitPublishFlags = 0; } hr = _EMailInit(); // no_sdksample _JumpIfError(hr, error, "Exit:_EMailInit"); error: if (NULL != hkey) { RegCloseKey(hkey); } VariantClear(&varValue); if (NULL != pServer) { pServer->Release(); } return(myHError(hr)); } //+-------------------------------------------------------------------------- // CCertExit::_ExpandEnvironmentVariables -- Expand environment variables // //+-------------------------------------------------------------------------- HRESULT CCertExit::_ExpandEnvironmentVariables( IN WCHAR const *pwszIn, OUT WCHAR *pwszOut, IN DWORD cwcOut) { HRESULT hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); WCHAR awcVar[MAX_PATH]; WCHAR const *pwszSrc; WCHAR *pwszDst; WCHAR *pwszDstEnd; WCHAR *pwszVar; DWORD cwc; pwszSrc = pwszIn; pwszDst = pwszOut; pwszDstEnd = &pwszOut[cwcOut]; while (L'\0' != (*pwszDst = *pwszSrc++)) { if ('%' == *pwszDst) { *pwszDst = L'\0'; pwszVar = awcVar; while (L'\0' != *pwszSrc) { if ('%' == *pwszSrc) { pwszSrc++; break; } *pwszVar++ = *pwszSrc++; if (pwszVar >= &awcVar[sizeof(awcVar)/sizeof(awcVar[0]) - 1]) { _JumpError(hr, error, "Exit:overflow 1"); } } *pwszVar = L'\0'; cwc = GetEnvironmentVariable(awcVar, pwszDst, SAFE_SUBTRACT_POINTERS(pwszDstEnd, pwszDst)); if (0 == cwc) { hr = myHLastError(); _JumpError(hr, error, "Exit:GetEnvironmentVariable"); } if ((DWORD) (pwszDstEnd - pwszDst) <= cwc) { _JumpError(hr, error, "Exit:overflow 2"); } pwszDst += cwc; } else { pwszDst++; } if (pwszDst >= pwszDstEnd) { _JumpError(hr, error, "Exit:overflow 3"); } } hr = S_OK; error: return(hr); } //+-------------------------------------------------------------------------- // CCertExit::_WriteCertToFile -- write binary certificate to a file // //+-------------------------------------------------------------------------- HRESULT CCertExit::_WriteCertToFile( IN ICertServerExit *pServer, IN BYTE const *pbCert, IN DWORD cbCert) { HRESULT hr; BSTR strCertFile = NULL; DWORD cbWritten; HANDLE hFile = INVALID_HANDLE_VALUE; WCHAR wszPath[MAX_PATH]; WCHAR const *pwszFile; WCHAR const *pwsz; hr = pServer->GetRequestAttribute(wszPROPEXITCERTFILE, &strCertFile); if (S_OK != hr) { DBGPRINT(( DBG_SS_CERTEXIT, "Exit:GetRequestAttribute(%ws): %x%hs\n", wszPROPEXITCERTFILE, hr, CERTSRV_E_PROPERTY_EMPTY == hr? " EMPTY VALUE" : "")); if (CERTSRV_E_PROPERTY_EMPTY == hr) { hr = S_OK; } goto error; } pwszFile = wcsrchr(strCertFile, L'\\'); if (NULL == pwszFile) { pwszFile = strCertFile; } else { pwszFile++; } pwsz = wcsrchr(pwszFile, L'/'); if (NULL != pwsz) { pwszFile = &pwsz[1]; } hr = _ExpandEnvironmentVariables( L"%SystemRoot%\\System32\\" wszCERTENROLLSHAREPATH L"\\", wszPath, ARRAYSIZE(wszPath)); _JumpIfError(hr, error, "_ExpandEnvironmentVariables"); if (ARRAYSIZE(wszPath) <= wcslen(wszPath) + wcslen(pwszFile)) { hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW); _JumpError(hr, error, "Exit:Path too long"); } wcscat(wszPath, pwszFile); // open file & write binary cert out. hFile = CreateFile( wszPath, GENERIC_WRITE, 0, // dwShareMode NULL, // lpSecurityAttributes CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); // hTemplateFile if (INVALID_HANDLE_VALUE == hFile) { hr = myHLastError(); _JumpErrorStr(hr, error, "Exit:CreateFile", wszPath); } if (!WriteFile(hFile, pbCert, cbCert, &cbWritten, NULL)) { hr = myHLastError(); _JumpErrorStr(hr, error, "Exit:WriteFile", wszPath); } if (cbWritten != cbCert) { hr = STG_E_WRITEFAULT; DBGPRINT(( DBG_SS_CERTEXIT, "Exit:WriteFile(%ws): attempted %x, actual %x bytes: %x\n", wszPath, cbCert, cbWritten, hr)); goto error; } error: // end_sdksample if (hr != S_OK) { LPCWSTR wszStrings[1]; wszStrings[0] = wszPath; ::LogModuleStatus( g_hInstance, MSG_UNABLE_TO_WRITEFILE, FALSE, m_strDescription, wszStrings); } // begin_sdksample if (INVALID_HANDLE_VALUE != hFile) { CloseHandle(hFile); } if (NULL != strCertFile) { SysFreeString(strCertFile); } return(hr); } //+-------------------------------------------------------------------------- // CCertExit::_NotifyNewCert -- Notify the exit module of a new certificate // //+-------------------------------------------------------------------------- HRESULT CCertExit::_NotifyNewCert( /* [in] */ LONG Context) { HRESULT hr; HRESULT hr2; VARIANT varCert; VARIANT varCertType; ICertServerExit *pServer = NULL; BSTR strCertType; VariantInit(&varCert); VariantInit(&varCertType); hr = CoCreateInstance( CLSID_CCertServerExit, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertServerExit, (VOID **) &pServer); _JumpIfError(hr, error, "Exit:CoCreateInstance"); hr = pServer->SetContext(Context); _JumpIfError(hr, error, "Exit:SetContext"); hr = pServer->GetCertificateProperty( wszPROPRAWCERTIFICATE, PROPTYPE_BINARY, &varCert); _JumpIfErrorStr( hr, error, "Exit:GetCertificateProperty", wszPROPRAWCERTIFICATE); if (VT_BSTR != varCert.vt) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Exit:BAD cert var type"); } strCertType = NULL; hr = pServer->GetCertificateProperty( wszPROPCERTIFICATETEMPLATE, PROPTYPE_STRING, &varCertType); if (S_OK == hr && VT_BSTR == varCertType.vt) { strCertType = varCertType.bstrVal; DBGPRINT((DBG_SS_CERTEXIT, "Exit:CertType = %ws\n", strCertType)); } hr = S_OK; // only call write fxns if server policy allows if (m_dwExitPublishFlags & EXITPUB_FILE) { hr2 = _WriteCertToFile( pServer, (BYTE const *) varCert.bstrVal, SysStringByteLen(varCert.bstrVal)); _PrintIfError(hr2, "_WriteCertToFile"); hr = hr2; } // end_sdksample if (m_fEMailNotify) { hr2 = _EMailNotify(pServer, strCertType); _PrintIfError(hr2, "_EMailNotify"); if (S_OK == hr) { hr = hr2; } } // begin_sdksample error: VariantClear(&varCert); VariantClear(&varCertType); if (NULL != pServer) { pServer->Release(); } return(hr); } //+-------------------------------------------------------------------------- // CCertExit::_NotifyCRLIssued -- Notify the exit module of a new certificate // //+-------------------------------------------------------------------------- HRESULT CCertExit::_NotifyCRLIssued( /* [in] */ LONG Context) { HRESULT hr; ICertServerExit *pServer = NULL; DWORD i; VARIANT varBaseCRL; VARIANT varDeltaCRL; DWORD cbbuf; DWORD dwType; VariantInit(&varBaseCRL); VariantInit(&varDeltaCRL); hr = CoCreateInstance( CLSID_CCertServerExit, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertServerExit, (VOID **) &pServer); _JumpIfError(hr, error, "Exit:CoCreateInstance"); hr = pServer->SetContext(Context); _JumpIfError(hr, error, "Exit:SetContext"); // How many CRLs are there? // Loop for each CRL for (i = 0; i < m_cCACert; i++) { WCHAR wszCRLPROP[MAX_CRL_PROP]; // Verify the CRL State says we should update this CRL wsprintf(wszCRLPROP, wszPROPCRLSTATE L".%u", i); hr = pServer->GetCertificateProperty( wszCRLPROP, PROPTYPE_LONG, &varBaseCRL); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszCRLPROP); if (CA_DISP_VALID != varBaseCRL.lVal) { continue; } // Grab the raw base CRL wsprintf(wszCRLPROP, wszPROPRAWCRL L".%u", i); hr = pServer->GetCertificateProperty( wszCRLPROP, PROPTYPE_BINARY, &varBaseCRL); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszCRLPROP); // Grab the raw delta CRL (which may not exist) wsprintf(wszCRLPROP, wszPROPRAWDELTACRL L".%u", i); hr = pServer->GetCertificateProperty( wszCRLPROP, PROPTYPE_BINARY, &varDeltaCRL); _PrintIfErrorStr(hr, "Exit:GetCertificateProperty", wszCRLPROP); // Publish the CRL(s) ... } error: if (NULL != pServer) { pServer->Release(); } VariantClear(&varBaseCRL); VariantClear(&varDeltaCRL); return(hr); } //+-------------------------------------------------------------------------- // CCertExit::Notify -- Notify the exit module of an event // // Returns S_OK. //+-------------------------------------------------------------------------- STDMETHODIMP CCertExit::Notify( /* [in] */ LONG ExitEvent, /* [in] */ LONG Context) { char *psz = "UNKNOWN EVENT"; HRESULT hr = S_OK; switch (ExitEvent) { case EXITEVENT_CERTISSUED: hr = _NotifyNewCert(Context); psz = "certissued"; break; case EXITEVENT_CERTPENDING: psz = "certpending"; break; case EXITEVENT_CERTDENIED: psz = "certdenied"; break; case EXITEVENT_CERTREVOKED: psz = "certrevoked"; break; case EXITEVENT_CERTRETRIEVEPENDING: psz = "retrievepending"; break; case EXITEVENT_CRLISSUED: hr = _NotifyCRLIssued(Context); psz = "crlissued"; break; case EXITEVENT_SHUTDOWN: psz = "shutdown"; break; } DBGPRINT(( DBG_SS_CERTEXIT, "Exit:Notify(%hs=%x, ctx=%x) rc=%x\n", psz, ExitEvent, Context, hr)); return(hr); } STDMETHODIMP CCertExit::GetDescription( /* [retval][out] */ BSTR *pstrDescription) { HRESULT hr = S_OK; WCHAR sz[MAX_PATH]; #ifdef IDS_MODULE_NAME // no_sdksample LoadString(g_hInstance, IDS_MODULE_NAME, sz, ARRAYSIZE(sz));// no_sdksample #else // no_sdksample CSASSERT(wcslen(wsz_SAMPLE_DESCRIPTION) < ARRAYSIZE(sz)); wcscpy(sz, wsz_SAMPLE_DESCRIPTION); #endif // no_sdksample *pstrDescription = SysAllocString(sz); if (NULL == *pstrDescription) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:SysAllocString"); } error: return(hr); } //+-------------------------------------------------------------------------- // CCertExit::GetManageModule // // Returns S_OK on success. //+-------------------------------------------------------------------------- STDMETHODIMP CCertExit::GetManageModule( /* [out, retval] */ ICertManageModule **ppManageModule) { HRESULT hr; *ppManageModule = NULL; hr = CoCreateInstance( CLSID_CCertManageExitModule, NULL, // pUnkOuter CLSCTX_INPROC_SERVER, IID_ICertManageModule, (VOID **) ppManageModule); _JumpIfError(hr, error, "CoCreateInstance"); error: return(hr); } ///////////////////////////////////////////////////////////////////////////// // STDMETHODIMP CCertExit::InterfaceSupportsErrorInfo(REFIID riid) { int i; static const IID *arr[] = { &IID_ICertExit, }; for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { if (IsEqualGUID(*arr[i],riid)) { return(S_OK); } } return(S_FALSE); } // end_sdksample HRESULT LoadAnsiResourceString( IN LONG idmsg, OUT char **ppszString) { HRESULT hr; WCHAR awc[4096]; if (!LoadString(g_hInstance, idmsg, awc, ARRAYSIZE(awc))) { hr = myHLastError(); _JumpError(hr, error, "Exit:LoadString"); } if (!ConvertWszToSz(ppszString, awc, MAXDWORD)) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:ConvertWszToSz"); } hr = S_OK; error: return(hr); } HRESULT CCertExit::_RegGetValue( HKEY hkey, LPCWSTR pcwszValName, VARIANT* pvarValue) { HRESULT hr; DWORD dwType; DWORD cbVal; BYTE* pbVal = NULL; hr = RegQueryValueEx(hkey, pcwszValName, NULL, &dwType, NULL, &cbVal); if (S_OK != hr) { hr = myHError(hr); _JumpErrorStr(hr, error, "RegQueryValueEx", pcwszValName); } pbVal = (BYTE*) LocalAlloc(LMEM_FIXED, cbVal); _JumpIfAllocFailed(pbVal, error); hr = RegQueryValueEx(hkey, pcwszValName, NULL, &dwType, pbVal, &cbVal); if (S_OK != hr) { hr = myHError(hr); _JumpErrorStr(hr, error, "RegQueryValueEx", pcwszValName); } hr = myRegValueToVariant( dwType, cbVal, pbVal, pvarValue); _JumpIfError(hr, error, "myRegValueToVariant"); error: if(pbVal) { LocalFree(pbVal); } return hr; } /*HRESULT CCertExit::_LoadBodyFieldsFromRegistry(HKEY hkeySMTP) { HRESULT hr; HKEY hkeyBodyFields = NULL; DWORD cValues; DWORD cbValue; DWORD dwValCount; DWORD dwType; // Enumerate all Body fields under SMTP\BodyFields key. Value names // are ordered and named 1, 2, 3 and so on. All values should be strings only hr = RegOpenKeyEx( hkeySMTP, wszREGEXITSMTPBODYFIELDSKEY, 0, KEY_QUERY_VALUE|KEY_READ, &hkeyBodyFields); if(S_OK != hr) { hr = myHError(hr); _JumpErrorStr(hr, error, "RegOpenKeyEx", wszREGEXITSMTPKEY); } hr = RegQueryInfoKey( hkeyBodyFields, NULL, NULL, NULL, NULL, NULL, NULL, &cValues, NULL, &cbValue, NULL, NULL); _JumpIfErrorStr(hr, error, "RegQueryInfoKey", wszREGEXITSMTPKEY); m_pawszBodyFields = (LPWSTR*)LocalAlloc(LMEM_FIXED, sizeof(LPWSTR)*cValues); _JumpIfAllocFailed(m_pawszBodyFields, error); ZeroMemory(m_pawszBodyFields, sizeof(LPWSTR)*cValues); for(dwValCount; dwValCountget_Item(CComVariant(pcwszFieldSchemaName),&pfld); _JumpIfErrorStr(hr, error, "CDO::Field::get_Item", pcwszFieldSchemaName); hr = pfld->put_Value(*pvarFieldValue); _JumpIfErrorStr(hr, error, "CDO::Field::put_Value", pcwszFieldSchemaName); error: if(pfld) { pfld->Release(); } return hr; } HRESULT CCertExit::_LoadFieldsFromLSASecret( Fields* pFields) { HRESULT hr; VARIANT var; // don't clear LPWSTR pwszProfileName = NULL; LPWSTR pwszLogonName = NULL; LPWSTR pwszPassword = NULL; BSTR bstrLogonName = NULL; BSTR bstrPassword = NULL; hr = myGetMapiInfo( NULL, &pwszProfileName, // not used &pwszLogonName, &pwszPassword); if(S_OK == hr) // if NTLM is used, username & password aren't needed { bstrLogonName = SysAllocString(pwszLogonName); _JumpIfAllocFailed(bstrLogonName, error); bstrPassword = SysAllocString(pwszPassword); _JumpIfAllocFailed(bstrPassword, error); V_VT(&var) = VT_BSTR; V_BSTR(&var) = bstrLogonName; hr = _SetField( pFields, cdoSendUserName, &var); _JumpIfError(hr, error, "_SetField"); V_VT(&var) = VT_BSTR; V_BSTR(&var) = bstrPassword; hr = _SetField( pFields, cdoSendPassword, &var); _JumpIfError(hr, error, "_SetField"); } error: if (NULL != pwszProfileName) { LocalFree(pwszProfileName); } if (NULL != pwszLogonName) { LocalFree(pwszLogonName); } if (NULL != pwszPassword) { DWORD cwc = wcslen(pwszPassword); ZeroMemory(pwszPassword, cwc * sizeof(WCHAR)); LocalFree(pwszPassword); } if(NULL != bstrLogonName) { SysFreeString(bstrLogonName); } if(NULL != bstrPassword) { DWORD cwc = wcslen(bstrPassword); ZeroMemory(bstrPassword, cwc * sizeof(WCHAR)); SysFreeString(bstrPassword); } return hr; } HRESULT CCertExit::_BuildCAMailAddressAndSubject() { HRESULT hr; LPWSTR pwszMachineDNSName = NULL; LPWSTR pwszMailAddr = NULL; // If not specified in the registry, build SMTP "From" field: // // CA_name@machine_dns_name // if(V_VT(&m_varFrom)==VT_EMPTY || V_VT(&m_varSubject)==VT_EMPTY) { hr = myGetMachineDnsName(&pwszMachineDNSName); _JumpIfError(hr, error, "myGetMachineDnsName"); pwszMailAddr = (LPWSTR)LocalAlloc( LMEM_FIXED, sizeof(WCHAR)*(wcslen(m_strCAName)+wcslen(pwszMachineDNSName)+4)); _JumpIfAllocFailed(pwszMailAddr, error); wcscpy(pwszMailAddr, m_strCAName); wcscat(pwszMailAddr, L"@"); wcscat(pwszMailAddr, pwszMachineDNSName); } if(V_VT(&m_varFrom)==VT_EMPTY) { V_BSTR(&m_varFrom) = SysAllocString(pwszMailAddr); _JumpIfAllocFailed(V_BSTR(&m_varFrom), error); V_VT(&m_varFrom) = VT_BSTR; } if(V_VT(&m_varSubject)==VT_EMPTY) { V_BSTR(&m_varSubject) = SysAllocString(pwszMailAddr); _JumpIfAllocFailed(V_BSTR(&m_varSubject), error); V_VT(&m_varSubject) = VT_BSTR; } error: if(pwszMachineDNSName) { LocalFree(pwszMachineDNSName); } if(pwszMailAddr) { LocalFree(pwszMailAddr); } return hr; } HRESULT CCertExit::_EMailInit() { HRESULT hr = S_OK; Fields* pFields = NULL; if ((EXITPUB_EMAILNOTIFYSMARTCARD | EXITPUB_EMAILNOTIFYALL) & m_dwExitPublishFlags) { m_fEMailNotify = TRUE; } if (m_fEMailNotify) { hr = CoCreateInstance(CDO::CLSID_Configuration, NULL, CLSCTX_INPROC_SERVER, CDO::IID_IConfiguration, reinterpret_cast(&m_pICDOConfig)); _JumpIfError(hr, error, "CoCreateInstance CDO_IConfiguration"); hr = m_pICDOConfig->get_Fields(&pFields); _JumpIfError(hr, error, "CDO::IConfig::get_Fields"); hr = _LoadFieldsFromRegistry(pFields); _JumpIfError(hr, error, "_LoadFieldsFromRegistry"); hr = _LoadFieldsFromLSASecret(pFields); _JumpIfError(hr, error, "_LoadFieldsFromLSASecret"); hr = _BuildCAMailAddressAndSubject(); _JumpIfError(hr, error, "_BuildFromField"); hr = pFields->Update(); _JumpIfError(hr, error, "config"); } error: if (S_OK != hr) { m_fEMailNotify = FALSE; if(m_pICDOConfig) { m_pICDOConfig->Release(); m_pICDOConfig = NULL; } } if(pFields) { pFields->Release(); } return(hr); } HRESULT GetCertTypeFriendlyName( IN WCHAR const *pwszCertType, OUT BSTR *pstrFriendlyName) { HRESULT hr; HCERTTYPE hCertType = NULL; WCHAR **apwszNames = NULL; CSASSERT(NULL == *pstrFriendlyName); hr = CAFindCertTypeByName( pwszCertType, NULL, // hCAInfo CT_FIND_LOCAL_SYSTEM | CT_ENUM_MACHINE_TYPES | CT_ENUM_USER_TYPES, // dwFlags &hCertType); _JumpIfErrorStr(hr, error, "Exit:CAFindCertTypeByName", pwszCertType); hr = CAGetCertTypeProperty( hCertType, CERTTYPE_PROP_FRIENDLY_NAME, &apwszNames); _JumpIfError(hr, error, "Exit:CAGetCertTypeProperty"); if (NULL == apwszNames[0]) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); _JumpError(hr, error, "Exit:NULL friendly name"); } *pstrFriendlyName = SysAllocString(apwszNames[0]); if (NULL == *pstrFriendlyName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:SysAllocString"); } error: if (NULL != apwszNames) { CAFreeCertTypeProperty(hCertType, apwszNames); } if (NULL != hCertType) { CACloseCertType(hCertType); } return(hr); } HRESULT GetStringProperty( IN ICertServerExit *pServer, IN BOOL fRequest, IN BOOL fAllowUnknown, OPTIONAL IN WCHAR *pwszProp, OUT BSTR *pstr) { HRESULT hr; VARIANT var; WCHAR awc[64]; VariantInit(&var); CSASSERT(NULL == *pstr); if (NULL == pwszProp) { hr = CERTSRV_E_PROPERTY_EMPTY; } else { if (fRequest) { hr = pServer->GetRequestProperty(pwszProp, PROPTYPE_STRING, &var); } else { hr = pServer->GetCertificateProperty( pwszProp, PROPTYPE_STRING, &var); } } if (!fAllowUnknown || CERTSRV_E_PROPERTY_EMPTY != hr) { _JumpIfErrorStr( hr, error, fRequest? "Exit:GetRequestProperty" : "Exit:GetCertificateProperty", pwszProp); if (VT_BSTR != var.vt) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpErrorStr(hr, error, "Exit:BAD var type", pwszProp); } *pstr = var.bstrVal; var.vt = VT_EMPTY; } else { if (!LoadString(g_hInstance, IDS_MAPI_UNKNOWN, awc, ARRAYSIZE(awc))) { hr = myHLastError(); _JumpError(hr, error, "Exit:LoadString"); } *pstr = SysAllocString(awc); if (NULL == *pstr) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:SysAllocString"); } } hr = S_OK; error: VariantClear(&var); return(hr); } HRESULT CCertExit::_EMailNotify( IN ICertServerExit *pServer, OPTIONAL IN BSTR strCertType) { HRESULT hr; WCHAR *apwsz[6]; WCHAR *pwszMessage = NULL; BSTR strEMail = NULL; BSTR strRequester = NULL; BSTR strDN = NULL; BSTR strSerialNumber = NULL; BSTR strCertTypeFriendlyName = NULL; IMessage* pMsg = NULL; hr = GetStringProperty( pServer, FALSE, FALSE, wszPROPEMAIL, &strEMail); _PrintIfErrorStr(hr, "Exit:GetStringProperty", wszPROPEMAIL); hr = GetStringProperty( pServer, TRUE, TRUE, wszPROPREQUESTERNAME, &strRequester); _JumpIfError(hr, error, "Exit:GetStringProperty"); hr = GetStringProperty( pServer, FALSE, TRUE, wszPROPDISTINGUISHEDNAME, &strDN); _JumpIfError(hr, error, "Exit:GetStringProperty"); hr = GetStringProperty( pServer, FALSE, TRUE, wszPROPCERTIFICATESERIALNUMBER, &strSerialNumber); _JumpIfError(hr, error, "Exit:GetStringProperty"); if (NULL == strCertType) { // "Unknown" hr = GetStringProperty( pServer, FALSE, TRUE, NULL, &strCertTypeFriendlyName); _JumpIfError(hr, error, "Exit:GetStringProperty"); } else { hr = GetCertTypeFriendlyName(strCertType, &strCertTypeFriendlyName); _PrintIfErrorStr(hr, "Exit:GetCertTypeFriendlyName", strCertType); } // %1 is used for a newline! // A new certificate requested by %2 was issued for\n%3\n // Certificate Type: %4\n // Serial Number: %5\n // Certification Authority: %6 on Server %7\n apwsz[0] = L"\n"; apwsz[1] = strRequester; apwsz[2] = strDN; apwsz[3] = NULL != strCertTypeFriendlyName? strCertTypeFriendlyName : strCertType; apwsz[4] = strSerialNumber; apwsz[5] = m_strCAName; CSASSERT(6 <= ARRAYSIZE(apwsz)); if (0 == FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ARGUMENT_ARRAY, g_hInstance, // lpSource MSG_ENROLLMENT_NOTIFICATION, // dwMessageId MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // dwLanguageId (WCHAR *) &pwszMessage, // lpBuffer 0, // nSize (va_list *) apwsz)) // Arguments { hr = myHLastError(); _JumpError(hr, error, "Exit:FormatMessage"); } hr = CoCreateInstance(CDO::CLSID_Message, NULL, CLSCTX_INPROC_SERVER, CDO::IID_IMessage, reinterpret_cast(&pMsg)); _JumpIfError(hr, error, "CoCreateInstance CDO_IConfiguration"); hr = pMsg->putref_Configuration(m_pICDOConfig); _JumpIfError(hr, error, "putref_Configuration"); // compose and send message hr = pMsg->put_To(strEMail); _JumpIfError(hr, error, "put_To"); hr = pMsg->put_From(V_BSTR(&m_varFrom)); _JumpIfError(hr, error, "put_From"); hr = pMsg->put_TextBody(pwszMessage); _JumpIfError(hr, error, "put_Body"); // optional, could be empty if(VT_BSTR==V_VT(&m_varCC)) { hr = pMsg->put_CC(V_BSTR(&m_varCC)); _JumpIfError(hr, error, "put_CC"); } // optional, could be empty if(VT_BSTR==V_VT(&m_varSubject)) { hr = pMsg->put_Subject(V_BSTR(&m_varSubject)); _JumpIfError(hr, error, "put_Subject"); } hr = pMsg->Send(); _JumpIfError(hr, error, "Send"); error: if (NULL != pwszMessage) { LocalFree(pwszMessage); } if (NULL != strEMail) { SysFreeString(strEMail); } if (NULL != strRequester) { SysFreeString(strRequester); } if (NULL != strDN) { SysFreeString(strDN); } if (NULL != strSerialNumber) { SysFreeString(strSerialNumber); } if (NULL != strCertTypeFriendlyName) { SysFreeString(strCertTypeFriendlyName); } if(pMsg) { pMsg->Release(); } return(hr); }