Leaked source code of windows server 2003
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.
 
 
 
 
 
 

816 lines
19 KiB

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: exit.cpp
//
// Contents: CCertExitSample 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_CERTDENIED | \
EXITEVENT_CERTISSUED | \
EXITEVENT_CERTPENDING | \
EXITEVENT_CERTRETRIEVEPENDING | \
EXITEVENT_CERTREVOKED | \
EXITEVENT_CRLISSUED | \
EXITEVENT_SHUTDOWN)
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);
}
//+--------------------------------------------------------------------------
// CCertExitSample::~CCertExitSample -- destructor
//
// free memory associated with this instance
//+--------------------------------------------------------------------------
CCertExitSample::~CCertExitSample()
{
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);
}
}
//+--------------------------------------------------------------------------
// CCertExitSample::Initialize -- initialize for a CA & return interesting Event Mask
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertExitSample::Initialize(
/* [in] */ BSTR const strConfig,
/* [retval][out] */ LONG __RPC_FAR *pEventMask)
{
HRESULT hr = S_OK;
DWORD cbbuf;
DWORD dwType;
ENUM_CATYPES CAType;
ICertServerExit *pServer = NULL;
VARIANT varValue;
WCHAR sz[MAX_PATH];
VariantInit(&varValue);
assert(wcslen(wsz_SAMPLE_DESCRIPTION) < ARRAYSIZE(sz));
wcsncpy(sz, wsz_SAMPLE_DESCRIPTION, ARRAYSIZE(sz));
sz[ARRAYSIZE(sz) - 1] = L'\0';
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 = ceEXITEVENTS;
DBGPRINT((fDebug, "Exit:Initialize(%ws) ==> %x\n", m_strCAName, *pEventMask));
// get server callbacks
hr = GetServerCallbackInterface(&pServer, 0);
_JumpIfError(hr, error, "Exit:GetServerCallbackInterface");
// get storage location
hr = exitGetProperty(
pServer,
FALSE, // fRequest
wszPROPMODULEREGLOC,
PROPTYPE_STRING,
&varValue);
_JumpIfErrorStr(hr, error, "Exit:exitGetProperty", 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 = exitGetProperty(
pServer,
FALSE, // fRequest
wszPROPCATYPE,
PROPTYPE_LONG,
&varValue);
_JumpIfErrorStr(hr, error, "Exit:exitGetProperty", 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 = exitGetProperty(
pServer,
FALSE, // fRequest
wszPROPCERTCOUNT,
PROPTYPE_LONG,
&varValue);
_JumpIfErrorStr(hr, error, "Exit:exitGetProperty", 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 = S_OK;
error:
VariantClear(&varValue);
if (NULL != pServer)
{
pServer->Release();
}
return(ceHError(hr));
}
//+--------------------------------------------------------------------------
// CCertExitSample::_ExpandEnvironmentVariables -- Expand environment variables
//
//+--------------------------------------------------------------------------
HRESULT
CCertExitSample::_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 = ceHLastError();
_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);
}
HRESULT
exitGetRequestAttribute(
IN ICertServerExit *pServer,
IN WCHAR const *pwszAttributeName,
OUT BSTR *pstrOut)
{
HRESULT hr;
BSTR strName = NULL;
*pstrOut = NULL;
strName = SysAllocString(pwszAttributeName);
if (NULL == strName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Exit:SysAllocString");
}
hr = pServer->GetRequestAttribute(strName, pstrOut);
_JumpIfErrorStr2(
hr,
error,
"Exit:GetRequestAttribute",
pwszAttributeName,
CERTSRV_E_PROPERTY_EMPTY);
error:
if (NULL != strName)
{
SysFreeString(strName);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CCertExitSample::_WriteCertToFile -- write binary certificate to a file
//
//+--------------------------------------------------------------------------
HRESULT
CCertExitSample::_WriteCertToFile(
IN ICertServerExit *pServer,
IN BYTE const *pbCert,
IN DWORD cbCert)
{
HRESULT hr;
BSTR strCertFile = NULL;
DWORD cbWritten;
HANDLE hFile = INVALID_HANDLE_VALUE;
WCHAR wszDir[MAX_PATH];
WCHAR *pwszPath = NULL;
WCHAR wszFile[cwcDWORDSPRINTF+5]; //format "requestid.cer"
VARIANT varRequestID;
VariantInit(&varRequestID);
hr = exitGetRequestAttribute(pServer, wszPROPEXITCERTFILE, &strCertFile);
if (S_OK != hr)
{
DBGPRINT((
fDebug,
"Exit:exitGetRequestAttribute(%ws): %x%hs\n",
wszPROPEXITCERTFILE,
hr,
CERTSRV_E_PROPERTY_EMPTY == hr? " EMPTY VALUE" : ""));
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = S_OK;
}
goto error;
}
// build file name as "requestid.cer"
hr = exitGetProperty(
pServer,
TRUE, // fRequest,
wszPROPREQUESTREQUESTID,
PROPTYPE_LONG,
&varRequestID);
_JumpIfErrorStr(hr, error, "Exit:exitGetProperty", wszPROPREQUESTREQUESTID);
wsprintf(wszFile, L"%d.cer", V_I4(&varRequestID));
hr = _ExpandEnvironmentVariables(
L"%SystemRoot%\\System32\\" wszCERTENROLLSHAREPATH L"\\",
wszDir,
ARRAYSIZE(wszDir));
_JumpIfError(hr, error, "_ExpandEnvironmentVariables");
hr = ceBuildPathAndExt(wszDir, wszFile, NULL, &pwszPath);
_JumpIfError(hr, error, "ceBuildPathAndExt");
// open file & write binary cert out.
hFile = CreateFile(
pwszPath,
GENERIC_WRITE,
0, // dwShareMode
NULL, // lpSecurityAttributes
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL); // hTemplateFile
if (INVALID_HANDLE_VALUE == hFile)
{
hr = ceHLastError();
_JumpErrorStr(hr, error, "Exit:CreateFile", pwszPath);
}
if (!WriteFile(hFile, pbCert, cbCert, &cbWritten, NULL))
{
hr = ceHLastError();
_JumpErrorStr(hr, error, "Exit:WriteFile", pwszPath);
}
if (cbWritten != cbCert)
{
hr = STG_E_WRITEFAULT;
DBGPRINT((
fDebug,
"Exit:WriteFile(%ws): attempted %x, actual %x bytes: %x\n",
pwszPath,
cbCert,
cbWritten,
hr));
goto error;
}
error:
if (INVALID_HANDLE_VALUE != hFile)
{
CloseHandle(hFile);
}
if (NULL != pwszPath)
{
LocalFree(pwszPath);
}
if (NULL != strCertFile)
{
SysFreeString(strCertFile);
}
return(hr);
}
//+--------------------------------------------------------------------------
// CCertExitSample::_NotifyNewCert -- Notify the exit module of a new certificate
//
//+--------------------------------------------------------------------------
HRESULT
CCertExitSample::_NotifyNewCert(
/* [in] */ LONG Context)
{
HRESULT hr;
VARIANT varCert;
ICertServerExit *pServer = NULL;
VariantInit(&varCert);
// only call write fxns if server policy allows
if (m_dwExitPublishFlags & EXITPUB_FILE)
{
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 = exitGetProperty(
pServer,
FALSE, // fRequest,
wszPROPRAWCERTIFICATE,
PROPTYPE_BINARY,
&varCert);
_JumpIfErrorStr(
hr,
error,
"Exit:exitGetProperty",
wszPROPRAWCERTIFICATE);
if (VT_BSTR != varCert.vt)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "Exit:BAD cert var type");
}
hr = _WriteCertToFile(
pServer,
(BYTE const *) varCert.bstrVal,
SysStringByteLen(varCert.bstrVal));
_JumpIfError(hr, error, "_WriteCertToFile");
}
hr = S_OK;
error:
VariantClear(&varCert);
if (NULL != pServer)
{
pServer->Release();
}
return(hr);
}
//+--------------------------------------------------------------------------
// CCertExitSample::_NotifyCRLIssued -- Notify the exit module of a new certificate
//
//+--------------------------------------------------------------------------
HRESULT
CCertExitSample::_NotifyCRLIssued(
/* [in] */ LONG Context)
{
HRESULT hr;
ICertServerExit *pServer = NULL;
DWORD i;
VARIANT varBaseCRL;
VARIANT varDeltaCRL;
BOOL fDeltaCRLsDisabled;
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");
hr = exitGetProperty(
pServer,
FALSE, // fRequest,
wszPROPDELTACRLSDISABLED,
PROPTYPE_LONG,
&varBaseCRL);
_JumpIfErrorStr(
hr,
error,
"Exit:exitGetProperty",
wszPROPDELTACRLSDISABLED);
fDeltaCRLsDisabled = varBaseCRL.lVal;
// How many CRLs are there?
// Loop for each CRL
for (i = 0; i < m_cCACert; i++)
{
// array size for wsprintf("%s.%u")
#define MAX_CRL_PROP \
(max( \
max(ARRAYSIZE(wszPROPCRLSTATE), ARRAYSIZE(wszPROPRAWCRL)), \
ARRAYSIZE(wszPROPRAWDELTACRL)) + \
1 + cwcDWORDSPRINTF)
WCHAR wszCRLPROP[MAX_CRL_PROP];
// Verify the CRL State says we should update this CRL
wsprintf(wszCRLPROP, wszPROPCRLSTATE L".%u", i);
hr = exitGetProperty(
pServer,
FALSE, // fRequest,
wszCRLPROP,
PROPTYPE_LONG,
&varBaseCRL);
_JumpIfErrorStr(hr, error, "Exit:exitGetProperty", wszCRLPROP);
if (CA_DISP_VALID != varBaseCRL.lVal)
{
continue;
}
// Grab the raw base CRL
wsprintf(wszCRLPROP, wszPROPRAWCRL L".%u", i);
hr = exitGetProperty(
pServer,
FALSE, // fRequest,
wszCRLPROP,
PROPTYPE_BINARY,
&varBaseCRL);
_JumpIfErrorStr(hr, error, "Exit:exitGetProperty", wszCRLPROP);
// Grab the raw delta CRL (which may not exist)
wsprintf(wszCRLPROP, wszPROPRAWDELTACRL L".%u", i);
hr = exitGetProperty(
pServer,
FALSE, // fRequest,
wszCRLPROP,
PROPTYPE_BINARY,
&varDeltaCRL);
_PrintIfErrorStr2(
hr,
"Exit:exitGetProperty",
wszCRLPROP,
fDeltaCRLsDisabled?
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) : S_OK);
if (S_OK != hr && !fDeltaCRLsDisabled)
{
goto error;
}
// Publish the CRL(s) ...
}
hr = S_OK;
error:
if (NULL != pServer)
{
pServer->Release();
}
VariantClear(&varBaseCRL);
VariantClear(&varDeltaCRL);
return(hr);
}
//+--------------------------------------------------------------------------
// CCertExitSample::Notify -- Notify the exit module of an event
//
// Returns S_OK.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertExitSample::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((
fDebug,
"Exit:Notify(%hs=%x, ctx=%x) rc=%x\n",
psz,
ExitEvent,
Context,
hr));
return(hr);
}
STDMETHODIMP
CCertExitSample::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);
}
//+--------------------------------------------------------------------------
// CCertExitSample::GetManageModule
//
// Returns S_OK on success.
//+--------------------------------------------------------------------------
STDMETHODIMP
CCertExitSample::GetManageModule(
/* [out, retval] */ ICertManageModule **ppManageModule)
{
HRESULT hr;
*ppManageModule = NULL;
hr = CoCreateInstance(
CLSID_CCertManageExitModuleSample,
NULL, // pUnkOuter
CLSCTX_INPROC_SERVER,
IID_ICertManageModule,
(VOID **) ppManageModule);
_JumpIfError(hr, error, "CoCreateInstance");
error:
return(hr);
}
/////////////////////////////////////////////////////////////////////////////
//
STDMETHODIMP
CCertExitSample::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
exitGetProperty(
IN ICertServerExit *pServer,
IN BOOL fRequest,
IN WCHAR const *pwszPropertyName,
IN DWORD PropType,
OUT VARIANT *pvarOut)
{
HRESULT hr;
BSTR strName = NULL;
VariantInit(pvarOut);
strName = SysAllocString(pwszPropertyName);
if (NULL == strName)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Exit:SysAllocString");
}
if (fRequest)
{
hr = pServer->GetRequestProperty(strName, PropType, pvarOut);
_JumpIfErrorStr2(
hr,
error,
"Exit:GetRequestProperty",
pwszPropertyName,
CERTSRV_E_PROPERTY_EMPTY);
}
else
{
hr = pServer->GetCertificateProperty(strName, PropType, pvarOut);
_JumpIfErrorStr2(
hr,
error,
"Exit:GetCertificateProperty",
pwszPropertyName,
CERTSRV_E_PROPERTY_EMPTY);
}
error:
if (NULL != strName)
{
SysFreeString(strName);
}
return(hr);
}