2036 lines
50 KiB
C++
2036 lines
50 KiB
C++
|
//+--------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
}
|