//+-------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: exit.cpp // // Contents: CCertExitSQLSample implementation // //--------------------------------------------------------------------------- #include "pch.cpp" #pragma hdrstop #include #include "celib.h" #include "exit.h" #include "module.h" BOOL fDebug = DBG_CERTSRV; #ifndef DBG_CERTSRV #error -- DBG_CERTSRV not defined! #endif #define ceEXITEVENTS \ EXITEVENT_CERTISSUED | \ EXITEVENT_CERTREVOKED #define CERTTYPE_ATTR_NAME TEXT("CertificateTemplate") extern HINSTANCE g_hInstance; // worker 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; } //+-------------------------------------------------------------------------- // CCertExitSQLSample::~CCertExitSQLSample -- destructor // // free memory associated with this instance //+-------------------------------------------------------------------------- CCertExitSQLSample::~CCertExitSQLSample() { if (SQL_NULL_HDBC != m_hdbc1) { SQLDisconnect(m_hdbc1); SQLFreeHandle(SQL_HANDLE_DBC, m_hdbc1); } if (SQL_NULL_HENV != m_henv) SQLFreeHandle(SQL_HANDLE_ENV, m_henv); if (NULL != m_strCAName) { SysFreeString(m_strCAName); } } //+-------------------------------------------------------------------------- // CCertExitSQLSample::Initialize -- initialize for a CA & return interesting Event Mask // // Returns S_OK on success. //+-------------------------------------------------------------------------- STDMETHODIMP CCertExitSQLSample::Initialize( /* [in] */ BSTR const strConfig, /* [retval][out] */ LONG __RPC_FAR *pEventMask) { HRESULT hr = S_OK; DWORD dwType; WCHAR rgchDsn[MAX_PATH]; WCHAR rgchUser[MAX_PATH]; WCHAR rgchPwd[MAX_PATH]; DWORD cbTmp; ICertServerExit *pServer = NULL; SQLRETURN retcode = SQL_SUCCESS; DWORD dwDisposition; HKEY hkeyStorageLocation = NULL; VARIANT varValue; VariantInit(&varValue); m_strCAName = SysAllocString(strConfig); if (NULL == m_strCAName) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:SysAllocString"); } hr = GetServerCallbackInterface(&pServer, 0); _JumpIfError(hr, error, "GetServerCallbackInterface"); hr = pServer->GetCertificateProperty( wszPROPMODULEREGLOC, PROPTYPE_STRING, &varValue); _JumpIfError(hr, error, "GetCertificateProperty"); hr = RegCreateKeyEx( HKEY_LOCAL_MACHINE, varValue.bstrVal, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hkeyStorageLocation, &dwDisposition); _JumpIfError(hr, error, "RegCreateKeyEx"); cbTmp = sizeof(rgchDsn)*sizeof(WCHAR); // dsn hr = RegQueryValueEx( hkeyStorageLocation, wszREG_EXITSQL_DSN, 0, &dwType, (PBYTE)rgchDsn, &cbTmp); if (dwType != REG_SZ) hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); _JumpIfError(hr, error, "RegQueryValueEx DSN"); cbTmp = sizeof(rgchUser)*sizeof(WCHAR); // username hr = RegQueryValueEx( hkeyStorageLocation, wszREG_EXITSQL_USER, 0, &dwType, (PBYTE)rgchUser, &cbTmp); if (dwType != REG_SZ) hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); _JumpIfError(hr, error, "RegQueryValueEx User"); cbTmp = sizeof(rgchPwd)*sizeof(WCHAR); // password hr = RegQueryValueEx( hkeyStorageLocation, wszREG_EXITSQL_PASSWORD, 0, &dwType, (PBYTE)rgchPwd, &cbTmp); if (dwType != REG_SZ) hr = HRESULT_FROM_WIN32(ERROR_DATATYPE_MISMATCH); _JumpIfError(hr, error, "RegQueryValueEx Pwd"); // Allocate the ODBC Environment and save handle. retcode = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_henv); if (!SQL_SUCCEEDED(retcode)) _JumpError(retcode, error, "SQLAllocHandle"); // Let ODBC know this is an ODBC 3.0 application. retcode = SQLSetEnvAttr(m_henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_INTEGER); if (!SQL_SUCCEEDED(retcode)) _JumpError(retcode, error, "SQLSetEnvAttr"); // Allocate an ODBC connection and connect. retcode = SQLAllocHandle(SQL_HANDLE_DBC, m_henv, &m_hdbc1); if (!SQL_SUCCEEDED(retcode)) _JumpError(retcode, error, "SQLAllocHandle"); retcode = SQLConnect(m_hdbc1, rgchDsn, SQL_NTS, rgchUser, SQL_NTS, rgchPwd, SQL_NTS); if (!SQL_SUCCEEDED(retcode)) _JumpError(retcode, error, "SQLConnect"); *pEventMask = ceEXITEVENTS; DBGPRINT((fDebug, "Exit:Initialize(%ws) ==> %x\n", m_strCAName, *pEventMask)); hr = S_OK; error: if (pServer) pServer->Release(); if (hkeyStorageLocation) RegCloseKey(hkeyStorageLocation); if (!SQL_SUCCEEDED(retcode)) hr = ERROR_BAD_QUERY_SYNTAX; return(ceHError(hr)); } //+-------------------------------------------------------------------------- // CCertExitSQLSample::_NotifyNewCert -- Notify the exit module of a new certificate // //+-------------------------------------------------------------------------- HRESULT CCertExitSQLSample::_NotifyNewCert( /* [in] */ LONG Context) { HRESULT hr; VARIANT varValue; ICertServerExit *pServer = NULL; SYSTEMTIME stBefore, stAfter; FILETIME ftBefore, ftAfter; // properties LONG lRequestID; BSTR bstrCertType = NULL; BSTR bstrRequester = NULL; DATE dateBefore; DATE dateAfter; VariantInit(&varValue); hr = GetServerCallbackInterface(&pServer, Context); _JumpIfError(hr, error, "GetServerCallbackInterface"); // ReqID hr = pServer->GetRequestProperty( wszPROPREQUESTREQUESTID, PROPTYPE_LONG, &varValue); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszPROPREQUESTREQUESTID); if (VT_I4 != varValue.vt) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Exit:BAD cert var type"); } lRequestID = varValue.lVal; VariantClear(&varValue); // Requester Name hr = pServer->GetRequestProperty( wszPROPREQUESTERNAME, PROPTYPE_STRING, &varValue); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszPROPREQUESTREQUESTID); if (VT_BSTR != varValue.vt) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Exit:BAD cert var type"); } bstrRequester = varValue.bstrVal; VariantInit(&varValue); // don't init, bstrRequester nows owns memory // not before hr = pServer->GetCertificateProperty( wszPROPCERTIFICATENOTBEFOREDATE, PROPTYPE_DATE, &varValue); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszPROPREQUESTREQUESTID); if (VT_DATE != varValue.vt) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Exit:BAD cert var type"); } dateBefore = varValue.date; VariantClear(&varValue); // not after hr = pServer->GetCertificateProperty( wszPROPCERTIFICATENOTAFTERDATE, PROPTYPE_DATE, &varValue); _JumpIfErrorStr(hr, error, "Exit:GetCertificateProperty", wszPROPREQUESTREQUESTID); if (VT_DATE != varValue.vt) { hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA); _JumpError(hr, error, "Exit:BAD cert var type"); } dateAfter = varValue.date; VariantClear(&varValue); // cert template name hr = pServer->GetRequestAttribute(CERTTYPE_ATTR_NAME, &bstrCertType); _PrintIfError2(hr, "Exit:GetRequestAttribute", hr); // now prettify hr = ceDateToFileTime(&dateBefore, &ftBefore); _JumpIfError(hr, error, "ceDateToFileTime"); hr = ceDateToFileTime(&dateAfter, &ftAfter); _JumpIfError(hr, error, "ceDateToFileTime"); hr = ExitModSetODBCProperty( lRequestID, m_strCAName, bstrRequester, bstrCertType, &ftBefore, &ftAfter); DBGPRINT((fDebug, "ESQL: Logged request %d to SQL database\n", lRequestID)); error: if (NULL != bstrCertType) { SysFreeString(bstrCertType); } if (NULL != bstrRequester) { SysFreeString(bstrCertType); } VariantClear(&varValue); if (NULL != pServer) { pServer->Release(); } return(hr); } //+-------------------------------------------------------------------------- // CCertExitSQLSample::Notify -- Notify the exit module of an event // // Returns S_OK. //+-------------------------------------------------------------------------- STDMETHODIMP CCertExitSQLSample::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: psz = "crlissued"; break; case EXITEVENT_SHUTDOWN: psz = "shutdown"; break; } DBGPRINT(( fDebug, "Exit:Notify(%hs=%x, ctx=%u) rc=%x\n", psz, ExitEvent, Context, hr)); return(hr); } STDMETHODIMP CCertExitSQLSample::GetDescription( /* [retval][out] */ BSTR *pstrDescription) { HRESULT hr = S_OK; WCHAR sz[MAX_PATH]; assert(wcslen(wsz_SAMPLE_DESCRIPTION) < ARRAYSIZE(sz)); wcscpy(sz, wsz_SAMPLE_DESCRIPTION); *pstrDescription = SysAllocString(sz); if (NULL == *pstrDescription) { hr = E_OUTOFMEMORY; _JumpError(hr, error, "Exit:SysAllocString"); } error: return(hr); } ///////////////////////////////////////////////////////////////////////////// // STDMETHODIMP CCertExitSQLSample::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); } HRESULT CCertExitSQLSample::ExitModSetODBCProperty( IN DWORD dwReqId, IN LPWSTR pszCAName, IN LPWSTR pszRequester, IN LPWSTR pszCertType, IN FILETIME* pftBefore, IN FILETIME* pftAfter) { SQLRETURN retcode; HRESULT hr = S_OK; SQLHSTMT hstmt1 = SQL_NULL_HSTMT; SQLWCHAR* pszStatement = NULL; SYSTEMTIME stTmp; SQL_TIMESTAMP_STRUCT dateValidFrom, dateValidTo; SQLINTEGER cValidFrom=sizeof(dateValidFrom), cValidTo =sizeof(dateValidTo); static WCHAR szSQLInsertStmt[] = L"INSERT INTO OutstandingCertificates (CAName, RequestID, RequesterName, CertType, validFrom, validTo) VALUES (\'%ws\', %d, \'%ws\', \'%ws\', ?, ?)"; // temporarily fix NULL to "" if (NULL == pszCAName) pszCAName = L""; if (NULL == pszRequester) pszRequester = L""; if (NULL == pszCertType) pszCertType = L""; // Allocate a statement handle. retcode = SQLAllocHandle(SQL_HANDLE_STMT, m_hdbc1, &hstmt1); if (!SQL_SUCCEEDED(retcode)) goto error; // Bind the parameter. retcode = SQLBindParameter(hstmt1, 1, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 0, 0, &dateValidFrom, 0, &cValidFrom); if (!SQL_SUCCEEDED(retcode)) goto error; retcode = SQLBindParameter(hstmt1, 2, SQL_PARAM_INPUT, SQL_C_TYPE_TIMESTAMP, SQL_TYPE_TIMESTAMP, 0, 0, &dateValidTo, 0, &cValidTo); if (!SQL_SUCCEEDED(retcode)) goto error; // Place the valid from date in the dsOpenDate structure. if (!FileTimeToSystemTime(pftBefore, &stTmp)) { hr = GetLastError(); hr = HRESULT_FROM_WIN32(hr); _JumpError(hr, error, "FileTimeToSystemTime"); } dateValidFrom.year = stTmp.wYear; dateValidFrom.month = stTmp.wMonth; dateValidFrom.day = stTmp.wDay; dateValidFrom.hour = stTmp.wHour; dateValidFrom.minute = stTmp.wMinute; dateValidFrom.second = stTmp.wSecond; // Place the valid to date in the dsOpenDate structure. if (!FileTimeToSystemTime(pftAfter, &stTmp)) { hr = GetLastError(); hr = HRESULT_FROM_WIN32(hr); _JumpError(hr, error, "FileTimeToSystemTime"); } dateValidTo.year = stTmp.wYear; dateValidTo.month = stTmp.wMonth; dateValidTo.day = stTmp.wDay; dateValidTo.hour = stTmp.wHour; dateValidTo.minute = stTmp.wMinute; dateValidTo.second = stTmp.wSecond; // Build INSERT statement. pszStatement = (SQLWCHAR*) LocalAlloc(LMEM_FIXED, (sizeof(szSQLInsertStmt)+wcslen(pszCAName)+wcslen(pszRequester)+wcslen(pszCertType)+15 +1) *2); if (NULL == pszStatement) { hr = E_OUTOFMEMORY; goto error; } wsprintf(pszStatement, szSQLInsertStmt, pszCAName, dwReqId, pszRequester, pszCertType); //OutputDebugStringW(pszStatement); // Execute an SQL statement directly on the statement handle. // Uses a default result set because no cursor attributes are set. retcode = SQLExecDirect(hstmt1, pszStatement, SQL_NTS); if (!SQL_SUCCEEDED(retcode)) goto error; error: /* Clean up. */ if (NULL != pszStatement) LocalFree(pszStatement); if (SQL_NULL_HSTMT != hstmt1) SQLFreeHandle(SQL_HANDLE_STMT, hstmt1); if (!SQL_SUCCEEDED(retcode)) hr = ERROR_BAD_QUERY_SYNTAX; return (hr); }