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.
587 lines
14 KiB
587 lines
14 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: exit.cpp
|
|
//
|
|
// Contents: CCertExitSQLSample implementation
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "pch.cpp"
|
|
#pragma hdrstop
|
|
|
|
#include <assert.h>
|
|
#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);
|
|
}
|