windows-nt/Source/XPSP1/NT/ds/security/services/ca/certsrv/request.cpp

2036 lines
50 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: request.cpp
//
// Contents: Implementation of DCOM object for RPC services
//
// History: July-97 xtan created
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <stdio.h>
#include <accctrl.h>
#include "cscom.h"
#include "csprop.h"
#include "certsrvd.h"
#include "request.h"
#include "certacl.h"
#include "tmpllist.h"
#define __dwFILE__ __dwFILE_CERTSRV_REQUEST_CPP__
extern HINSTANCE g_hInstApp;
extern const GUID *g_guidAdmin[1];
extern const GUID *g_guidsReadAdminOfficer[3];
// Global variables
long g_cRequestComponents = 0; // Count of active components
long g_cRequestServerLocks = 0; // Count of locks
DWORD g_dwRequestRegister = 0;
IClassFactory* g_pIRequestFactory = NULL;
// Sequence# incremented every time the CA template list is changed.
// Policy module detects any changes to this number and refreshes its
// template data from DS.
long g_cTemplateUpdateSequenceNum = 0;
#ifdef DBG_CERTSRV_DEBUG_PRINT
DWORD s_ssRequest = DBG_SS_CERTSRVI;
#endif
using namespace CertSrv;
#ifndef CERTSRV_E_UNKNOWN_CERT_TYPE
// begin implementation of component functions
// Request component
// begin implementing cert request services
//
// MessageId: CERTSRV_E_UNKNOWN_CERT_TYPE
//
// MessageText:
//
// One or more certificate templates to be enabled on this certification authority could not be found.
//
#define CERTSRV_E_UNKNOWN_CERT_TYPE _HRESULT_TYPEDEF_(0x80094010L)
//
// MessageId: CERTSRV_E_ENROLL_DENIED
//
// MessageText:
//
// The permissions on this certification authority do not allow current user to enroll for certificates.
//
#define CERTSRV_E_ENROLL_DENIED _HRESULT_TYPEDEF_(0x80094011L)
#endif // CERTSRV_E_UNKNOWN_CERT_TYPE
HRESULT RequestAccessCheck(
OPTIONAL OUT BOOL *pfInRequesterGroup = NULL,
OPTIONAL OUT HANDLE *phToken = NULL)
{
HRESULT hr = S_OK;
CAuditEvent audit(0, g_dwAuditFilter);
BOOL fInRequesterGroup = FALSE;
hr = audit.AccessCheck(
CA_ACCESS_ENROLL,
audit.m_gcNoAuditSuccess |
audit.m_gcNoAuditFailure,
NULL,
phToken);
if(S_OK==hr)
{
fInRequesterGroup = TRUE;
}
if(pfInRequesterGroup)
*pfInRequesterGroup = fInRequesterGroup;
if(E_ACCESSDENIED==hr)
{
// When this flag is set, ICertReq calls should immediately return
// if access is denied. If not set, we ignore access denied error
// but pass down the result to the policy module through fInRequesterGroup
if(g_fLockICertRequest)
{
hr = CERTSRV_E_ENROLL_DENIED;
}
else
{
hr = S_OK;
}
}
_JumpIfError(hr, error, "CAuditEvent::AccessCheck");
error:
return hr;
}
VOID
ReleaseResult(
IN OUT CERTSRV_RESULT_CONTEXT *pResult)
{
if (NULL != pResult->pbSenderNonce)
{
LocalFree(pResult->pbSenderNonce);
}
if (NULL != pResult->pbKeyHashIn)
{
LocalFree(pResult->pbKeyHashIn);
}
if (NULL != pResult->pbKeyHashOut)
{
LocalFree(pResult->pbKeyHashOut);
}
}
STDMETHODIMP
CCertRequestD::Request(
/* [in] */ DWORD dwFlags,
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [ref][out][in] */ DWORD __RPC_FAR *pdwRequestId,
/* [out] */ DWORD __RPC_FAR *pdwDisposition,
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAttributes,
/* [ref][in] */ CERTTRANSBLOB const __RPC_FAR *pctbRequest,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbCertChain,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbEncodedCert,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbDispositionMessage)
{
HRESULT hr;
WCHAR const *pwszSerialNumber = NULL;
CERTSRV_RESULT_CONTEXT Result;
ZeroMemory(&Result, sizeof(Result));
if (NULL != pctbRequest && NULL == pctbRequest->pb)
{
// RetrievePending by SerialNumber in pwszAttributes
pwszSerialNumber = pwszAttributes;
pwszAttributes = NULL;
}
Result.pdwRequestId = pdwRequestId;
Result.pdwDisposition = pdwDisposition;
Result.pctbDispositionMessage = pctbDispositionMessage;
Result.pctbCert = pctbEncodedCert;
Result.pctbCertChain = pctbCertChain;
hr = _Request(
pwszAuthority,
dwFlags,
pwszSerialNumber,
*pdwRequestId,
pwszAttributes,
pctbRequest,
&Result);
_JumpIfError(hr, error, "Request");
error:
ReleaseResult(&Result);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertRequestD::Request2(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ DWORD dwFlags,
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszSerialNumber,
/* [ref][out][in] */ DWORD __RPC_FAR *pdwRequestId,
/* [out] */ DWORD __RPC_FAR *pdwDisposition,
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAttributes,
/* [ref][in] */ const CERTTRANSBLOB __RPC_FAR *pctbRequest,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbFullResponse,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbEncodedCert,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbDispositionMessage)
{
HRESULT hr;
CERTSRV_RESULT_CONTEXT Result;
ZeroMemory(&Result, sizeof(Result));
Result.pdwRequestId = pdwRequestId;
Result.pdwDisposition = pdwDisposition;
Result.pctbDispositionMessage = pctbDispositionMessage;
Result.pctbCert = pctbEncodedCert;
if (CR_IN_FULLRESPONSE & dwFlags)
{
Result.pctbFullResponse = pctbFullResponse;
}
else
{
Result.pctbCertChain = pctbFullResponse;
}
hr = _Request(
pwszAuthority,
dwFlags,
pwszSerialNumber,
*pdwRequestId,
pwszAttributes,
pctbRequest,
&Result);
_JumpIfError(hr, error, "Request2");
error:
ReleaseResult(&Result);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
VOID
requestRegisterMemFreeBlob(
OPTIONAL CERTTRANSBLOB const *pctb)
{
if (NULL != pctb && NULL != pctb->pb)
{
myRegisterMemFree(pctb->pb, CSM_MIDLUSERALLOC);
}
}
HRESULT
CCertRequestD::_Request(
IN WCHAR const *pwszAuthority,
IN DWORD dwFlags,
OPTIONAL IN WCHAR const *pwszSerialNumber,
IN DWORD dwRequestId,
OPTIONAL IN WCHAR const *pwszAttributes,
OPTIONAL IN CERTTRANSBLOB const *pctbRequest,
OUT CERTSRV_RESULT_CONTEXT *pResult)
{
HRESULT hr;
DWORD OpRequest;
WCHAR *pwszUserName = NULL;
DWORD dwComContextIndex = MAXDWORD;
CERTSRV_COM_CONTEXT ComContext;
DWORD State = 0;
DBGPRINT((
s_ssRequest,
"CCertRequestD::Request2(tid=%d)\n",
GetCurrentThreadId()));
ZeroMemory(&ComContext, sizeof(ComContext));
//ComContext.pwszUserDN = NULL;
//ComContext.hAccessToken = NULL;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
hr = RegisterComContext(&ComContext, &dwComContextIndex);
_JumpIfError(hr, error, "RegsiterComContext");
__try
{
hr = RequestAccessCheck(
&ComContext.fInRequestGroup,
&ComContext.hAccessToken);
_LeaveIfError(hr, "RequestAccessCheck");
// Set up default output parameters:
*pResult->pdwRequestId = 0;
*pResult->pdwDisposition = CR_DISP_ERROR;
OpRequest = CR_IN_RETRIEVE;
if (NULL != pctbRequest->pb)
{
OpRequest = CR_IN_NEW;
}
hr = GetClientUserName(
NULL,
&pwszUserName,
CR_IN_NEW == OpRequest && IsEnterpriseCA(g_CAType)?
&ComContext.pwszUserDN : NULL);
_LeaveIfError(hr, "GetClientUserName");
hr = CoreProcessRequest(
OpRequest | (dwFlags & ~CR_IN_COREMASK),
pwszUserName,
pctbRequest->cb, // cbRequest
pctbRequest->pb, // pbRequest
pwszAttributes,
pwszSerialNumber,
dwComContextIndex,
dwRequestId,
pResult); // Allocates returned memory
if (S_OK != hr)
{
hr = myHError(hr);
_LeaveError(hr, "CoreProcessRequest");
}
requestRegisterMemFreeBlob(pResult->pctbDispositionMessage);
requestRegisterMemFreeBlob(pResult->pctbCert);
requestRegisterMemFreeBlob(pResult->pctbCertChain);
requestRegisterMemFreeBlob(pResult->pctbFullResponse);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
// CloseHandle can throw an exception
if (NULL != ComContext.hAccessToken)
{
__try
{
CloseHandle(ComContext.hAccessToken);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
}
if (NULL != pwszUserName)
{
LocalFree(pwszUserName);
}
if (MAXDWORD != dwComContextIndex)
{
if (NULL != ComContext.pwszUserDN)
{
LocalFree(ComContext.pwszUserDN);
}
UnregisterComContext(&ComContext, dwComContextIndex);
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
#define MAX_VERSION_RESOURCE_SIZE 64
HRESULT
GetVersionString(
IN DWORD type,
OUT WCHAR *pwszVersion)
{
HRESULT hr;
typedef struct _MY_RESOURCE_DATA
{
USHORT TotalSize;
USHORT DataSize;
USHORT Type;
WCHAR Name[16]; // L"VS_VERSION_INFO" + unicode nul
VS_FIXEDFILEINFO FixedFileInfo;
} MY_RESOURCE_DATA;
MY_RESOURCE_DATA *pResource;
HRSRC hrsc;
HGLOBAL hg;
// FindResource: don't need to free hrsc
hrsc = FindResource(g_hInstApp, MAKEINTRESOURCE(1), RT_VERSION);
if (NULL == hrsc)
{
hr = myHLastError();
_JumpError(hr, error, "FindResource");
}
// LoadResource: don't need to free HGLOBAL
hg = LoadResource(g_hInstApp, hrsc);
if (NULL == hg)
{
hr = myHLastError();
_JumpError(hr, error, "LoadResource");
}
// LockResource: don't need to free pResource
pResource = (MY_RESOURCE_DATA *) LockResource(hg);
if (NULL == pResource)
{
hr = myHLastError();
if (S_OK == hr) // LockResource isn't doc'd to use SetLastError
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
}
_JumpError(hr, error, "LockResource");
}
if (0 != lstrcmpi(pResource->Name, L"VS_VERSION_INFO"))
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
goto error;
}
if (CR_PROP_FILEVERSION == type)
{
wsprintf(
pwszVersion,
L"%d.%d:%d.%d",
HIWORD(pResource->FixedFileInfo.dwFileVersionMS),
LOWORD(pResource->FixedFileInfo.dwFileVersionMS),
HIWORD(pResource->FixedFileInfo.dwFileVersionLS),
LOWORD(pResource->FixedFileInfo.dwFileVersionLS));
}
else
{
wsprintf(
pwszVersion,
L"%d.%d:%d.%d",
HIWORD(pResource->FixedFileInfo.dwProductVersionMS),
LOWORD(pResource->FixedFileInfo.dwProductVersionMS),
HIWORD(pResource->FixedFileInfo.dwProductVersionLS),
LOWORD(pResource->FixedFileInfo.dwProductVersionLS));
}
hr = S_OK;
error:
return(hr);
}
// for ICertRequest2::GetCAProperty & ICertAdmin2::GetCAProperty
LONG g_CAPropIdMax = 0;
CAPROP g_aCAProp[] = {
{ CR_PROP_FILEVERSION, PROPTYPE_STRING, },
{ CR_PROP_PRODUCTVERSION, PROPTYPE_STRING, },
{ CR_PROP_EXITCOUNT, PROPTYPE_LONG, },
{ CR_PROP_EXITDESCRIPTION, PROPTYPE_STRING | PROPFLAGS_INDEXED, },
{ CR_PROP_POLICYDESCRIPTION, PROPTYPE_STRING, },
{ CR_PROP_CANAME, PROPTYPE_STRING, },
{ CR_PROP_SANITIZEDCANAME, PROPTYPE_STRING, },
{ CR_PROP_SHAREDFOLDER, PROPTYPE_STRING, },
{ CR_PROP_PARENTCA, PROPTYPE_STRING, FALSE, },
{ CR_PROP_CATYPE, PROPTYPE_LONG, },
{ CR_PROP_CASIGCERTCOUNT, PROPTYPE_LONG, },
{ CR_PROP_CASIGCERT, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_CASIGCERTCHAIN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_CAXCHGCERTCOUNT, PROPTYPE_LONG, },
{ CR_PROP_CAXCHGCERT, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_CAXCHGCERTCHAIN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_BASECRL, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_DELTACRL, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_CACERTSTATE, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
{ CR_PROP_CRLSTATE, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
{ CR_PROP_CAPROPIDMAX, PROPTYPE_LONG, },
{ CR_PROP_DNSNAME, PROPTYPE_STRING, },
// { CR_PROP_ROLESEPARATIONENABLED, PROPTYPE_LONG, },
{ CR_PROP_KRACERTUSEDCOUNT, PROPTYPE_LONG, },
{ CR_PROP_KRACERTCOUNT, PROPTYPE_LONG, },
{ CR_PROP_KRACERT, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_KRACERTSTATE, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
{ CR_PROP_ADVANCEDSERVER,PROPTYPE_LONG, },
{ CR_PROP_TEMPLATES, PROPTYPE_STRING, },
{ CR_PROP_BASECRLPUBLISHSTATUS, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
{ CR_PROP_DELTACRLPUBLISHSTATUS, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
{ CR_PROP_CASIGCERTCRLCHAIN, PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_CAXCHGCERTCRLCHAIN,PROPTYPE_BINARY | PROPFLAGS_INDEXED, },
{ CR_PROP_CACERTSTATUSCODE, PROPTYPE_LONG | PROPFLAGS_INDEXED, },
};
// Map old ICertRequest::GetCACertificate calls to ICertRequest2::GetCAProperty
typedef struct _GETCERTMAP {
DWORD dwGetCert;
LONG lPropId;
LONG lPropType;
} GETCERTMAP;
GETCERTMAP g_aCAPropMap[] = {
{ GETCERT_FILEVERSION, CR_PROP_FILEVERSION, PROPTYPE_STRING, },
{ GETCERT_PRODUCTVERSION, CR_PROP_PRODUCTVERSION, PROPTYPE_STRING, },
{ GETCERT_EXITVERSIONBYINDEX, CR_PROP_EXITDESCRIPTION, PROPTYPE_STRING, },
{ GETCERT_POLICYVERSION, CR_PROP_POLICYDESCRIPTION, PROPTYPE_STRING, },
{ GETCERT_CANAME, CR_PROP_CANAME, PROPTYPE_STRING, },
{ GETCERT_SANITIZEDCANAME, CR_PROP_SANITIZEDCANAME, PROPTYPE_STRING, },
{ GETCERT_SHAREDFOLDER, CR_PROP_SHAREDFOLDER, PROPTYPE_STRING, },
{ GETCERT_PARENTCONFIG, CR_PROP_PARENTCA, PROPTYPE_STRING, },
{ GETCERT_CAINFO, CR_PROP_CATYPE, PROPTYPE_LONG, },
{ GETCERT_CACERTBYINDEX, CR_PROP_CASIGCERT, PROPTYPE_BINARY, },
{ GETCERT_CRLBYINDEX, CR_PROP_BASECRL, PROPTYPE_BINARY, },
{ GETCERT_CACERTSTATEBYINDEX, CR_PROP_CACERTSTATE, PROPTYPE_LONG, },
{ GETCERT_CRLSTATEBYINDEX, CR_PROP_CRLSTATE, PROPTYPE_LONG, },
};
// Handled via code hacks:
//{ GETCERT_CASIGCERT, CR_PROP_CASIGCERTCRLCHAIN, PROPTYPE_BINARY, },
//{ GETCERT_CASIGCERT, CR_PROP_CASIGCERTCHAIN, PROPTYPE_BINARY, },
//{ GETCERT_CASIGCERT, CR_PROP_CASIGCERT, PROPTYPE_BINARY, },
//{ GETCERT_CAXCHGCERT, CR_PROP_CAXCHGCERT, PROPTYPE_BINARY, },
//{ GETCERT_CAXCHGCERT, CR_PROP_CAXCHGCERTCRLCHAIN,PROPTYPE_BINARY, },
//{ GETCERT_CAXCHGCERT, CR_PROP_CAXCHGCERTCHAIN, PROPTYPE_BINARY, },
//{ GETCERT_CURRENTCRL, CR_PROP_BASECRL, PROPTYPE_BINARY, },
//{ GETCERT_CATYPE, CR_PROP_CATYPE, PROPTYPE_LONG, },
HRESULT
RequestInitCAPropertyInfo(VOID)
{
HRESULT hr;
CAPROP *pcap;
g_CAPropIdMax = 0;
for (pcap = g_aCAProp; pcap < &g_aCAProp[ARRAYSIZE(g_aCAProp)]; pcap++)
{
hr = myCAPropGetDisplayName(pcap->lPropId, &pcap->pwszDisplayName);
if (S_OK != hr)
{
DBGPRINT((
DBG_SS_CERTSRVI,
"myCAPropGetDisplayName(%u)\n",
pcap->lPropId));
_PrintError(hr, "myCAPropGetDisplayName");
}
if (g_CAPropIdMax < pcap->lPropId)
{
g_CAPropIdMax = pcap->lPropId;
}
}
return(S_OK);
}
HRESULT
RequestGetCAPropertyInfo(
OUT LONG *pcProperty,
OUT CERTTRANSBLOB *pctbPropInfo)
{
HRESULT hr;
LONG i;
DWORD cb;
DWORD cbT;
CAPROP *rgcap = NULL;
CAPROP *pcap;
CAPROP *pcapEnd;
pctbPropInfo->pb = NULL;
pctbPropInfo->cb = 0;
__try
{
cb = sizeof(g_aCAProp);
for (i = 0; i < ARRAYSIZE(g_aCAProp); i++)
{
if (NULL != g_aCAProp[i].pwszDisplayName)
{
cbT = (wcslen(g_aCAProp[i].pwszDisplayName) + 1) * sizeof(WCHAR);
cb += DWORDROUND(cbT);
}
}
rgcap = (CAPROP *) MIDL_user_allocate(cb);
if (NULL == rgcap)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "MIDL_user_allocate rgcap");
}
CopyMemory(rgcap, g_aCAProp, sizeof(g_aCAProp));
cb = sizeof(g_aCAProp);
pcapEnd = &rgcap[ARRAYSIZE(g_aCAProp)];
for (pcap = rgcap; pcap < pcapEnd; pcap++)
{
DBGPRINT((
DBG_SS_CERTSRVI,
"RequestGetCAPropertyInfo: ielt=%d idx=%x t=%x \"%ws\"\n",
pcap - rgcap,
pcap->lPropId,
pcap->lPropFlags,
pcap->pwszDisplayName));
if (NULL != pcap->pwszDisplayName)
{
cbT = (wcslen(pcap->pwszDisplayName) + 1) * sizeof(WCHAR);
CopyMemory(Add2Ptr(rgcap, cb), pcap->pwszDisplayName, cbT);
pcap->pwszDisplayName = (WCHAR *) (ULONG_PTR) cb;
cb += DWORDROUND(cbT);
}
}
pctbPropInfo->cb = cb;
pctbPropInfo->pb = (BYTE *) rgcap;
rgcap = NULL;
*pcProperty = ARRAYSIZE(g_aCAProp);
myRegisterMemFree(pctbPropInfo->pb, CSM_MIDLUSERALLOC);
hr = S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
//error:
if (NULL != rgcap)
{
MIDL_user_free(rgcap);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
ValidatePropertyParameters(
LONG PropId,
LONG PropIndex,
LONG PropType)
{
HRESULT hr;
CAPROP const * pcap;
hr = E_INVALIDARG;
for (pcap = g_aCAProp; ; pcap++)
{
if (pcap >= &g_aCAProp[ARRAYSIZE(g_aCAProp)])
{
_JumpError(hr, error, "invalid propid");
}
if (PropId == pcap->lPropId)
{
if ((PropType != (PROPTYPE_MASK & pcap->lPropFlags)) ||
(0 == (PROPFLAGS_INDEXED & pcap->lPropFlags) &&
0 != PropIndex))
{
_JumpError(hr, error, "invalid type/index");
}
break;
}
}
hr = S_OK;
error:
DBGPRINT((
S_OK != hr? DBG_SS_ERROR : DBG_SS_CERTSRVI,
"ValidatePropertyParameters(PropId=%x, PropIndex=%x, PropType=%x) -> %x\n",
PropId,
PropIndex,
PropType,
hr));
return(hr);
}
// Returns a string containing the list of templates supported
// by this CA, one pair of name and string OID for each template,
// separated by new lines:
//
// "name1\nOID1\nname2\OID2...\nnameN\nOIDN\0"
//
// If the template doesn't have an OID (Win2k domain) there will
// be an empty string in its place
HRESULT
GetCATemplates(
BYTE*& rpb,
DWORD& rcb)
{
HRESULT hr = S_OK;
HCAINFO hCAInfo = NULL;
HCERTTYPE hCrtCertType = NULL;
HCERTTYPE hPrevCertType = NULL;
LPWSTR* pwszCertTypeCN = NULL;
LPWSTR* pwszCertTypeOID = NULL;
CTemplateList CATemplateList;
rpb = NULL;
rcb = 0;
hr = CAFindByName(
g_wszSanitizedName,
NULL,
CA_FIND_LOCAL_SYSTEM,
&hCAInfo);
_JumpIfError(hr, error, "CAFindByName");
hr = CAEnumCertTypesForCA(
hCAInfo,
CT_ENUM_MACHINE_TYPES |
CT_ENUM_USER_TYPES |
CT_FIND_LOCAL_SYSTEM |
CT_FLAG_NO_CACHE_LOOKUP,
&hCrtCertType);
_JumpIfError(hr, error, "CAEnumCertTypesForCA");
while(hCrtCertType)
{
hr = CAGetCertTypeProperty(
hCrtCertType,
CERTTYPE_PROP_CN,
&pwszCertTypeCN);
_JumpIfError(hr, error, "CAGetCertTypeProperty CERTTYPE_PROP_CN");
hr = CAGetCertTypeProperty(
hCrtCertType,
CERTTYPE_PROP_OID,
&pwszCertTypeOID);
_JumpIfError(hr, error, "CAGetCertTypeProperty CERTTYPE_PROP_OID");
hr = CATemplateList.AddTemplateInfo(
pwszCertTypeCN?*pwszCertTypeCN:NULL,
pwszCertTypeOID?*pwszCertTypeOID:NULL);
_JumpIfError(hr, error, "CTemplateList::AddTemplate");
if(pwszCertTypeCN)
{
CAFreeCertTypeProperty(hCrtCertType, pwszCertTypeCN);
pwszCertTypeCN = NULL;
}
if(pwszCertTypeOID)
{
CAFreeCertTypeProperty(hCrtCertType, pwszCertTypeOID);
pwszCertTypeOID = NULL;
}
hPrevCertType = hCrtCertType;
hr = CAEnumNextCertType(hCrtCertType, &hCrtCertType);
_JumpIfError(hr, error, "CAEnumNextCertType");
CACloseCertType(hPrevCertType);
}
hCrtCertType = NULL;
hr = CATemplateList.Marshal(rpb, rcb);
_JumpIfError(hr, error, "CTemplateList::Marshal");
error:
if(pwszCertTypeCN)
{
CSASSERT(hCrtCertType);
CAFreeCertTypeProperty(hCrtCertType, pwszCertTypeCN);
}
if(pwszCertTypeOID)
{
CSASSERT(hCrtCertType);
CAFreeCertTypeProperty(hCrtCertType, pwszCertTypeOID);
}
if(hCrtCertType)
{
CACloseCertType(hCrtCertType);
}
if(hCAInfo)
{
CACloseCA(hCAInfo);
}
return hr;
}
HRESULT
SetCATemplates(
const BYTE* pb,
DWORD cb)
{
HRESULT hr = S_OK;
HCAINFO hCAInfo = NULL;
CTemplateList CATemplateList;
CTemplateListEnum CATemplateListEnum(CATemplateList);
CTemplateInfo *pTemplateInfo;
DWORD cTempl;
DWORD nTemplates;
LPCWSTR *ppTemplateList = NULL;
HCERTTYPE hCertType = NULL;
bool fRefreshTemplateCache = true;
hr = CATemplateList.Unmarshal(pb, cb);
_JumpIfError(hr, error, "CTemplateList::Unmarshal");
hr = CAFindByName(
g_wszSanitizedName,
NULL,
CA_FIND_LOCAL_SYSTEM,
&hCAInfo);
_JumpIfError(hr, error, "CAFindByName");
nTemplates = CATemplateList.GetCount();
ppTemplateList = (LPCWSTR*)LocalAlloc(
LMEM_FIXED|LMEM_ZEROINIT,
sizeof(LPWSTR)* (nTemplates+1) );
_JumpIfAllocFailed(ppTemplateList, error);
CATemplateListEnum.Reset();
for(pTemplateInfo=CATemplateListEnum.Next(), cTempl=0;
pTemplateInfo;
pTemplateInfo=CATemplateListEnum.Next(), cTempl++)
{
ppTemplateList[cTempl] = pTemplateInfo->GetName();
// check if this is a valid template
hr = CAFindCertTypeByName(
pTemplateInfo->GetName(),
NULL,
CT_FIND_LOCAL_SYSTEM |
CT_ENUM_MACHINE_TYPES |
CT_ENUM_USER_TYPES |
(fRefreshTemplateCache?CT_FLAG_NO_CACHE_LOOKUP:0),
&hCertType);
fRefreshTemplateCache = false;
if(HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == hr)
{
// try with the OID
hr = CAFindCertTypeByName(
pTemplateInfo->GetOID(),
NULL,
CT_FIND_LOCAL_SYSTEM |
CT_ENUM_MACHINE_TYPES |
CT_ENUM_USER_TYPES |
CT_FIND_BY_OID,
&hCertType);
if(HRESULT_FROM_WIN32(ERROR_NOT_FOUND) == hr)
{
hr = CERTSRV_E_UNKNOWN_CERT_TYPE;
_JumpErrorStr(hr, error, "CAFindCertTypeByOID",
pTemplateInfo->GetOID());
}
_JumpIfErrorStr(hr, error, "CAFindCertTypeByName", pTemplateInfo->GetOID());
}
_JumpIfErrorStr(hr, error, "CAFindCertTypeByName", pTemplateInfo->GetName());
CACloseCertType(hCertType);
hCertType = NULL;
hr = S_OK;
}
ppTemplateList[nTemplates] = NULL;
hr = CASetCAProperty(hCAInfo, CA_PROP_CERT_TYPES,
const_cast<LPWSTR*>(ppTemplateList));
_JumpIfError(hr, error, "CASetCAProperty(CA_PROP_CERT_TYPES)");
hr = CAUpdateCA(hCAInfo);
_JumpIfError(hr, error, "CAUpdateCA");
// Increment sequence number so that policy module can detect
// there was a template change
InterlockedIncrement(&g_cTemplateUpdateSequenceNum);
error:
LOCAL_FREE(ppTemplateList);
if(hCAInfo)
{
CACloseCA(hCAInfo);
}
return hr;
}
STDMETHODIMP
RequestGetCAPropertySub(
IN LONG PropId, // CR_PROP_*
IN LONG PropIndex,
IN LONG PropType, // PROPTYPE_*
OUT CERTTRANSBLOB *pctbOut)
{
HRESULT hr = S_OK;
CAPROP const *pcap;
BYTE *pbReturn;
BYTE *pbAlloc = NULL;
WCHAR wszVersion[MAX_VERSION_RESOURCE_SIZE];
BYTE *pb = NULL;
WCHAR const *pwsz = NULL;
WCHAR *pwszSharedFolder = NULL;
CAINFO CAInfo;
DWORD iCertSig;
CRL_CONTEXT const *pCRL = NULL;
WCHAR *pwszUserName = NULL;
HCERTSTORE hKRAStore = NULL;
CERT_CONTEXT const *pCertContext = NULL;
HRESULT hrCAStatusCode;
switch (PropId)
{
case CR_PROP_FILEVERSION:
case CR_PROP_PRODUCTVERSION:
hr = GetVersionString(PropId, wszVersion);
_JumpIfError(hr, error, "GetVersionString");
pwsz = wszVersion;
break;
case CR_PROP_EXITDESCRIPTION:
case CR_PROP_POLICYDESCRIPTION:
pwsz = CR_PROP_EXITDESCRIPTION == PropId?
ExitGetDescription(PropIndex) :
g_strPolicyDescription;
if (NULL == pwsz)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "No description");
}
break;
case CR_PROP_CANAME:
pwsz = g_wszCommonName;
break;
case CR_PROP_SANITIZEDCANAME:
pwsz = g_wszSanitizedName;
break;
case CR_PROP_SHAREDFOLDER:
hr = myGetCertRegStrValue(
NULL,
NULL,
NULL,
wszREGDIRECTORY,
&pwszSharedFolder);
_JumpIfError(hr, error, "myGetCertRegStrValue");
if (NULL == pwszSharedFolder)
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "No shared folder");
}
pwsz = pwszSharedFolder;
break;
case CR_PROP_PARENTCA:
if (L'\0' == g_wszParentConfig[0])
{
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
_JumpError(hr, error, "No parent");
}
pwsz = g_wszParentConfig;
break;
case CR_PROP_CATYPE:
case CR_PROP_CASIGCERTCOUNT:
case CR_PROP_CAXCHGCERTCOUNT:
case CR_PROP_EXITCOUNT:
case CR_PROP_CAPROPIDMAX:
case CR_PROP_ROLESEPARATIONENABLED:
case CR_PROP_KRACERTUSEDCOUNT:
case CR_PROP_KRACERTCOUNT:
case CR_PROP_ADVANCEDSERVER:
ZeroMemory(&CAInfo, sizeof(CAInfo));
CAInfo.cbSize = sizeof(CAInfo);
CAInfo.CAType = g_CAType;
CAInfo.cCASignatureCerts = g_cCACerts;
CAInfo.cCAExchangeCerts = 1; // current Xchg cert only
CAInfo.cExitModules = g_cExitMod;
CAInfo.lPropIdMax = g_CAPropIdMax;
CAInfo.lRoleSeparationEnabled = CAuditEvent::RoleSeparationIsEnabled();
CAInfo.fAdvancedServer = g_fAdvancedServer;
hr = myGetCertRegDWValue(
g_wszSanitizedName,
NULL,
NULL,
wszREGKRACERTCOUNT,
&CAInfo.cKRACertUsedCount);
_JumpIfError(hr, error, "myGetCertRegDWValue wszREGKRACERTCOUNT");
hr = myGetCARegHashCount(
g_wszSanitizedName,
CSRH_CAKRACERT,
&CAInfo.cKRACertCount);
_JumpIfError(hr, error, "myGetCertRegStrValue wszREGKRACERTCOUNT");
pctbOut->cb = sizeof(CAInfo);
pb = (BYTE *) &CAInfo;
break;
case CR_PROP_CASIGCERT:
hr = PKCSGetCACert(PropIndex, &pb, &pctbOut->cb);
_JumpIfError(hr, error, "PKCSGetCACert");
break;
case CR_PROP_CASIGCERTCHAIN:
case CR_PROP_CASIGCERTCRLCHAIN:
hr = PKCSGetCAChain(
PropIndex,
CR_PROP_CASIGCERTCRLCHAIN == PropId,
&pbAlloc,
&pctbOut->cb);
_JumpIfError(hr, error, "PKCSGetCAChain");
pb = pbAlloc; // must be freed
break;
case CR_PROP_CAXCHGCERT:
hr = GetClientUserName(NULL, &pwszUserName, NULL);
_JumpIfError(hr, error, "GetClientUserName");
hr = PKCSGetCAXchgCert(
PropIndex,
pwszUserName,
&iCertSig,
&pb,
&pctbOut->cb);
_JumpIfError(hr, error, "PKCSGetCAXchgCert");
break;
case CR_PROP_CAXCHGCERTCHAIN:
case CR_PROP_CAXCHGCERTCRLCHAIN:
hr = GetClientUserName(NULL, &pwszUserName, NULL);
_JumpIfError(hr, error, "GetClientUserName");
hr = PKCSGetCAXchgChain(
PropIndex,
pwszUserName,
CR_PROP_CAXCHGCERTCRLCHAIN == PropId,
&pbAlloc,
&pctbOut->cb);
_JumpIfError(hr, error, "PKCSGetCAXchgChain");
pb = pbAlloc; // must be freed
break;
case CR_PROP_BASECRL:
case CR_PROP_DELTACRL:
hr = CRLGetCRL(
PropIndex,
CR_PROP_DELTACRL == PropId,
&pCRL,
NULL);
_JumpIfError(hr, error, "CRLGetCRL");
pctbOut->cb = pCRL->cbCrlEncoded;
pb = (BYTE *) pCRL->pbCrlEncoded;
break;
case CR_PROP_CACERTSTATUSCODE:
hr = PKCSGetCACertStatusCode(PropIndex, &hrCAStatusCode);
pctbOut->cb = sizeof(hrCAStatusCode);
pb = (BYTE *) &hrCAStatusCode;
break;
case CR_PROP_CACERTSTATE:
case CR_PROP_CRLSTATE:
pctbOut->cb = g_cCACerts;
pbAlloc = (BYTE *) MIDL_user_allocate(g_cCACerts);
if (NULL == pbAlloc)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "no memory");
}
pb = pbAlloc; // must be freed
hr = PKCSGetCAState(CR_PROP_CACERTSTATE == PropId, pb);
_JumpIfError(hr, error, "PKCSGetCAState");
break;
case CR_PROP_KRACERTSTATE:
hr = myGetCARegHashCount(
g_wszSanitizedName,
CSRH_CAKRACERT,
&pctbOut->cb);
_JumpIfError(hr, error, "myGetCARegHashCount CSRH_CAKRACERT");
pbAlloc = (BYTE *) MIDL_user_allocate(pctbOut->cb);
if (NULL == pbAlloc)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "no memory");
}
pb = pbAlloc; // must be freed
hr = PKCSGetKRAState(pctbOut->cb, pb);
_JumpIfError(hr, error, "PKCSGetKRAState");
break;
case CR_PROP_DNSNAME:
pwsz = g_pwszServerName;
break;
case CR_PROP_KRACERT:
hKRAStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING,
NULL, // hProv
CERT_SYSTEM_STORE_LOCAL_MACHINE,
wszKRA_CERTSTORE);
hr = myFindCACertByHashIndex(
hKRAStore,
g_wszSanitizedName,
CSRH_CAKRACERT,
PropIndex,
NULL,
&pCertContext);
_JumpIfError(hr, error, "myFindCACertByHashIndex");
pb = pCertContext->pbCertEncoded;
pctbOut->cb = pCertContext->cbCertEncoded;
break;
case CR_PROP_TEMPLATES:
hr = GetCATemplates(pbAlloc, pctbOut->cb);
_JumpIfError(hr, error, "GetCATemplates");
break;
case CR_PROP_BASECRLPUBLISHSTATUS:
case CR_PROP_DELTACRLPUBLISHSTATUS:
pctbOut->cb = sizeof(DWORD);
pbAlloc = (BYTE *) MIDL_user_allocate(pctbOut->cb);
_JumpIfAllocFailed(pbAlloc, error);
pb = pbAlloc; // must be freed
hr = CRLGetCRL(
PropIndex,
CR_PROP_DELTACRLPUBLISHSTATUS == PropId, // fDelta
NULL,
(DWORD *) pbAlloc);
_JumpIfError(hr, error, "CRLGetCRL");
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "Bad PropId");
}
// not yet populated?
if (NULL == pb && NULL != pwsz)
{
pctbOut->cb = (wcslen(pwsz) + 1) * sizeof(WCHAR);
pb = (BYTE *) pwsz;
}
if (NULL != pbAlloc)
{
pctbOut->pb = pbAlloc;
pbAlloc = NULL;
}
else
{
if (NULL == pb)
{
hr = E_POINTER;
_JumpError(hr, error, "pb NULL");
}
pbReturn = (BYTE *) MIDL_user_allocate(pctbOut->cb);
if (NULL == pbReturn)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "no memory");
}
CopyMemory(pbReturn, pb, pctbOut->cb);
pctbOut->pb = pbReturn;
}
error:
if (NULL != pwszUserName)
{
LocalFree(pwszUserName);
}
if (NULL != pCRL)
{
CertFreeCRLContext(pCRL);
}
if (NULL != pbAlloc)
{
CoTaskMemFree(pbAlloc);
}
if (NULL != pwszSharedFolder)
{
LocalFree(pwszSharedFolder);
}
if (NULL != hKRAStore)
{
CertCloseStore(hKRAStore, CERT_CLOSE_STORE_CHECK_FLAG);
}
if (NULL != pCertContext)
{
CertFreeCertificateContext(pCertContext);
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
RequestGetCAProperty(
IN LONG PropId, // CR_PROP_*
IN LONG PropIndex,
IN LONG PropType, // PROPTYPE_*
OUT CERTTRANSBLOB *pctbPropertyValue)
{
HRESULT hr;
pctbPropertyValue->pb = NULL;
pctbPropertyValue->cb = 0;
hr = ValidatePropertyParameters(PropId, PropIndex, PropType);
_JumpIfError(hr, error, "Invalid prop params");
hr = RequestGetCAPropertySub(
PropId,
PropIndex,
PropType,
pctbPropertyValue);
_JumpIfError(hr, error, "RequestGetCAPropertySub");
myRegisterMemFree(pctbPropertyValue->pb, CSM_COTASKALLOC);
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
RequestSetCAPropertySub(
IN LONG PropId, // CR_PROP_*
IN LONG PropIndex,
IN LONG PropType, // PROPTYPE_*
IN CERTTRANSBLOB *pctbIn)
{
HRESULT hr = S_OK;
LONG lVal = 0;
const CERT_CONTEXT *pCertContext = NULL;
HCERTSTORE hKRAStore = NULL;
switch(PropId)
{
case CR_PROP_ROLESEPARATIONENABLED:
{
lVal = *(LONG *) pctbIn->pb;
CAuditEvent SaveFlagObj; // used just for saving the flag
SaveFlagObj.RoleSeparationEnable(lVal? true : false);
hr = SaveFlagObj.RoleSeparationFlagSave(g_wszSanitizedName);
_JumpIfError(hr, error, "failed to save ");
}
break;
case CR_PROP_KRACERTUSEDCOUNT:
CSASSERT(sizeof(DWORD)==pctbIn->cb);
hr = mySetCertRegDWValue(
g_wszSanitizedName,
NULL,
NULL,
wszREGKRACERTCOUNT,
*(DWORD*)pctbIn->pb);
_JumpIfError(hr, error, "mySetCertRegDWValue ");
break;
case CR_PROP_KRACERTCOUNT:
// New hash count; calling this should follow a sequence of
// SetCaProperty(CR_PROP_KRACERT) and should be called only if
// new hash count is smaller than current count. If PropIndex>=current count
// this fails with E_INVALIDARG;
CSASSERT(sizeof(DWORD)==pctbIn->cb);
hr = myShrinkCARegHash(
g_wszSanitizedName,
CSRH_CAKRACERT,
*(DWORD*)pctbIn->pb);
_JumpIfError(hr, error, "myShrinkCARegHash");
break;
case CR_PROP_KRACERT:
pCertContext = CertCreateCertificateContext(
X509_ASN_ENCODING,
pctbIn->pb,
pctbIn->cb);
if(!pCertContext)
{
hr = HRESULT_FROM_WIN32(GetLastError());
_JumpError(hr, error, "CertCreateCertificateContext");
}
// add certificate to KRA store
hKRAStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM_W,
X509_ASN_ENCODING,
NULL, // hProv
CERT_SYSTEM_STORE_LOCAL_MACHINE,
wszKRA_CERTSTORE);
if (NULL == hKRAStore)
{
hr = myHLastError();
_JumpError(hr, error, "CertOpenStore");
}
if (!CertAddCertificateContextToStore(
hKRAStore,
pCertContext,
CERT_STORE_ADD_NEW,
NULL))
{
hr = myHLastError();
if (HRESULT_FROM_WIN32(CRYPT_E_EXISTS) != hr)
{
_JumpError(hr, error, "CertAddCertificateContextToStore");
}
//the cert exists, ignore error
hr = S_OK;
}
// persist the hash
hr = mySetCARegHash(
g_wszSanitizedName,
CSRH_CAKRACERT,
PropIndex,
pCertContext);
_JumpIfError(hr, error, "mySetCARegHash");
break;
case CR_PROP_TEMPLATES:
hr = SetCATemplates(
pctbIn->pb,
pctbIn->cb);
_JumpIfError(hr, error, "GetCATemplates");
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "Bad PropId");
}
error:
if(pCertContext)
{
CertFreeCertificateContext(pCertContext);
}
return hr;
}
STDMETHODIMP
RequestSetCAProperty(
IN wchar_t const *pwszAuthority,
IN LONG PropId, // CR_PROP_*
IN LONG PropIndex,
IN LONG PropType, // PROPTYPE_*
IN CERTTRANSBLOB *pctbPropertyValue)
{
HRESULT hr;
CAuditEvent audit(SE_AUDITID_CERTSRV_SETCAPROPERTY, g_dwAuditFilter);
DWORD State = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
hr = ValidatePropertyParameters(
PropId,
PropIndex,
PropType);
_LeaveIfError(hr, "Invalid prop params");
hr = CheckAuthorityName(pwszAuthority);
_LeaveIfError(hr, "No authority name");
// Ignore role separation if setting the role separation flag.
// This allows an admin to turn the flag off even with role separation
// enabled so he won't lock himself out.
if(CR_PROP_ROLESEPARATIONENABLED==PropId)
{
audit.EventRoleSeparationEnable(false);
}
hr = audit.AddData((DWORD)PropId); // %1 property ID
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.AddData((DWORD)PropIndex); // %2 index
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.AddData((DWORD)PropType); // %3 type
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.AddData(pctbPropertyValue->pb, pctbPropertyValue->cb); // %4 value
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.AccessCheck(
CA_ACCESS_ADMIN,
audit.m_gcAuditSuccessOrFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = RequestSetCAPropertySub(
PropId,
PropIndex,
PropType,
pctbPropertyValue);
_LeaveIfError(hr, "RequestSetCAPropertySub");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return(hr);
}
STDMETHODIMP
CCertRequestD::GetCACert(
/* [in] */ DWORD Flags,
/* [unique][size_is][in] */ USHORT const __RPC_FAR *pwszAuthority,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbOut)
{
HRESULT hr = S_OK;
DWORD type = GETCERT_VERSIONMASK & Flags;
LONG PropIndex;
LONG PropId;
LONG PropType;
BOOL fChainAllowed;
GETCERTMAP const *pmap;
GETCERTMAP const *pmapFound;
DWORD State = 0;
DBGPRINT((
s_ssRequest,
"CCertRequestD::GetCACert(tid=%d, Flags=0x%x)\n",
GetCurrentThreadId(),
Flags));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
// allow empty name only if the client attempts retrieving the name
if(hr == E_INVALIDARG &&
(GETCERT_CANAME == type ||
GETCERT_SANITIZEDCANAME == type))
{
hr = S_OK;
}
_JumpIfError(hr, error, "No authority name");
__try
{
hr = RequestAccessCheck();
_LeaveIfError(hr, "RequestAccessCheck");
type = GETCERT_VERSIONMASK & Flags;
PropIndex = 0;
// NOTE: all of these should return only a single entry --
// multiple entries will be batched up by the caller
// (eg multiple CAs on a machine)
DBGCODE(WCHAR wszArg[10]); // Build up a nice debug print:
PropId = 0;
PropType = PROPTYPE_BINARY;
switch (type)
{
case GETCERT_CASIGCERT:
DBGCODE(wcscpy(wszArg, L"Cert"));
PropId = CR_PROP_CASIGCERT;
PropIndex = -1; // return latest Cert
break;
case GETCERT_CAXCHGCERT:
DBGCODE(wcscpy(wszArg, L"XchgCert"));
PropId = CR_PROP_CAXCHGCERT;
PropIndex = -1; // return latest Xchg Cert
break;
case GETCERT_CURRENTCRL:
DBGCODE(wcscpy(wszArg, L"CRL"));
PropId = CR_PROP_BASECRL;
PropIndex = -1; // return latest CRL
break;
default:
{
DBGCODE(wszArg[0] = ((char *) &type)[3]);
DBGCODE(wszArg[1] = ((char *) &type)[2]);
DBGCODE(wszArg[2] = ((char *) &type)[1]);
DBGCODE(wszArg[3] = ((char *) &type)[0]);
DBGCODE(wszArg[4] = L'\0');
switch (GETCERT_BYINDEXMASK & Flags)
{
case GETCERT_CACERTSTATEBYINDEX:
case GETCERT_CRLSTATEBYINDEX:
if (0 != (GETCERT_INDEXVALUEMASK & Flags))
{
hr = E_INVALIDARG;
_LeaveError(hr, "Invalid State Index");
}
// FALLTHROUGH
case GETCERT_EXITVERSIONBYINDEX:
case GETCERT_CACERTBYINDEX:
case GETCERT_CRLBYINDEX:
PropIndex = GETCERT_INDEXVALUEMASK & Flags;
type = GETCERT_BYINDEXMASK & Flags;
DBGCODE(swprintf(&wszArg[2], L".%u", PropIndex));
break;
}
break;
}
}
DBGPRINT((
s_ssRequest,
"CCertRequestD::GetCACert(\"%ws\"%ws)\n",
wszArg,
(GETCERT_CHAIN & Flags)? L"+Chain" : L""));
for (
pmap = g_aCAPropMap;
pmap < &g_aCAPropMap[ARRAYSIZE(g_aCAPropMap)];
pmap++)
{
if (type == pmap->dwGetCert)
{
PropId = pmap->lPropId;
PropType = pmap->lPropType;
break;
}
}
if (CR_PROP_CASIGCERT == PropId)
{
if (GETCERT_CHAIN & Flags)
{
PropId = CR_PROP_CASIGCERTCHAIN;
if (GETCERT_CRLS & Flags)
{
PropId = CR_PROP_CASIGCERTCRLCHAIN;
}
}
}
else if (CR_PROP_CAXCHGCERT == PropId)
{
if (GETCERT_CHAIN & Flags)
{
PropId = CR_PROP_CAXCHGCERTCHAIN;
if (GETCERT_CRLS & Flags)
{
PropId = CR_PROP_CAXCHGCERTCRLCHAIN;
}
}
}
else if ((GETCERT_CHAIN | GETCERT_CRLS) & Flags)
{
hr = E_INVALIDARG;
_LeaveError(hr, "Chain/CRLS Flag");
}
if (0 == PropId)
{
BYTE *pb;
switch (type)
{
case GETCERT_CATYPE:
pctbOut->cb = sizeof(g_CAType);
pb = (BYTE *) &g_CAType;
break;
default:
hr = E_INVALIDARG;
_LeaveError(hr, "Invalid GetCert Flags");
}
pctbOut->pb = (BYTE *) MIDL_user_allocate(pctbOut->cb);
if (NULL == pctbOut->pb)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "no memory");
}
CopyMemory(pctbOut->pb, pb, pctbOut->cb);
}
else
{
hr = RequestGetCAPropertySub(
PropId,
PropIndex,
PropType,
pctbOut);
_LeaveIfError(hr, "RequestGetCAPropertySub");
}
myRegisterMemFree(pctbOut->pb, CSM_COTASKALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertRequestD::GetCAProperty(
IN wchar_t const *pwszAuthority,
IN LONG PropId, // CR_PROP_*
IN LONG PropIndex,
IN LONG PropType, // PROPTYPE_*
OUT CERTTRANSBLOB *pctbPropertyValue)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssRequest,
"CCertRequestD::GetCAProperty(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
if (NULL == pwszAuthority ||
((L'\0' != *pwszAuthority ||
(CR_PROP_CANAME != PropId &&
CR_PROP_DNSNAME != PropId &&
CR_PROP_SANITIZEDCANAME != PropId)) &&
0 != lstrcmpi(pwszAuthority, g_wszCommonName) &&
0 != lstrcmpi(pwszAuthority, g_wszSanitizedName) &&
0 != lstrcmpi(pwszAuthority, g_pwszSanitizedDSName)))
{
hr = E_INVALIDARG;
_JumpError(hr, error, "bad authority name");
}
__try
{
hr = RequestAccessCheck();
_LeaveIfError(hr, "RequestAccessCheck");
hr = RequestGetCAProperty(
PropId,
PropIndex,
PropType,
pctbPropertyValue);
_LeaveIfError(hr, "RequestGetCAProperty");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertRequestD::GetCAPropertyInfo(
IN wchar_t const *pwszAuthority,
OUT LONG *pcProperty,
OUT CERTTRANSBLOB *pctbPropInfo)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssRequest,
"CCertRequestD::GetCAPropertyInfo(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
hr = RequestAccessCheck();
_LeaveIfError(hr, "RequestAccessCheck");
hr = RequestGetCAPropertyInfo(
pcProperty,
pctbPropInfo);
_JumpIfError(hr, error, "RequestGetCAPropertyInfo");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
CCertRequestD::_Ping(
IN WCHAR const *pwszAuthority)
{
HRESULT hr;
DWORD State = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
hr = CheckAuthorityName(pwszAuthority, true); // allow empty name
_JumpIfError(hr, error, "No authority name");
hr = RequestAccessCheck();
_LeaveIfError(hr, "RequestAccessCheck");
#if 1
wprintf(L"."); // may fault if I/O buffer is odd aligned
fprintf(stdout, ".");
wprintf(L".\n"); // may fault if I/O buffer is odd aligned
#endif
hr = S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertRequestD::Ping(
IN WCHAR const *pwszAuthority)
{
HRESULT hr;
DBGPRINT((
s_ssRequest,
"CCertRequestD::Ping(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = _Ping(pwszAuthority);
_JumpIfError(hr, error, "_Ping");
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertRequestD::Ping2(
IN WCHAR const *pwszAuthority)
{
HRESULT hr;
DBGPRINT((
s_ssRequest,
"CCertRequestD::Ping2(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = _Ping(pwszAuthority);
_JumpIfError(hr, error, "_Ping");
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
// Constructor
CCertRequestD::CCertRequestD() : m_cRef(1)
{
InterlockedIncrement(&g_cRequestComponents);
}
// Destructor
CCertRequestD::~CCertRequestD()
{
InterlockedDecrement(&g_cRequestComponents);
if (m_cRef != 0)
{
DBGPRINT((
DBG_SS_CERTSRV,
"CCertRequestD has %d instances left over\n",
m_cRef));
}
}
// IUnknown implementation
STDMETHODIMP
CCertRequestD::QueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown)
{
*ppv = static_cast<ICertRequestD *>(this);
}
else if (iid == IID_ICertRequestD)
{
*ppv = static_cast<ICertRequestD *>(this);
}
else if (iid == IID_ICertRequestD2)
{
*ppv = static_cast<ICertRequestD2 *>(this);
}
else
{
*ppv = NULL;
return(E_NOINTERFACE);
}
reinterpret_cast<IUnknown *>(*ppv)->AddRef();
return(S_OK);
}
ULONG STDMETHODCALLTYPE
CCertRequestD::AddRef()
{
return(InterlockedIncrement(&m_cRef));
}
ULONG STDMETHODCALLTYPE
CCertRequestD::Release()
{
ULONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
}
return(cRef);
}
// Class factory IUnknown implementation
STDMETHODIMP
CRequestFactory::QueryInterface(const IID& iid, void** ppv)
{
if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))
{
*ppv = static_cast<IClassFactory*>(this);
}
else
{
*ppv = NULL;
return(E_NOINTERFACE);
}
reinterpret_cast<IUnknown *>(*ppv)->AddRef();
return(S_OK);
}
ULONG STDMETHODCALLTYPE
CRequestFactory::AddRef()
{
return(InterlockedIncrement(&m_cRef));
}
ULONG STDMETHODCALLTYPE
CRequestFactory::Release()
{
ULONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
return(0);
}
return(cRef);
}
// IClassFactory implementation
STDMETHODIMP
CRequestFactory::CreateInstance(
IUnknown *pUnknownOuter,
const IID& iid,
void **ppv)
{
HRESULT hr;
CCertRequestD *pA;
// Cannot aggregate.
if (pUnknownOuter != NULL)
{
hr = CLASS_E_NOAGGREGATION;
_JumpError(hr, error, "pUnknownOuter");
}
// Create component.
pA = new CCertRequestD;
if (pA == NULL)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "out of memory");
}
// Get the requested interface.
hr = pA->QueryInterface(iid, ppv);
// Release the IUnknown pointer.
// (If QueryInterface failed, component will delete itself.)
pA->Release();
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
// LockServer
STDMETHODIMP
CRequestFactory::LockServer(
BOOL bLock)
{
if (bLock)
{
InterlockedIncrement(&g_cRequestServerLocks);
}
else
{
InterlockedDecrement(&g_cRequestServerLocks);
}
return(S_OK);
}
STDMETHODIMP
CRequestFactory::CanUnloadNow()
{
if (g_cRequestComponents || g_cRequestServerLocks)
{
return(S_FALSE);
}
return(S_OK);
}
STDMETHODIMP
CRequestFactory::StartFactory()
{
HRESULT hr;
g_pIRequestFactory = new CRequestFactory();
if (NULL == g_pIRequestFactory)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "alloc CRequestFactory");
}
hr = CoRegisterClassObject(
CLSID_CCertRequestD,
static_cast<IUnknown *>(g_pIRequestFactory),
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE,
&g_dwRequestRegister);
_JumpIfError(hr, error, "CoRegisterClassObject");
error:
if (S_OK != hr)
{
// does deletion
CRequestFactory::StopFactory();
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
VOID
CRequestFactory::StopFactory()
{
HRESULT hr;
if (0 != g_dwRequestRegister)
{
hr = CoRevokeClassObject(g_dwRequestRegister);
_PrintIfError(hr, "CoRevokeClassObject");
g_dwRequestRegister = 0;
}
if (NULL != g_pIRequestFactory)
{
g_pIRequestFactory->Release();
g_pIRequestFactory = NULL;
}
}