windows-nt/Source/XPSP1/NT/ds/security/services/ca/certsrv/admin.cpp
2020-09-26 16:20:57 +08:00

4920 lines
110 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: admin.cpp
//
// Contents: Implementation of DCOM object for RPC services
//
// History: July-97 xtan created
//
//---------------------------------------------------------------------------
#include <pch.cpp>
#pragma hdrstop
#include <accctrl.h>
#include "csdisp.h"
#include "csprop.h"
#include "cscom.h"
#include "certlog.h"
#include "certsrvd.h"
#include "admin.h"
#include "resource.h"
#include "dbtable.h"
#include "elog.h"
#define __dwFILE__ __dwFILE_CERTSRV_ADMIN_CPP__
// Global variables
long g_cAdminComponents = 0; // Count of active components
long g_cAdminServerLocks = 0; // Count of locks
DWORD g_dwAdminRegister = 0;
IClassFactory* g_pIAdminFactory = NULL;
extern HWND g_hwndMain;
#ifdef DBG_CERTSRV_DEBUG_PRINT
DWORD s_ssAdmin = DBG_SS_CERTSRVI;
#endif
using namespace CertSrv;
// Admin component
// begin implementing cert admin services
HRESULT
AdminGetIndexedCRL(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ DWORD CertIndex, // -1: current CA cert
/* [in] */ DWORD Flags, // CA_CRL_*
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbCRL)
{
HRESULT hr;
CRL_CONTEXT const *pCRL = NULL;
CAuditEvent audit(0, g_dwAuditFilter);
DWORD State = 0;
pctbCRL->pb = NULL;
pctbCRL->cb = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
switch (Flags)
{
case CA_CRL_BASE:
case CA_CRL_DELTA:
break;
default:
hr = E_INVALIDARG;
_LeaveError(hr, "Flags");
}
// get the requested CRL:
hr = CRLGetCRL(CertIndex, CA_CRL_DELTA == Flags, &pCRL, NULL);
_LeaveIfError(hr, "CRLGetCRL");
pctbCRL->cb = pCRL->cbCrlEncoded;
pctbCRL->pb = (BYTE *) MIDL_user_allocate(pCRL->cbCrlEncoded);
if (NULL == pctbCRL->pb)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "MIDL_user_allocate");
}
CopyMemory(pctbCRL->pb, pCRL->pbCrlEncoded, pCRL->cbCrlEncoded);
myRegisterMemFree(pctbCRL->pb, CSM_MIDLUSERALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != pCRL)
{
CertFreeCRLContext(pCRL);
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::GetCRL(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbCRL)
{
HRESULT hr;
// Just get current base CRL:
hr = AdminGetIndexedCRL(pwszAuthority, MAXDWORD, CA_CRL_BASE, pctbCRL);
_JumpIfError(hr, error, "AdminGetIndexedCRL");
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::GetArchivedKey(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ DWORD dwRequestId,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbArchivedKey)
{
HRESULT hr;
CAuditEvent audit(SE_AUDITID_CERTSRV_GETARCHIVEDKEY, g_dwAuditFilter);
DWORD State = 0;
pctbArchivedKey->pb = NULL;
pctbArchivedKey->cb = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
hr = audit.AddData(dwRequestId); // %1 request ID
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.AccessCheck(
CA_ACCESS_OFFICER,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = CheckOfficerRights(dwRequestId, audit);
_LeaveIfError(hr, "CheckOfficerRights");
hr = PKCSGetArchivedKey(
dwRequestId,
&pctbArchivedKey->pb,
&pctbArchivedKey->cb);
_LeaveIfError(hr, "PKCSGetArchivedKey");
myRegisterMemFree(pctbArchivedKey->pb, CSM_COTASKALLOC);
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::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_ssAdmin,
"CCertAdminD::GetCAProperty(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
CAuditEvent audit(0, g_dwAuditFilter);
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess |
audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
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
CCertAdminD::SetCAProperty(
IN wchar_t const *pwszAuthority,
IN LONG PropId, // CR_PROP_*
IN LONG PropIndex,
IN LONG PropType, // PROPTYPE_*
OUT CERTTRANSBLOB *pctbPropertyValue)
{
HRESULT hr;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::SetCAProperty(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = RequestSetCAProperty(
pwszAuthority,
PropId,
PropIndex,
PropType,
pctbPropertyValue);
_JumpIfError(hr, error, "RequestSetCAProperty");
error:
return(hr);
}
STDMETHODIMP
CCertAdminD::GetCAPropertyInfo(
IN wchar_t const *pwszAuthority,
OUT LONG *pcProperty,
OUT CERTTRANSBLOB *pctbPropInfo)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::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
{
CAuditEvent audit(0, g_dwAuditFilter);
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess |
audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = RequestGetCAPropertyInfo(
pcProperty,
pctbPropInfo);
_LeaveIfError(hr, "RequestGetCAPropertyInfo");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::PublishCRL(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ FILETIME NextUpdate)
{
HRESULT hr;
// CA_CRL_BASE implies CA_CRL_DELTA when delta CRLs are enabled.
hr = PublishCRLs(pwszAuthority, NextUpdate, CA_CRL_BASE);
_JumpError(hr, error, "PublishCRLs");
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::PublishCRLs(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ FILETIME NextUpdate,
/* [in] */ DWORD Flags) // CA_CRL_*
{
HRESULT hr;
BOOL fRetry = FALSE;
BOOL fForceRepublishCRL;
BOOL fShadowDelta = FALSE;
WCHAR *pwszUserName = NULL;
CAuditEvent audit(SE_AUDITID_CERTSRV_PUBLISHCRL, g_dwAuditFilter);
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::PublishCRL(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
HRESULT hrPublish;
hr = audit.AddData(NextUpdate); // %1 next update
_LeaveIfError(hr, "AddData");
hr = audit.AddData(
(CA_CRL_BASE & Flags)? true : false); // %2 publish base
_LeaveIfError(hr, "AddData");
hr = audit.AddData(
(CA_CRL_DELTA & Flags)? true : false); // %3 publish delta
_LeaveIfError(hr, "AddData");
hr = audit.AccessCheck(
CA_ACCESS_ADMIN,
audit.m_gcAuditSuccessOrFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
switch (~CA_CRL_REPUBLISH & Flags)
{
case CA_CRL_BASE:
break;
case CA_CRL_DELTA:
if (g_fDeltaCRLPublishDisabled)
{
fShadowDelta = TRUE;
}
break;
case CA_CRL_BASE | CA_CRL_DELTA:
if (g_fDeltaCRLPublishDisabled)
{
hr = E_INVALIDARG;
_LeaveError(hr, "Delta CRLs disabled");
}
break;
default:
hr = E_INVALIDARG;
_LeaveError(hr, "Flags");
}
fForceRepublishCRL = (CA_CRL_REPUBLISH & Flags)? TRUE : FALSE;
hr = GetClientUserName(NULL, &pwszUserName, NULL);
_LeaveIfError(hr, "GetClientUserName");
hr = CRLPublishCRLs(
!fForceRepublishCRL, // fRebuildCRL
fForceRepublishCRL, // fForceRepublish
pwszUserName,
CA_CRL_DELTA == (~CA_CRL_REPUBLISH & Flags), // fDeltaOnly
fShadowDelta,
NextUpdate,
&fRetry,
&hrPublish);
_LeaveIfError(hr, "CRLPublishCRLs");
hr = hrPublish;
_LeaveIfError(hr, "CRLPublishCRLs(hrPublish)");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != pwszUserName)
{
LocalFree(pwszUserName);
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::SetExtension(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ DWORD dwRequestId,
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszExtensionName,
/* [in] */ DWORD dwType,
/* [in] */ DWORD dwFlags,
/* [ref][in] */ CERTTRANSBLOB __RPC_FAR *pctbValue)
{
HRESULT hr;
ICertDBRow *prow = NULL;
CAuditEvent audit(SE_AUDITID_CERTSRV_SETEXTENSION, g_dwAuditFilter);
DWORD State = 0;
BOOL fCommitted = FALSE;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::SetExtension(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 = audit.AddData(dwRequestId); // %1 Request ID
_LeaveIfError(hr, "AddData");
hr = audit.AddData(pwszExtensionName); // %2 name
_LeaveIfError(hr, "AddData");
hr = audit.AddData(dwType); // %3 type
_LeaveIfError(hr, "AddData");
hr = audit.AddData(dwFlags); // %4 flags
_LeaveIfError(hr, "AddData");
hr = audit.AddData(pctbValue->pb, pctbValue->cb); // %5 data
_LeaveIfError(hr, "AddData");
hr = audit.AccessCheck(
CA_ACCESS_OFFICER,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = CheckOfficerRights(dwRequestId, audit);
_LeaveIfError(hr, "CheckOfficerRights");
hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, dwRequestId, NULL, &prow);
_LeaveIfError(hr, "OpenRow");
hr = CoreValidateRequestId(prow, DB_DISP_PENDING);
if (S_OK != hr)
{
hr = myHError(hr);
_LeaveError(hr, "CoreValidateRequestId");
}
hr = PropSetExtension(
prow,
PROPCALLER_ADMIN | (PROPTYPE_MASK & dwType),
pwszExtensionName,
EXTENSION_ORIGIN_ADMIN |
(EXTENSION_POLICY_MASK & dwFlags),
pctbValue->cb,
pctbValue->pb);
_LeaveIfError(hr, "PropSetExtension");
hr = prow->CommitTransaction(TRUE);
_LeaveIfError(hr, "CommitTransaction");
fCommitted = TRUE;
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != prow)
{
if (S_OK != hr && !fCommitted)
{
HRESULT hr2 = prow->CommitTransaction(FALSE);
_PrintIfError(hr2, "CommitTransaction");
}
prow->Release();
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::SetAttributes(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ DWORD dwRequestId,
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAttributes)
{
HRESULT hr;
ICertDBRow *prow = NULL;
CAuditEvent audit(SE_AUDITID_CERTSRV_SETATTRIBUTES, g_dwAuditFilter);
DWORD State = 0;
BOOL fCommitted = FALSE;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::SetAttributes(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 = audit.AddData(dwRequestId); // %1 request ID
_LeaveIfError(hr, "AddData");
hr = audit.AddData(pwszAttributes); // %2 attributes
_LeaveIfError(hr, "AddData");
hr = audit.AccessCheck(
CA_ACCESS_OFFICER,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = CheckOfficerRights(dwRequestId, audit);
_LeaveIfError(hr, "CheckOfficerRights");
hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, dwRequestId, NULL, &prow);
_LeaveIfError(hr, "OpenRow");
hr = CoreValidateRequestId(prow, DB_DISP_PENDING);
if (S_OK != hr)
{
hr = myHError(hr);
_LeaveError(hr, "CoreValidateRequestId");
}
if (NULL == pwszAttributes)
{
hr = E_INVALIDARG;
_LeaveError(hr, "pwszAttributes NULL");
}
hr = PKCSParseAttributes(
prow,
pwszAttributes,
FALSE,
PROPTABLE_CERTIFICATE,
NULL);
if (S_OK != hr)
{
hr = myHError(hr);
_LeaveError(hr, "PKCSParseAttributes");
}
hr = prow->CommitTransaction(TRUE);
_LeaveIfError(hr, "CommitTransaction");
fCommitted = TRUE;
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != prow)
{
if (S_OK != hr && !fCommitted)
{
HRESULT hr2 = prow->CommitTransaction(FALSE);
_PrintIfError(hr2, "CommitTransaction");
}
prow->Release();
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::DenyRequest(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ DWORD dwRequestId)
{
HRESULT hr;
DWORD Disposition;
WCHAR *pwszUserName = NULL;
CERTSRV_COM_CONTEXT ComContext;
DWORD dwComContextIndex = MAXDWORD;
CERTSRV_RESULT_CONTEXT Result;
CAuditEvent audit(SE_AUDITID_CERTSRV_DENYREQUEST, g_dwAuditFilter);
DWORD State = 0;
ZeroMemory(&ComContext, sizeof(ComContext));
DBGPRINT((
s_ssAdmin,
"CCertAdminD::DenyRequest(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No Authority Name");
hr = RegisterComContext(&ComContext, &dwComContextIndex);
_JumpIfError(hr, error, "RegisterComContext");
ZeroMemory(&Result, sizeof(Result));
Result.pdwRequestId = &dwRequestId;
Result.pdwDisposition = &Disposition;
__try
{
hr = audit.AddData(dwRequestId); // %1 request ID
_LeaveIfError(hr, "AddData");
hr = audit.AccessCheck(
CA_ACCESS_OFFICER,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = CheckOfficerRights(dwRequestId, audit);
_LeaveIfError(hr, "CheckOfficerRights");
hr = GetClientUserName(NULL, &pwszUserName, NULL);
_LeaveIfError(hr, "GetClientUserName");
hr = CoreProcessRequest(
CR_IN_DENY, // dwFlags
pwszUserName,
0, // cbRequest
NULL, // pbRequest
NULL, // pwszAttributes
NULL, // pwszSerialNumber
dwComContextIndex,
dwRequestId,
&Result);
if (S_OK != hr)
{
hr = myHError(hr);
_LeaveError(hr, "CoreProcessRequest");
}
if (FAILED(Disposition))
{
hr = (HRESULT) Disposition;
_LeaveError(hr, "CoreProcessRequest(Disposition)");
}
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != pwszUserName)
{
LocalFree(pwszUserName);
}
if (MAXDWORD != dwComContextIndex)
{
UnregisterComContext(&ComContext, dwComContextIndex);
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::ResubmitRequest(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [in] */ DWORD dwRequestId,
/* [out] */ DWORD __RPC_FAR *pdwDisposition)
{
HRESULT hr;
WCHAR *pwszUserName = NULL;
CERTSRV_COM_CONTEXT ComContext;
DWORD dwComContextIndex = MAXDWORD;
CERTSRV_RESULT_CONTEXT Result;
CAuditEvent audit(SE_AUDITID_CERTSRV_RESUBMITREQUEST, g_dwAuditFilter);
DWORD State = 0;
ZeroMemory(&ComContext, sizeof(ComContext));
DBGPRINT((
s_ssAdmin,
"CCertAdminD::ResubmitRequest(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
hr = RegisterComContext(&ComContext, &dwComContextIndex);
_JumpIfError(hr, error, "RegisterComContext");
__try
{
hr = audit.AddData(dwRequestId); // %1 request ID
_LeaveIfError(hr, "AddData");
hr = audit.AccessCheck(
CA_ACCESS_OFFICER,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = CheckOfficerRights(dwRequestId, audit);
_LeaveIfError(hr, "CheckOfficerRights");
hr = GetClientUserName(NULL, &pwszUserName, NULL);
_LeaveIfError(hr, "GetClientUserName");
ComContext.fInRequestGroup = MAXDWORD; // mark value invalid
ZeroMemory(&Result, sizeof(Result));
Result.pdwRequestId = &dwRequestId;
Result.pdwDisposition = pdwDisposition;
hr = CoreProcessRequest(
CR_IN_RESUBMIT, // dwFlags
pwszUserName, // pwszUserName
0, // cbRequest
NULL, // pbRequest
NULL, // pwszAttributes
NULL, // pwszSerialNumber
dwComContextIndex,
dwRequestId,
&Result);
if (S_OK != hr)
{
hr = myHError(hr);
_LeaveError(hr, "CoreProcessRequest");
}
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != pwszUserName)
{
LocalFree(pwszUserName);
}
if (NULL != ComContext.hAccessToken)
{
__try
{
CloseHandle(ComContext.hAccessToken);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
}
if (MAXDWORD != dwComContextIndex)
{
UnregisterComContext(&ComContext, dwComContextIndex);
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::EnumViewColumn(
/* [ref][in] */ wchar_t const *pwszAuthority,
/* [in] */ DWORD iColumn,
/* [in] */ DWORD cColumn,
/* [out] */ DWORD *pcColumn,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbColumnInfo) // CoTaskMem*
{
HRESULT hr;
hr = EnumViewColumnTable(
pwszAuthority,
CVRC_TABLE_REQCERT,
iColumn,
cColumn,
pcColumn,
pctbColumnInfo); // CoTaskMem*
_JumpIfError(hr, error, "EnumViewColumnTable");
error:
CSASSERT(S_OK == hr || S_FALSE == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::EnumViewColumnTable(
/* [ref][in] */ wchar_t const *pwszAuthority,
/* [in] */ DWORD iTable,
/* [in] */ DWORD iColumn,
/* [in] */ DWORD cColumn,
/* [out] */ DWORD *pcColumn,
/* [ref][out] */ CERTTRANSBLOB __RPC_FAR *pctbColumnInfo) // CoTaskMem*
{
HRESULT hr;
LONG iColumnCurrent;
CERTDBCOLUMN *rgColumn = NULL;
CERTDBCOLUMN *pColumn;
CERTDBCOLUMN *pColumnEnd;
CERTTRANSDBCOLUMN *rgtColumnOut = NULL;
CERTTRANSDBCOLUMN *ptColumn;
DWORD cColumnFetched;
DWORD cb;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::EnumViewColumnTable(tid=%d, this=%x, icol=%d, ccol=%d)\n",
GetCurrentThreadId(),
this,
iColumn,
cColumn));
pctbColumnInfo->cb = 0;
pctbColumnInfo->pb = NULL;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
if (NULL == m_pEnumCol || iTable != m_iTableEnum)
{
if (NULL != m_pEnumCol)
{
m_pEnumCol->Release();
m_pEnumCol = NULL;
}
hr = g_pCertDB->EnumCertDBColumn(iTable, &m_pEnumCol);
_LeaveIfError(hr, "EnumCertDBColumn");
m_iTableEnum = iTable;
}
rgColumn = (CERTDBCOLUMN *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
cColumn * sizeof(rgColumn[0]));
if (NULL == rgColumn)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "Alloc rgColumn");
}
hr = m_pEnumCol->Skip(0, &iColumnCurrent);
_LeaveIfError(hr, "Skip");
if (iColumnCurrent != (LONG) iColumn)
{
hr = m_pEnumCol->Skip(
(LONG) iColumn - iColumnCurrent,
&iColumnCurrent);
_LeaveIfError(hr, "Skip");
CSASSERT((LONG) iColumn == iColumnCurrent);
}
hr = m_pEnumCol->Next(cColumn, rgColumn, &cColumnFetched);
if (S_FALSE != hr)
{
_LeaveIfError(hr, "Next");
}
DBGPRINT((
DBG_SS_CERTSRVI,
"EnumViewColumnTable: cColumnFetched=%d\n",
cColumnFetched));
cb = cColumnFetched * sizeof(rgtColumnOut[0]);
pColumnEnd = &rgColumn[cColumnFetched];
for (pColumn = rgColumn; pColumn < pColumnEnd; pColumn++)
{
cb += DWORDROUND((wcslen(pColumn->pwszName) + 1) * sizeof(WCHAR));
cb += DWORDROUND((wcslen(pColumn->pwszDisplayName) + 1) * sizeof(WCHAR));
}
rgtColumnOut = (CERTTRANSDBCOLUMN *) MIDL_user_allocate(cb);
if (NULL == rgtColumnOut)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "MIDL_user_allocate rgtColumnOut");
}
ZeroMemory(rgtColumnOut, cb);
pctbColumnInfo->cb = cb;
cb = cColumnFetched * sizeof(rgtColumnOut[0]);
pColumnEnd = &rgColumn[cColumnFetched];
ptColumn = rgtColumnOut;
for (pColumn = rgColumn; pColumn < pColumnEnd; ptColumn++, pColumn++)
{
DWORD cbT;
ptColumn->Type = pColumn->Type;
ptColumn->Index = pColumn->Index;
ptColumn->cbMax = pColumn->cbMax;
DBGPRINT((
DBG_SS_CERTSRVI,
"EnumViewColumnTable: ielt=%d idx=%x \"%ws\"\n",
iColumn + (ptColumn - rgtColumnOut),
ptColumn->Index,
pColumn->pwszName));
cbT = (wcslen(pColumn->pwszName) + 1) * sizeof(WCHAR);
CopyMemory(Add2Ptr(rgtColumnOut, cb), pColumn->pwszName, cbT);
ptColumn->obwszName = cb;
cb += DWORDROUND(cbT);
cbT = (wcslen(pColumn->pwszDisplayName) + 1) * sizeof(WCHAR);
CopyMemory(Add2Ptr(rgtColumnOut, cb), pColumn->pwszDisplayName, cbT);
ptColumn->obwszDisplayName = cb;
cb += DWORDROUND(cbT);
}
CSASSERT(cb == pctbColumnInfo->cb);
pctbColumnInfo->pb = (BYTE *) rgtColumnOut;
rgtColumnOut = NULL;
*pcColumn = cColumnFetched;
myRegisterMemFree(pctbColumnInfo->pb, CSM_MIDLUSERALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != rgColumn)
{
pColumnEnd = &rgColumn[cColumn];
for (pColumn = rgColumn; pColumn < pColumnEnd; pColumn++)
{
if (NULL != pColumn->pwszName)
{
CoTaskMemFree(pColumn->pwszName);
}
if (NULL != pColumn->pwszDisplayName)
{
CoTaskMemFree(pColumn->pwszDisplayName);
}
}
LocalFree(rgColumn);
}
if (NULL != rgtColumnOut)
{
MIDL_user_free(rgtColumnOut);
}
DBGPRINT((
DBG_SS_CERTSRVI,
"EnumViewColumnTable: icol=%d, ccol=%d, ccolout=%d, hr=%x\n",
iColumn,
cColumn,
*pcColumn,
hr));
CertSrvExitServer(State);
CSASSERT(S_OK == hr || S_FALSE == hr || FAILED(hr));
return(hr);
}
HRESULT
CCertAdminD::GetViewDefaultColumnSet(
IN wchar_t const *pwszAuthority,
IN DWORD iColumnSetDefault,
OUT DWORD *pcColumn,
OUT CERTTRANSBLOB *ptbColumnInfo) // CoTaskMem*
{
HRESULT hr;
DWORD ccol;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::GetViewDefaultColumnSet(tid=%d, this=%x, icolset=%d)\n",
GetCurrentThreadId(),
this,
iColumnSetDefault));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
{
CAuditEvent audit(0, g_dwAuditFilter);
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
}
hr = g_pCertDB->GetDefaultColumnSet(iColumnSetDefault, 0, &ccol, NULL);
_LeaveIfError(hr, "GetDefaultColumnSet");
ptbColumnInfo->cb = ccol * sizeof(DWORD);
ptbColumnInfo->pb = (BYTE *) MIDL_user_allocate(ptbColumnInfo->cb);
if (NULL == ptbColumnInfo->pb)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "MIDL_user_allocate");
}
myRegisterMemFree(ptbColumnInfo->pb, CSM_MIDLUSERALLOC);
hr = g_pCertDB->GetDefaultColumnSet(
iColumnSetDefault,
ccol,
pcColumn,
(DWORD *) ptbColumnInfo->pb);
_LeaveIfError(hr, "GetDefaultColumnSet");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
DBGPRINT((
S_OK == hr? DBG_SS_CERTSRVI : DBG_SS_CERTSRV,
"GetViewDefaultColumnSet: icolset=%d, ccolout=%d, hr=%x\n",
iColumnSetDefault,
*pcColumn,
hr));
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
CCertAdminD::_EnumAttributes(
IN ICertDBRow *prow,
IN CERTDBNAME *adbn,
IN DWORD celt,
OUT CERTTRANSBLOB *pctbOut) // CoTaskMem*
{
HRESULT hr;
DWORD i;
DWORD cb;
DWORD cbT;
CERTTRANSDBATTRIBUTE *pteltOut;
BYTE *pbOut;
BYTE *pbOutEnd;
DWORD State = 0;
CSASSERT(NULL == pctbOut->pb);
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
cb = sizeof(*pteltOut) * celt;
for (i = 0; i < celt; i++)
{
cb += (wcslen(adbn[i].pwszName) + 1) * sizeof(WCHAR);
cb = DWORDROUND(cb);
cbT = 0;
hr = prow->GetProperty(
adbn[i].pwszName,
PROPTYPE_STRING |
PROPCALLER_ADMIN |
PROPTABLE_ATTRIBUTE,
&cbT,
NULL);
_JumpIfError(hr, error, "GetProperty(NULL)");
cb += DWORDROUND(cbT);
}
pctbOut->pb = (BYTE *) MIDL_user_allocate(cb);
if (NULL == pctbOut->pb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "MIDL_user_allocate out data");
}
pctbOut->cb = cb;
pteltOut = (CERTTRANSDBATTRIBUTE *) pctbOut->pb;
pbOut = (BYTE *) &pteltOut[celt];
pbOutEnd = &pctbOut->pb[pctbOut->cb];
for (i = 0; i < celt; i++)
{
cbT = (wcslen(adbn[i].pwszName) + 1) * sizeof(WCHAR);
CopyMemory(pbOut, adbn[i].pwszName, cbT);
pteltOut->obwszName = SAFE_SUBTRACT_POINTERS(pbOut, pctbOut->pb);
pbOut += DWORDROUND(cbT);
cbT = SAFE_SUBTRACT_POINTERS(pbOutEnd, pbOut);
hr = prow->GetProperty(
adbn[i].pwszName,
PROPTYPE_STRING |
PROPCALLER_ADMIN |
PROPTABLE_ATTRIBUTE,
&cbT,
pbOut);
_JumpIfError(hr, error, "GetProperty(pbOut)");
CSASSERT(wcslen((WCHAR const *) pbOut) * sizeof(WCHAR) == cbT);
pteltOut->obwszValue = SAFE_SUBTRACT_POINTERS(pbOut, pctbOut->pb);
pbOut += DWORDROUND(cbT + sizeof(WCHAR));
pteltOut++;
}
CSASSERT(pbOut == pbOutEnd);
hr = S_OK;
error:
if (S_OK != hr && NULL != pctbOut->pb)
{
MIDL_user_free(pctbOut->pb);
pctbOut->pb = NULL;
}
CertSrvExitServer(State);
return(hr);
}
HRESULT
CCertAdminD::_EnumExtensions(
IN ICertDBRow *prow,
IN CERTDBNAME *adbn,
IN DWORD celt,
OUT CERTTRANSBLOB *pctbOut) // CoTaskMem*
{
HRESULT hr;
DWORD i;
DWORD cb;
DWORD cbT;
DWORD ExtFlags;
CERTTRANSDBEXTENSION *pteltOut;
BYTE *pbOut;
BYTE *pbOutEnd;
DWORD State = 0;
CSASSERT(NULL == pctbOut->pb);
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
cb = sizeof(*pteltOut) * celt;
for (i = 0; i < celt; i++)
{
cb += (wcslen(adbn[i].pwszName) + 1) * sizeof(WCHAR);
cb = DWORDROUND(cb);
cbT = 0;
hr = prow->GetExtension(
adbn[i].pwszName,
&ExtFlags,
&cbT,
NULL);
_JumpIfError(hr, error, "GetExtension(NULL)");
cb += DWORDROUND(cbT);
}
pctbOut->pb = (BYTE *) MIDL_user_allocate(cb);
if (NULL == pctbOut->pb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "MIDL_user_allocate out data");
}
pctbOut->cb = cb;
pteltOut = (CERTTRANSDBEXTENSION *) pctbOut->pb;
pbOut = (BYTE *) &pteltOut[celt];
pbOutEnd = &pctbOut->pb[pctbOut->cb];
for (i = 0; i < celt; i++)
{
cbT = (wcslen(adbn[i].pwszName) + 1) * sizeof(WCHAR);
CopyMemory(pbOut, adbn[i].pwszName, cbT);
pteltOut->obwszName = SAFE_SUBTRACT_POINTERS(pbOut, pctbOut->pb);
pbOut += DWORDROUND(cbT);
cbT = SAFE_SUBTRACT_POINTERS(pbOutEnd, pbOut);
hr = prow->GetExtension(
adbn[i].pwszName,
(DWORD *) &pteltOut->ExtFlags,
&cbT,
pbOut);
_JumpIfError(hr, error, "GetExtension(pbOut)");
pteltOut->cbValue = cbT;
pteltOut->obValue = SAFE_SUBTRACT_POINTERS(pbOut, pctbOut->pb);
pbOut += DWORDROUND(cbT);
pteltOut++;
}
CSASSERT(pbOut == pbOutEnd);
hr = S_OK;
error:
if (S_OK != hr && NULL != pctbOut->pb)
{
MIDL_user_free(pctbOut->pb);
pctbOut->pb = NULL;
}
CertSrvExitServer(State);
return(hr);
}
STDMETHODIMP
CCertAdminD::EnumAttributesOrExtensions(
IN wchar_t const *pwszAuthority,
IN DWORD RowId,
IN DWORD Flags,
OPTIONAL IN wchar_t const *pwszLast,
IN DWORD celt,
OUT DWORD *pceltFetched,
OUT CERTTRANSBLOB *pctbOut) // CoTaskMem*
{
HRESULT hr;
ICertDBRow *prow = NULL;
IEnumCERTDBNAME *penum = NULL;
DWORD EnumFlags;
CERTDBNAME *adbn = NULL;
DWORD celtFetched;
DWORD i;
DWORD j;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::EnumAttributesOrExtensions(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
DBGPRINT((
DBG_SS_CERTSRVI,
"EnumAttributesOrExtensions(row=%d, flags=0x%x, last=%ws, celt=%d)\n",
RowId,
Flags,
pwszLast,
celt));
__try
{
pctbOut->pb = NULL;
{
CAuditEvent audit(0, g_dwAuditFilter);
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
}
if (0 >= RowId)
{
hr = E_INVALIDARG;
_LeaveError(hr, "RowId");
}
switch (Flags)
{
case CDBENUM_ATTRIBUTES:
EnumFlags = CIE_TABLE_ATTRIBUTES;
break;
case CDBENUM_EXTENSIONS:
EnumFlags = CIE_TABLE_EXTENSIONS;
break;
default:
hr = E_INVALIDARG;
_LeaveError(hr, "Flags");
}
hr = g_pCertDB->OpenRow(
PROPOPEN_READONLY | PROPTABLE_REQCERT,
RowId,
NULL,
&prow);
_LeaveIfError(hr, "OpenRow(RowId)");
hr = prow->EnumCertDBName(EnumFlags, &penum);
_LeaveIfError(hr, "EnumCertDBName");
adbn = (CERTDBNAME *) LocalAlloc(
LMEM_FIXED | LMEM_ZEROINIT,
sizeof(adbn[0]) * celt);
if (NULL == adbn)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "Alloc string pointers");
}
// If specified, skip entries up to and including the last key.
if (NULL != pwszLast)
{
int r;
do
{
hr = penum->Next(1, &adbn[0], &celtFetched);
if (S_FALSE == hr)
{
hr = E_INVALIDARG;
_PrintError(hr, "pwszLast missing");
}
_LeaveIfError(hr, "Next");
r = lstrcmpi(pwszLast, adbn[0].pwszName);
LocalFree(adbn[0].pwszName);
adbn[0].pwszName = NULL;
} while (0 != r);
}
hr = penum->Next(celt, adbn, &celtFetched);
if (S_FALSE != hr)
{
_LeaveIfError(hr, "Next");
}
if (CIE_TABLE_ATTRIBUTES == EnumFlags)
{
hr = _EnumAttributes(prow, adbn, celtFetched, pctbOut);
_LeaveIfError(hr, "_EnumAttributes");
}
else
{
hr = _EnumExtensions(prow, adbn, celtFetched, pctbOut);
_LeaveIfError(hr, "_EnumExtensions");
}
myRegisterMemFree(pctbOut->pb, CSM_MIDLUSERALLOC);
*pceltFetched = celtFetched;
hr = S_OK;
if (celt > celtFetched)
{
hr = S_FALSE;
}
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != adbn)
{
for (i = 0; i < celt; i++)
{
if (NULL != adbn[i].pwszName)
{
MIDL_user_free(adbn[i].pwszName);
}
}
LocalFree(adbn);
}
if (NULL != penum)
{
penum->Release();
}
if (NULL != prow)
{
prow->Release();
}
DBGPRINT((
DBG_SS_CERTSRVI,
"EnumAttributesOrExtensions: celtFetched=%d, hr=%x\n",
*pceltFetched,
hr));
CertSrvExitServer(State);
CSASSERT(S_OK == hr || S_FALSE == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::OpenView(
IN wchar_t const *pwszAuthority,
IN DWORD ccvr,
IN CERTVIEWRESTRICTION const *acvr,
IN DWORD ccolOut,
IN DWORD const *acolOut,
IN DWORD ielt,
IN DWORD celt,
OUT DWORD *pceltFetched,
OUT CERTTRANSBLOB *pctbResultRows) // CoTaskMem*
{
HRESULT hr;
IEnumCERTDBRESULTROW *pview = NULL;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::OpenView(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
DBGPRINT((
DBG_SS_CERTSRVI,
"================================================================\n"));
DBGPRINT((
DBG_SS_CERTSRVI,
"OpenView(ccvr=%d, ccolOut=%d, celt=%d)\n",
ccvr,
ccolOut,
celt));
__try
{
pctbResultRows->pb = NULL;
{
CAuditEvent audit(0, g_dwAuditFilter);
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
}
if (NULL != m_pView)
{
hr = E_UNEXPECTED;
_LeaveError(hr, "Has View");
}
hr = g_pCertDB->OpenView(
ccvr,
acvr,
ccolOut,
acolOut,
CDBOPENVIEW_WORKERTHREAD,
&pview);
_LeaveIfError(hr, "OpenView");
hr = _EnumViewNext(pview, ielt, celt, pceltFetched, pctbResultRows);
if (S_FALSE != hr)
{
_LeaveIfError(hr, "_EnumViewNext");
}
m_pView = pview;
pview = NULL;
myRegisterMemFree(pctbResultRows->pb, CSM_MIDLUSERALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != pview)
{
pview->Release();
}
DBGPRINT((
DBG_SS_CERTSRVI,
"OpenView: celtFetched=%d, hr=%x\n",
*pceltFetched,
hr));
CertSrvExitServer(State);
CSASSERT(S_OK == hr || S_FALSE == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::EnumView(
IN wchar_t const *pwszAuthority,
IN DWORD ielt,
IN DWORD celt,
OUT DWORD *pceltFetched,
OUT CERTTRANSBLOB *pctbResultRows) // CoTaskMem*
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::EnumView(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
DBGPRINT((DBG_SS_CERTSRVI, "EnumView(ielt=%d, celt=%d)\n", ielt, celt));
__try
{
if (NULL == m_pView)
{
hr = E_UNEXPECTED;
_LeaveError(hr, "No View");
}
hr = _EnumViewNext(
m_pView,
ielt,
celt,
pceltFetched,
pctbResultRows);
if (S_FALSE != hr)
{
_LeaveIfError(hr, "_EnumViewNext");
}
myRegisterMemFree(pctbResultRows->pb, CSM_MIDLUSERALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
DBGPRINT((
DBG_SS_CERTSRVI,
"EnumView: celtFetched=%d, hr=%x\n",
*pceltFetched,
hr));
CertSrvExitServer(State);
CSASSERT(S_OK == hr || S_FALSE == hr || FAILED(hr));
return(hr);
}
HRESULT
CCertAdminD::_EnumViewNext(
IN IEnumCERTDBRESULTROW *pview,
IN DWORD ielt,
IN DWORD celt,
OUT DWORD *pceltFetched,
OUT CERTTRANSBLOB *pctbResultRows) // CoTaskMem
{
HRESULT hr;
BOOL fNoMore = FALSE;
BOOL fFetched = FALSE;
DWORD cb;
DWORD cbT;
DWORD cColTotal;
CERTDBRESULTROW *aelt = NULL;
CERTDBRESULTROW *pelt;
CERTDBRESULTROW *peltEnd;
CERTDBRESULTCOLUMN *pcol;
CERTDBRESULTCOLUMN *pcolEnd;
CERTTRANSDBRESULTROW *pteltOut;
CERTTRANSDBRESULTCOLUMN *ptcolOut;
BYTE *pbOut;
DWORD ieltLast;
DWORD State = 0;
if(1<InterlockedIncrement(&m_cNext))
{
hr = E_UNEXPECTED;
_JumpError(hr, error, "Calls from multiple threads on the same view object");
}
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
DBGPRINT((DBG_SS_CERTSRVI, "_EnumViewNext(ielt=%d celt=%d)\n", ielt, celt));
aelt = (CERTDBRESULTROW *) LocalAlloc(LMEM_FIXED, celt * sizeof(aelt[0]));
if (NULL == aelt)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "Alloc result rows");
}
hr = pview->Skip(0, (LONG *) &ieltLast);
_JumpIfError(hr, error, "Skip");
if (ielt != ieltLast + 1)
{
DBGPRINT((
DBG_SS_CERTSRVI, "_EnumViewNext! ieltLast=%d cskip=%d\n",
ieltLast,
ielt - ieltLast));
hr = pview->Skip(ielt - (ieltLast + 1), (LONG *) &ieltLast);
_JumpIfError(hr, error, "Skip");
DBGPRINT((
DBG_SS_CERTSRVI, "_EnumViewNext! ielt after skip=%d\n",
ieltLast));
}
hr = pview->Next(celt, aelt, pceltFetched);
if (S_FALSE == hr)
{
fNoMore = TRUE;
}
else
{
_JumpIfError(hr, error, "Next");
}
fFetched = TRUE;
DBGPRINT((
DBG_SS_CERTSRVI,
"_EnumViewNext! celtFetched=%d\n",
*pceltFetched));
cb = *pceltFetched * sizeof(*pteltOut);
if (fNoMore)
{
cb += sizeof(*pteltOut);
}
cColTotal = 0;
peltEnd = &aelt[*pceltFetched];
for (pelt = aelt; pelt < peltEnd; pelt++)
{
cColTotal += pelt->ccol;
cb += pelt->ccol * sizeof(*ptcolOut);
pcolEnd = &pelt->acol[pelt->ccol];
for (pcol = pelt->acol; pcol < pcolEnd; pcol++)
{
CSASSERT(DWORDROUND(cb) == cb);
if (NULL != pcol->pbValue)
{
if ((DTI_REQUESTTABLE | DTR_REQUESTRAWARCHIVEDKEY) ==
pcol->Index)
{
cb += sizeof(DWORD);
}
else
{
cb += DWORDROUND(pcol->cbValue);
}
}
}
}
pctbResultRows->pb = (BYTE *) MIDL_user_allocate(cb);
if (NULL == pctbResultRows->pb)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "MIDL_user_allocate result rows");
}
pctbResultRows->cb = cb;
ZeroMemory(pctbResultRows->pb, pctbResultRows->cb);
pbOut = pctbResultRows->pb;
DBGPRINT((
DBG_SS_CERTSRVI,
"_EnumViewNext! Result Row data cb=0x%x @%x\n",
pctbResultRows->cb,
pctbResultRows->pb));
for (pelt = aelt; pelt < peltEnd; pelt++)
{
pteltOut = (CERTTRANSDBRESULTROW *) pbOut;
pbOut += sizeof(*pteltOut);
ptcolOut = (CERTTRANSDBRESULTCOLUMN *) pbOut;
pbOut += pelt->ccol * sizeof(*ptcolOut);
pteltOut->rowid = pelt->rowid;
pteltOut->ccol = pelt->ccol;
pcolEnd = &pelt->acol[pelt->ccol];
for (pcol = pelt->acol; pcol < pcolEnd; pcol++, ptcolOut++)
{
ptcolOut->Type = pcol->Type;
ptcolOut->Index = pcol->Index;
if (NULL != pcol->pbValue)
{
if ((DTI_REQUESTTABLE | DTR_REQUESTRAWARCHIVEDKEY) ==
ptcolOut->Index)
{
cbT = sizeof(BYTE);
CSASSERT(0 == *(DWORD *) pbOut);
}
else
{
cbT = pcol->cbValue;
CopyMemory(pbOut, pcol->pbValue, cbT);
}
ptcolOut->cbValue = cbT;
ptcolOut->obValue = SAFE_SUBTRACT_POINTERS(pbOut, (BYTE *) pteltOut);
pbOut += DWORDROUND(cbT);
}
}
pteltOut->cbrow = SAFE_SUBTRACT_POINTERS(pbOut, (BYTE *) pteltOut);
}
// if past the end or at end of rowset, write an extra record containimg
// the maximum element count.
if (fNoMore)
{
pteltOut = (CERTTRANSDBRESULTROW *) pbOut;
pbOut += sizeof(*pteltOut);
pteltOut->rowid = pelt->rowid;
pteltOut->ccol = pelt->ccol;
pteltOut->cbrow = SAFE_SUBTRACT_POINTERS(pbOut, (BYTE *) pteltOut);
CSASSERT(pteltOut->rowid == ~pteltOut->ccol);
DBGPRINT((
DBG_SS_CERTSRVI,
"_EnumViewNext! celtMax=%d\n",
pteltOut->rowid));
}
DBGPRINT((
DBG_SS_CERTSRVI,
"_EnumViewNext! pbOut=%x/%x\n",
pbOut,
&pctbResultRows->pb[pctbResultRows->cb]));
CSASSERT(&pctbResultRows->pb[pctbResultRows->cb] == pbOut);
if (fNoMore)
{
hr = S_FALSE;
}
error:
DBGPRINT((
DBG_SS_CERTSRVI,
"_EnumViewNext: celtFetched=%d, hr=%x\n",
*pceltFetched,
hr));
if (fFetched)
{
HRESULT hr2;
hr2 = pview->ReleaseResultRow(*pceltFetched, aelt);
_PrintIfError(hr2, "ReleaseResultRow");
}
if (NULL != aelt)
{
LocalFree(aelt);
}
CertSrvExitServer(State);
InterlockedDecrement(&m_cNext);
return(hr);
}
STDMETHODIMP
CCertAdminD::CloseView(
IN wchar_t const *pwszAuthority)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::CloseView(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
if (NULL == m_pView)
{
hr = E_UNEXPECTED;
_LeaveError(hr, "No View");
}
m_pView->Release();
m_pView = NULL;
hr = S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::RevokeCertificate(
/* [unique][in] */ USHORT const __RPC_FAR *pwszAuthority,
/* [in, string, unique] */ USHORT const __RPC_FAR *pwszSerialNumber,
/* [in] */ DWORD Reason,
/* [in] */ FILETIME FileTime)
{
HRESULT hr;
DWORD ReqId;
DWORD cbProp;
DWORD Disposition;
DWORD OldReason;
ICertDBRow *prow = NULL;
WCHAR const *pwszDisposition = NULL;
WCHAR const *pwszDispT;
BOOL fUnRevoke = FALSE;
BOOL fRevokeOnHold = FALSE;
WCHAR *pwszUserName = NULL;
CAuditEvent audit(SE_AUDITID_CERTSRV_REVOKECERT, g_dwAuditFilter);
LPWSTR pwszRequesterName = NULL;
DWORD State = 0;
BOOL fCommitted = FALSE;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::RevokeCertificate(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 = audit.AddData(pwszSerialNumber); // %1 serial no.
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.AddData(Reason); // %2 reason
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.AccessCheck(
CA_ACCESS_OFFICER,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
switch (Reason)
{
case MAXDWORD:
fUnRevoke = TRUE;
break;
case CRL_REASON_CERTIFICATE_HOLD:
fRevokeOnHold = TRUE;
break;
case CRL_REASON_UNSPECIFIED:
case CRL_REASON_KEY_COMPROMISE:
case CRL_REASON_CA_COMPROMISE:
case CRL_REASON_AFFILIATION_CHANGED:
case CRL_REASON_SUPERSEDED:
case CRL_REASON_CESSATION_OF_OPERATION:
case CRL_REASON_REMOVE_FROM_CRL:
break;
default:
hr = E_INVALIDARG;
_LeaveError(hr, "Reason parameter");
}
hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, pwszSerialNumber, &prow);
if (S_OK != hr)
{
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
hr = E_INVALIDARG; // Invalid Serial Number
}
_LeaveErrorStr(hr, "OpenRow", pwszSerialNumber);
}
hr = PKCSGetProperty(
prow,
g_wszPropRequesterName,
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
NULL,
(BYTE **) &pwszRequesterName);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_LeaveIfErrorStr(hr, "PKCSGetProperty", g_wszPropRequesterName);
}
hr = CheckOfficerRights(pwszRequesterName, audit);
_LeaveIfError(hr, "CheckOfficerRights");
cbProp = sizeof(Disposition);
hr = prow->GetProperty(
g_wszPropRequestDisposition,
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
&cbProp,
(BYTE *) &Disposition);
_LeaveIfError(hr, "GetProperty");
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
switch (Disposition)
{
HRESULT hr2;
case DB_DISP_CA_CERT:
if (!IsRootCA(g_CAType))
{
_LeaveError(hr, "non-root CA");
}
// FALLTHROUGH
case DB_DISP_ISSUED:
case DB_DISP_REVOKED:
cbProp = sizeof(OldReason);
hr2 = prow->GetProperty(
g_wszPropRequestRevokedReason,
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
&cbProp,
(BYTE *) &OldReason);
// Converted MDB databases have UNrevoked rows' RevokedReason
// column set to zero (CRL_REASON_UNSPECIFIED).
if (S_OK != hr2 ||
(DB_DISP_ISSUED == Disposition &&
CRL_REASON_UNSPECIFIED == OldReason))
{
OldReason = MAXDWORD;
}
if (fRevokeOnHold &&
MAXDWORD != OldReason &&
CRL_REASON_CERTIFICATE_HOLD != OldReason)
{
_LeaveError(hr, "already revoked: not on hold");
}
if (fUnRevoke && CRL_REASON_CERTIFICATE_HOLD != OldReason)
{
_LeaveError(hr, "unrevoke: not on hold");
}
break;
default:
_LeaveError(hr, "invalid disposition");
}
hr = PropSetRequestTimeProperty(prow, g_wszPropRequestRevokedWhen);
if (S_OK != hr)
{
hr = myHError(hr);
_LeaveError(hr, "PropSetRequestTimeProperty");
}
hr = prow->SetProperty(
g_wszPropRequestRevokedEffectiveWhen,
PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST,
sizeof(FileTime),
(BYTE const *) &FileTime);
_LeaveIfError(hr, "SetProperty");
hr = prow->SetProperty(
g_wszPropRequestRevokedReason,
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
sizeof(Reason),
(BYTE const *) &Reason);
_LeaveIfError(hr, "SetProperty");
hr = GetClientUserName(NULL, &pwszUserName, NULL);
_LeaveIfError(hr, "GetClientUserName");
pwszDispT = fUnRevoke? g_pwszUnrevokedBy : g_pwszRevokedBy;
pwszDisposition = CoreBuildDispositionString(
pwszDispT,
pwszUserName,
NULL,
NULL,
S_OK,
FALSE);
if (NULL == pwszDisposition)
{
pwszDisposition = pwszDispT;
}
hr = prow->SetProperty(
g_wszPropRequestDispositionMessage,
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
MAXDWORD,
(BYTE const *) pwszDisposition);
_LeaveIfError(hr, "SetProperty");
if (DB_DISP_CA_CERT != Disposition)
{
Disposition = fUnRevoke? DB_DISP_ISSUED : DB_DISP_REVOKED;
hr = prow->SetProperty(
g_wszPropRequestDisposition,
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
sizeof(Disposition),
(BYTE const *) &Disposition);
_LeaveIfError(hr, "SetProperty");
}
hr = prow->CommitTransaction(TRUE);
_LeaveIfError(hr, "CommitTransaction");
fCommitted = TRUE;
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
prow->GetRowId(&ReqId);
ExitNotify(EXITEVENT_CERTREVOKED, ReqId, MAXDWORD);
CoreLogRequestStatus(
prow,
MSG_DN_CERT_REVOKED,
hr,
pwszDisposition);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != pwszUserName)
{
LocalFree(pwszUserName);
}
if (NULL != pwszRequesterName)
{
LocalFree(pwszRequesterName);
}
if (NULL != pwszDisposition && pwszDisposition != g_pwszRevokedBy)
{
LocalFree(const_cast<WCHAR *>(pwszDisposition));
}
if (NULL != prow)
{
if (S_OK != hr && !fCommitted)
{
HRESULT hr2 = prow->CommitTransaction(FALSE);
_PrintIfError(hr2, "CommitTransaction");
}
prow->Release();
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::IsValidCertificate(
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszAuthority,
/* [unique][string][in] */ const wchar_t __RPC_FAR *pwszSerialNumber,
/* [out] */ LONG __RPC_FAR *pRevocationReason,
/* [out] */ LONG __RPC_FAR *pDisposition)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::IsValidCertificate(tid=%d, this=%x, serial=%ws)\n",
GetCurrentThreadId(),
this,
pwszSerialNumber));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
CAuditEvent audit(0, g_dwAuditFilter);
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = PKCSIsRevoked(
0,
pwszSerialNumber,
pRevocationReason,
pDisposition);
_LeaveIfError(hr, "PKCSIsRevoked");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
DBGPRINT((
s_ssAdmin,
"CCertAdminD::IsValidCertificate(serial=%ws) --> %x, Reason=%u Disposition=%u\n",
pwszSerialNumber,
hr,
*pRevocationReason,
*pDisposition));
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::ServerControl(
IN wchar_t const *pwszAuthority,
IN DWORD dwControlFlags,
OUT CERTTRANSBLOB *pctbOut)
{
HRESULT hr;
BOOL fBackupAccess = FALSE;
CAuditEvent audit(SE_AUDITID_CERTSRV_SHUTDOWN, g_dwAuditFilter);
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::ServerControl(tid=%d, this=%x, Flags=0x%x)\n",
GetCurrentThreadId(),
this,
dwControlFlags));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority, true); //allow empty name
_JumpIfError(hr, error, "CheckAuthorityName");
switch (dwControlFlags)
{
case CSCONTROL_SUSPEND:
case CSCONTROL_RESTART:
fBackupAccess = TRUE;
break;
case CSCONTROL_SHUTDOWN:
break;
default:
hr = E_INVALIDARG;
_JumpError(hr, error, "bad control flags");
}
__try
{
hr = audit.AccessCheck(
fBackupAccess?CA_ACCESS_OPERATOR:CA_ACCESS_ADMIN,
audit.m_gcAuditSuccessOrFailure);
_LeaveIfError(
hr,
fBackupAccess?
"CAuditEvent::AccessCheck backup":
"CAuditEvent::AccessCheck admin");
switch (dwControlFlags)
{
case CSCONTROL_SHUTDOWN:
myRegisterMemFree(this, CSM_NEW | CSM_GLOBALDESTRUCTOR);
hr = CertSrvLockServer(&State);
_JumpIfError(hr, error, "CertSrvLockServer");
// have message loop run shutdown code
SendMessage(g_hwndMain, WM_STOPSERVER, 0, 0);
// post, don't wait for shutdown
PostMessage(g_hwndMain, WM_SYNC_CLOSING_THREADS, 0, 0);
break;
}
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
CCertAdminD::_Ping(
IN WCHAR const *pwszAuthority)
{
HRESULT hr;
DWORD State = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority, true); //allow empty name
_JumpIfError(hr, error, "CheckAuthorityName");
__try
{
CAuditEvent audit(0, g_dwAuditFilter);
hr = audit.AccessCheck(
CA_ACCESS_ADMIN,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
myRegisterMemDump();
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::Ping(
IN WCHAR const *pwszAuthority)
{
HRESULT hr;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::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
CCertAdminD::Ping2(
IN WCHAR const *pwszAuthority)
{
HRESULT hr;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::Ping2(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = _Ping(pwszAuthority);
_JumpIfError(hr, error, "_Ping");
error:
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::GetServerState(
IN WCHAR const *pwszAuthority,
OUT DWORD *pdwState)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::GetServerState(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority, true); //allow empty name
_JumpIfError(hr, error, "CheckAuthorityName");
__try
{
*pdwState = 0;
{
CAuditEvent audit(0, g_dwAuditFilter);
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
}
*pdwState = 1;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupPrepare(
IN WCHAR const *pwszAuthority,
IN unsigned long grbitJet,
IN unsigned long dwBackupFlags,
IN WCHAR const *pwszBackupAnnotation,
IN DWORD dwClientIdentifier)
{
HRESULT hr;
CertSrv::CAuditEvent audit(SE_AUDITID_CERTSRV_BACKUPSTART,g_dwAuditFilter);
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupPrepare(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority, true); //allow empty name
_JumpIfError(hr, error, "CheckAuthorityName");
__try
{
hr = audit.AddData(dwBackupFlags); //%1 backup type
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.AccessCheck(
CA_ACCESS_OPERATOR,
audit.m_gcAuditSuccessOrFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
if (NULL != m_pBackup)
{
hr = E_UNEXPECTED;
_LeaveError(hr, "Has Backup");
}
hr = g_pCertDB->OpenBackup(grbitJet, &m_pBackup);
_LeaveIfError(hr, "OpenBackup");
m_grbitBackup = grbitJet;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupEnd()
{
HRESULT hr;
CertSrv::CAuditEvent audit(SE_AUDITID_CERTSRV_BACKUPEND,g_dwAuditFilter);
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupEnd(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
hr = audit.AccessCheck(
CA_ACCESS_OPERATOR,
audit.m_gcAuditSuccessOrFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
if (NULL == m_pBackup)
{
hr = E_UNEXPECTED;
_LeaveError(hr, "No backup");
}
m_pBackup->Release();
m_pBackup = NULL;
hr = S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
HRESULT
CCertAdminD::_GetDynamicFileList(
IN OUT DWORD *pcwcList,
OPTIONAL OUT WCHAR *pwszzList)
{
HRESULT hr = S_OK;
HRESULT hr2;
DWORD iCert;
DWORD iDelta;
DWORD iDeltaMax;
DWORD cwc;
DWORD cwcRemain;
DWORD cwcTotal;
WCHAR const * const *papwszSrc;
WCHAR const * const *ppwsz;
DWORD State = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
cwcRemain = *pcwcList;
cwcTotal = 0;
iDeltaMax = g_fDeltaCRLPublishDisabled? 0 : 1;
for (iCert = 0; iCert < g_cCACerts; iCert++)
{
for (iDelta = 0; iDelta <= iDeltaMax; iDelta++)
{
hr2 = PKCSGetCRLList(0 != iDelta, iCert, &papwszSrc);
if (S_OK != hr2)
{
_PrintError2(hr2, "PKCSGetCRLList", hr2);
continue;
}
for (ppwsz = papwszSrc; NULL != *ppwsz; ppwsz++)
{
WCHAR const *pwsz = *ppwsz;
// Just return local full path files:
if (iswalpha(pwsz[0]) && L':' == pwsz[1] && L'\\' == pwsz[2])
{
cwc = wcslen(pwsz) + 1;
if (NULL != pwszzList)
{
DWORD cwcT;
cwcT = min(cwc, cwcRemain);
CopyMemory(pwszzList, *ppwsz, cwcT * sizeof(WCHAR));
pwszzList += cwcT;
if (cwc > cwcT)
{
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
pwszzList = NULL;
}
cwcRemain -= cwcT;
}
cwcTotal += cwc;
}
}
}
}
// append an extra trailing L'\0'
if (NULL != pwszzList)
{
if (1 <= cwcRemain)
{
*pwszzList = L'\0';
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
}
}
cwcTotal++;
*pcwcList = cwcTotal;
_JumpIfError(hr, error, "Buffer Overflow");
error:
CertSrvExitServer(State);
return(hr);
}
typedef struct _DBTAG
{
WCHAR const *pwszPath;
WCHAR wcFileType;
} DBTAG;
DBTAG g_adbtag[] = {
{ g_wszDatabase, CSBFT_CERTSERVER_DATABASE },
{ g_wszLogDir, CSBFT_LOG_DIR },
{ g_wszSystemDir, CSBFT_CHECKPOINT_DIR },
};
CSBFT
BftClassify(
IN WCHAR const *pwszFileName)
{
WCHAR *pwszPath = NULL;
WCHAR const *pwszExt;
WCHAR *pwsz;
DWORD i;
CSBFT bft;
// Do the easy cases first.
pwszExt = wcsrchr(pwszFileName, L'.');
if (NULL != pwszExt)
{
if (0 == lstrcmpi(pwszExt, L".pat"))
{
bft = CSBFT_PATCH_FILE;
goto done;
}
if (0 == lstrcmpi(pwszExt, L".log"))
{
bft = CSBFT_LOG;
goto done;
}
if (0 == lstrcmpi(pwszExt, L".edb"))
{
// It's a database. Find out which database it is.
for (i = 0; i < ARRAYSIZE(g_adbtag); i++)
{
bft = g_adbtag[i].wcFileType;
if ((bft & CSBFT_DATABASE_DIRECTORY) &&
0 == lstrcmpi(g_adbtag[i].pwszPath, pwszFileName))
{
goto done;
}
}
}
}
// Ok, I give up. We don't know anything about this file at all;
// try to figure out what we can tell the caller about it.
pwszPath = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwszFileName) + 1) * sizeof(WCHAR));
if (NULL != pwszPath)
{
wcscpy(pwszPath, pwszFileName);
pwsz = wcsrchr(pwszPath, L'\\');
if (NULL != pwsz)
{
*pwsz = L'\0'; // truncate to directory path
}
for (i = 0; i < ARRAYSIZE(g_adbtag); i++)
{
bft = g_adbtag[i].wcFileType;
if (bft & CSBFT_DIRECTORY)
{
// If this file's directory matches the directory we're
// looking at, we know where it needs to go on the restore.
if (0 == lstrcmpi(g_adbtag[i].pwszPath, pwszPath))
{
goto done;
}
}
}
}
bft = CSBFT_UNKNOWN;
done:
if (NULL != pwszPath)
{
LocalFree(pwszPath);
}
return(bft);
}
HRESULT
CCertAdminD::_GetDatabaseLocations(
IN OUT DWORD *pcwcList,
OPTIONAL OUT WCHAR *pwszzList)
{
HRESULT hr = S_OK;
DWORD cwc;
DWORD cwcRemain;
WCHAR *pwcRemain;
DWORD i;
DWORD State = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
cwcRemain = *pcwcList;
pwcRemain = pwszzList;
cwc = 1;
for (i = 0; i < ARRAYSIZE(g_adbtag); i++)
{
DWORD cwcT;
cwcT = wcslen(g_adbtag[i].pwszPath) + 1;
cwc += 1 + cwcT;
if (NULL != pwcRemain && 0 < cwcRemain)
{
*pwcRemain++ = g_adbtag[i].wcFileType;
cwcRemain--;
if (cwcT > cwcRemain)
{
cwcT = cwcRemain;
}
CopyMemory(pwcRemain, g_adbtag[i].pwszPath, cwcT * sizeof(WCHAR));
pwcRemain += cwcT;
cwcRemain -= cwcT;
}
}
if (NULL != pwcRemain)
{
if (0 < cwcRemain)
{
*pwcRemain = L'\0';
}
if (cwc > *pcwcList)
{
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
}
}
*pcwcList = cwc;
_JumpIfError(hr, error, "Buffer Overflow");
error:
CertSrvExitServer(State);
return(hr);
}
STDMETHODIMP
CCertAdminD::RestoreGetDatabaseLocations(
OUT WCHAR **ppwszDatabaseLocations,
OUT LONG *pcwcPaths)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::RestoreGetDatabaseLocations(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
hr = _BackupGetFileList(MAXDWORD, ppwszDatabaseLocations, pcwcPaths);
_LeaveIfError(hr, "_BackupGetFileList");
myRegisterMemFree(*ppwszDatabaseLocations, CSM_MIDLUSERALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
// Convert UNC path to local full path, as in:
// \\server\c$\foo... --> c:\foo...
// Note the server name need not match the current server name.
HRESULT
ConvertUNCToLocalPath(
IN WCHAR const *pwszPath,
OUT WCHAR **ppwszPathLocal) // LocalAlloc
{
HRESULT hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
WCHAR const *pwc;
*ppwszPathLocal = NULL;
if (L'\\' != pwszPath[0] || L'\\' != pwszPath[1])
{
_JumpError(hr, error, "not a UNC path");
}
pwc = wcschr(&pwszPath[2], L'\\');
if (NULL == pwc || !iswalpha(pwc[1]) || L'$' != pwc[2] || L'\\' != pwc[3])
{
_JumpError(hr, error, "bad-UNC path");
}
pwc++;
*ppwszPathLocal = (WCHAR *) LocalAlloc(
LMEM_FIXED,
(wcslen(pwc) + 1) * sizeof(WCHAR));
if (NULL == *ppwszPathLocal)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc");
}
wcscpy(*ppwszPathLocal, pwc);
CSASSERT(L'$' == (*ppwszPathLocal)[1]);
(*ppwszPathLocal)[1] = L':';
hr = S_OK;
error:
return(hr);
}
// Convert local possibly annotated full paths to possibly annotated UNC, as:
// [CSBFT_*]c:\foo... --> [CSBFT_*]\\server\c$\foo...
HRESULT
ConvertLocalPathsToMungedUNC(
IN WCHAR const *pwszzFiles,
IN BOOL fAnnotated, // TRUE if already annotated
IN WCHAR wcFileType, // else Annotation WCHAR (if not L'\0')
OUT DWORD *pcwc,
OUT WCHAR **ppwszzFilesUNC) // MIDL_user_allocate
{
HRESULT hr;
DWORD cwc;
WCHAR const *pwsz;
WCHAR *pwszDst;
DWORD cfiles = 0;
WCHAR *pwszzFilesUNC = NULL;
*pcwc = 0;
for (pwsz = pwszzFiles; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
if (fAnnotated)
{
pwsz++;
}
if (!iswalpha(pwsz[0]) || L':' != pwsz[1] || L'\\' != pwsz[2])
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_JumpError(hr, error, "non-local path");
}
cfiles++;
}
cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszzFiles) + 1;
cwc += cfiles * (2 + wcslen(g_pwszServerName) + 1);
if (!fAnnotated && 0 != wcFileType)
{
cwc += cfiles; // Add munged CSBFT_* character
}
pwszzFilesUNC = (WCHAR *) MIDL_user_allocate(cwc * sizeof(WCHAR));
if (NULL == pwszzFilesUNC)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "MIDL_user_allocate pwszzFiles");
}
pwszDst = pwszzFilesUNC;
for (pwsz = pwszzFiles; L'\0' != *pwsz; pwsz += wcslen(pwsz) + 1)
{
if (fAnnotated)
{
*pwszDst++ = *pwsz++; // "CSBFT"
}
else
if (0 != wcFileType)
{
*pwszDst++ = BftClassify(pwsz); // "CSBFT"
}
wcscpy(pwszDst, L"\\\\"); // "[CSBFT]\\"
wcscat(pwszDst, g_pwszServerName); // "[CSBFT]\\server"
pwszDst += wcslen(pwszDst);
*pwszDst++ = L'\\'; // "[CSBFT]\\server\"
*pwszDst++ = *pwsz++; // "[CSBFT]\\server\c"
*pwszDst++ = L'$'; // "[CSBFT]\\server\c$"
pwsz++; // skip colon
wcscpy(pwszDst, pwsz); // "[CSBFT]\\server\c$\foo..."
pwszDst += wcslen(pwszDst) + 1;
}
*pwszDst = L'\0';
CSASSERT(SAFE_SUBTRACT_POINTERS(pwszDst, pwszzFilesUNC) + 1 == cwc);
*pcwc = cwc;
*ppwszzFilesUNC = pwszzFilesUNC;
hr = S_OK;
error:
return(hr);
}
HRESULT
CCertAdminD::_BackupGetFileList(
IN DWORD dwFileType,
OUT WCHAR **ppwszzFiles, // CoTaskMem*
OUT LONG *pcwcFiles)
{
HRESULT hr;
WCHAR *pwszzFiles = NULL;
WCHAR *pwszzFilesUNC = NULL;
DWORD cwcFiles = 0;
DWORD cwc;
BOOL fAnnotated = FALSE;
DWORD State = 0;
*ppwszzFiles = NULL;
*pcwcFiles = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
if (NULL == m_pBackup && MAXDWORD != dwFileType && 0 != dwFileType)
{
hr = E_UNEXPECTED;
_JumpIfError(hr, error, "No backup");
}
while (TRUE)
{
cwc = cwcFiles;
if (CSBFT_CERTSERVER_DATABASE == dwFileType)
{
hr = m_pBackup->GetDBFileList(&cwc, pwszzFiles);
_JumpIfError(hr, error, "GetDBFileList");
}
else if (CSBFT_LOG == dwFileType)
{
hr = m_pBackup->GetLogFileList(&cwc, pwszzFiles);
_JumpIfError(hr, error, "GetLogFileList");
}
else if (MAXDWORD == dwFileType)
{
hr = _GetDatabaseLocations(&cwc, pwszzFiles);
_JumpIfError(hr, error, "_GetDatabaseLocations");
fAnnotated = TRUE;
}
else if (0 == dwFileType)
{
hr = _GetDynamicFileList(&cwc, pwszzFiles);
_JumpIfError(hr, error, "_GetDynamicFileList");
}
else
{
CSASSERT(!"bad FileListtype");
}
if (NULL != pwszzFiles)
{
break;
}
pwszzFiles = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
if (NULL == pwszzFiles)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "LocalAlloc pwszzFiles");
}
cwcFiles = cwc;
}
hr = ConvertLocalPathsToMungedUNC(
pwszzFiles,
fAnnotated,
(WCHAR) dwFileType,
&cwc,
&pwszzFilesUNC);
_JumpIfError(hr, error, "ConvertLocalPathsToMungedUNC");
*ppwszzFiles = pwszzFilesUNC;
*pcwcFiles = cwc;
pwszzFilesUNC = NULL;
error:
if (NULL != pwszzFilesUNC)
{
MIDL_user_free(pwszzFilesUNC);
}
if (NULL != pwszzFiles)
{
LocalFree(pwszzFiles);
}
CertSrvExitServer(State);
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupGetAttachmentInformation(
OUT WCHAR **ppwszzDBFiles,
OUT LONG *pcwcDBFiles)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupGetAttachmentInformation(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
hr = _BackupGetFileList(
CSBFT_CERTSERVER_DATABASE,
ppwszzDBFiles,
pcwcDBFiles);
_LeaveIfError(hr, "_BackupGetFileList");
myRegisterMemFree(*ppwszzDBFiles, CSM_MIDLUSERALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupGetBackupLogs(
OUT WCHAR **ppwszzLogFiles,
OUT LONG *pcwcLogFiles)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupGetBackupLogs(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
hr = _BackupGetFileList(CSBFT_LOG, ppwszzLogFiles, pcwcLogFiles);
_LeaveIfError(hr, "_BackupGetFileList");
myRegisterMemFree(*ppwszzLogFiles, CSM_MIDLUSERALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupGetDynamicFiles(
OUT WCHAR **ppwszzFiles,
OUT LONG *pcwcFiles)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupGetDynamicFiles(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
hr = _BackupGetFileList(0, ppwszzFiles, pcwcFiles);
_LeaveIfError(hr, "_BackupGetFileList");
myRegisterMemFree(*ppwszzFiles, CSM_MIDLUSERALLOC);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupOpenFile(
IN WCHAR const *pwszPath,
OUT unsigned hyper *pliLength)
{
HRESULT hr;
WCHAR *pwszPathLocal = NULL;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupOpenFile(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
if (NULL == m_pBackup)
{
hr = E_UNEXPECTED;
_LeaveIfError(hr, "No backup");
}
hr = ConvertUNCToLocalPath(pwszPath, &pwszPathLocal);
_LeaveIfError(hr, "ConvertUNCToLocalPath");
hr = m_pBackup->OpenFile(pwszPathLocal, (ULARGE_INTEGER *) pliLength);
_LeaveIfError(hr, "OpenFile");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
if (NULL != pwszPathLocal)
{
LocalFree(pwszPathLocal);
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupReadFile(
OUT BYTE *pbBuffer,
IN LONG cbBuffer,
OUT LONG *pcbRead)
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupReadFile(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
if (NULL == m_pBackup)
{
hr = E_UNEXPECTED;
_LeaveIfError(hr, "No backup");
}
*pcbRead = cbBuffer;
hr = m_pBackup->ReadFile((DWORD *) pcbRead, pbBuffer);
_LeaveIfError(hr, "ReadFile");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupCloseFile()
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupCloseFile(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
if (NULL == m_pBackup)
{
hr = E_UNEXPECTED;
_LeaveIfError(hr, "No backup");
}
hr = m_pBackup->CloseFile();
_LeaveIfError(hr, "CloseFile");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::BackupTruncateLogs()
{
HRESULT hr;
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::BackupTruncateLogs(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
__try
{
WCHAR *apwsz[1];
if (NULL == m_pBackup)
{
hr = E_UNEXPECTED;
_LeaveIfError(hr, "No backup");
}
hr = m_pBackup->TruncateLog();
_LeaveIfError(hr, "TruncateLog");
apwsz[0] = wszREGDBLASTINCREMENTALBACKUP;
hr = CertSrvSetRegistryFileTimeValue(
TRUE,
(JET_bitBackupIncremental & m_grbitBackup)?
wszREGDBLASTINCREMENTALBACKUP :
wszREGDBLASTFULLBACKUP,
(DWORD)((JET_bitBackupIncremental & m_grbitBackup)?
0 : ARRAYSIZE(apwsz)),
apwsz);
_PrintIfError(hr, "CertSrvSetRegistryFileTimeValue");
hr = S_OK;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::ImportCertificate(
IN wchar_t const *pwszAuthority,
IN CERTTRANSBLOB *pctbCertificate,
IN LONG Flags,
OUT LONG *pRequestId)
{
HRESULT hr;
ICertDBRow *prow = NULL;
CERT_CONTEXT const *pCert = NULL;
WCHAR *pwszUserName = NULL;
BOOL fAllowed = FALSE;
CACTX *pCAContext;
CAuditEvent audit(SE_AUDITID_CERTSRV_IMPORTCERT, g_dwAuditFilter);
DWORD State = 0;
BOOL fCommitted = FALSE;
DWORD Disposition;
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
DWORD cbHash;
BSTR strHash = NULL;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::ImportCertificate(tid=%d, this=%x, cb=%x)\n",
GetCurrentThreadId(),
this,
pctbCertificate->cb));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
if (~(ICF_ALLOWFOREIGN | CR_IN_ENCODEMASK) & Flags)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "Flags");
}
if ((ICF_ALLOWFOREIGN & Flags) &&
0 == (KRAF_ENABLEFOREIGN & g_KRAFlags))
{
hr = E_INVALIDARG;
_JumpError(hr, error, "Foreign disabled");
}
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
hr = audit.AddData(
pctbCertificate->pb,
pctbCertificate->cb); // %1 Certificate
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.AddData((DWORD)0); // %2 dummy request ID, if access check fails
// and a deny event is generated, we need the
// right number of audit arguments
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.AccessCheck(
CA_ACCESS_OFFICER,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
pCert = CertCreateCertificateContext(
X509_ASN_ENCODING,
pctbCertificate->pb,
pctbCertificate->cb);
if (NULL == pCert)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_LeaveError(hr, "CertCreateCertificateContext");
}
// Be sure we issued this certificate before adding it to the database.
Disposition = DB_DISP_ISSUED;
hr = PKCSVerifyIssuedCertificate(pCert, &pCAContext);
if (S_OK != hr)
{
_PrintError2(hr, "PKCSVerifyIssuedCertificate", NTE_BAD_SIGNATURE);
if (0 == (ICF_ALLOWFOREIGN & Flags))
{
_LeaveError2(
hr,
"PKCSVerifyIssuedCertificate",
NTE_BAD_SIGNATURE);
}
Disposition = DB_DISP_FOREIGN;
pCAContext = NULL;
}
cbHash = sizeof(abHash);
if (!CertGetCertificateContextProperty(
pCert,
CERT_SHA1_HASH_PROP_ID,
abHash,
&cbHash))
{
hr = myHLastError();
_LeaveError(hr, "CertGetCertificateContextProperty");
}
hr = MultiByteIntegerToBstr(TRUE, cbHash, abHash, &strHash);
_LeaveIfError(hr, "MultiByteIntegerToBstr");
hr = g_pCertDB->OpenRow(
PROPOPEN_READONLY |
PROPOPEN_CERTHASH |
PROPTABLE_REQCERT,
0, // RequestId
strHash,
&prow);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_LeaveIfErrorStr(hr, "OpenRow", strHash);
fCommitted = TRUE; // open for read-only: skip rollback
hr = HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS);
_LeaveErrorStr2(
hr,
"Cert exists",
strHash,
HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS));
}
// okay, we've got valid data. Time to write to the Database.
hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, NULL, &prow);
_LeaveIfError(hr, "OpenRow");
// set request id
hr = prow->GetRowId((DWORD *) pRequestId);
_LeaveIfError(hr, "GetRowId");
hr = GetClientUserName(NULL, &pwszUserName, NULL);
_LeaveIfError(hr, "GetClientUserName");
hr = prow->SetProperty(
g_wszPropRequesterName,
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
MAXDWORD,
(BYTE const *) pwszUserName);
_LeaveIfError(hr, "SetProperty(requester)");
hr = prow->SetProperty(
g_wszPropCallerName,
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
MAXDWORD,
(BYTE const *) pwszUserName);
_LeaveIfError(hr, "SetProperty(caller)");
hr = PKCSParseImportedCertificate(
Disposition,
prow,
pCAContext,
pCert);
_LeaveIfError(hr, "PKCSParseImportedCertificate");
hr = prow->CommitTransaction(TRUE);
_LeaveIfError(hr, "CommitTransaction");
fCommitted = TRUE;
audit.DeleteLastData(); // remove dummy request ID added above
hr = audit.AddData((DWORD) *pRequestId); // %2 request ID
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != strHash)
{
SysFreeString(strHash);
}
if (NULL != pwszUserName)
{
LocalFree(pwszUserName);
}
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != prow)
{
if (S_OK != hr && !fCommitted)
{
HRESULT hr2 = prow->CommitTransaction(FALSE);
_PrintIfError(hr2, "CommitTransaction");
}
prow->Release();
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::ImportKey(
IN wchar_t const *pwszAuthority,
IN DWORD RequestId,
IN wchar_t const *pwszCertHash,
IN DWORD Flags,
IN CERTTRANSBLOB *pctbKey)
{
HRESULT hr;
ICertDBRow *prow = NULL;
CAuditEvent audit(SE_AUDITID_CERTSRV_IMPORTKEY, g_dwAuditFilter);
DWORD State = 0;
BOOL fCommitted = FALSE;
BYTE *pbCert = NULL;
DWORD cbCert;
CERT_CONTEXT const *pCert = NULL;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::ImportKey(tid=%d, this=%x, cb=%x)\n",
GetCurrentThreadId(),
this,
pctbKey->cb));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
if (~(IKF_OVERWRITE | CR_IN_ENCODEMASK) & Flags)
{
hr = E_INVALIDARG;
_JumpError(hr, error, "Flags");
}
__try
{
CRYPT_ATTR_BLOB BlobEncrypted;
DWORD cb;
hr = audit.AddData(RequestId); // %1 request ID
_LeaveIfError(hr, "AddData");
hr = audit.AccessCheck(
CA_ACCESS_OFFICER,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
if (MAXDWORD == RequestId)
{
RequestId = 0;
}
if (0 == RequestId && NULL == pwszCertHash)
{
hr = E_INVALIDARG;
_LeaveError(hr, "pwszCertHash NULL");
}
hr = g_pCertDB->OpenRow(
PROPTABLE_REQCERT |
(NULL != pwszCertHash? PROPOPEN_CERTHASH : 0),
RequestId,
pwszCertHash,
&prow);
_LeaveIfErrorStr(hr, "OpenRow", pwszCertHash);
BlobEncrypted.cbData = pctbKey->cb;
BlobEncrypted.pbData = pctbKey->pb;
cb = 0;
hr = prow->GetProperty(
g_wszPropRequestRawArchivedKey,
PROPTYPE_BINARY |
PROPCALLER_SERVER |
PROPTABLE_REQUEST,
&cb,
NULL);
if (CERTSRV_E_PROPERTY_EMPTY != hr)
{
_LeaveIfErrorStr(hr, "OpenRow", pwszCertHash);
}
hr = PKCSGetProperty(
prow,
g_wszPropRawCertificate,
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
&cbCert,
(BYTE **) &pbCert);
_LeaveIfError(hr, "PKCSGetProperty(cert)");
pCert = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
if (NULL == pCert)
{
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
_LeaveError(hr, "CertCreateCertificateContext");
}
hr = PKCSArchivePrivateKey(
prow,
CERT_V1 == pCert->pCertInfo->dwVersion,
(IKF_OVERWRITE & Flags)? TRUE : FALSE,
&BlobEncrypted,
NULL);
_LeaveIfError2(
hr,
"PKCSArchivePrivateKey",
HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS));
hr = prow->CommitTransaction(TRUE);
_LeaveIfError(hr, "CommitTransaction");
fCommitted = TRUE;
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (NULL != pbCert)
{
LocalFree(pbCert);
}
if (NULL != pCert)
{
CertFreeCertificateContext(pCert);
}
if (NULL != prow)
{
if (S_OK != hr && !fCommitted)
{
HRESULT hr2 = prow->CommitTransaction(FALSE);
_PrintIfError(hr2, "CommitTransaction");
}
prow->Release();
}
CertSrvExitServer(State);
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
STDMETHODIMP
CCertAdminD::GetCASecurity(
IN WCHAR const *pwszAuthority,
OUT CERTTRANSBLOB *pctbSD) // CoTaskMem*
{
HRESULT hr;
PSECURITY_DESCRIPTOR pSD = NULL;
CAuditEvent audit(0, g_dwAuditFilter);
DWORD State = 0;
// init
pctbSD->pb = NULL;
pctbSD->cb = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::GetCASecurity(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "CheckAuthorityName");
__try
{
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
// get current SD:
hr = g_CASD.LockGet(&pSD); // no free
_LeaveIfError(hr, "CProtectedSecurityDescriptor::LockGet");
pctbSD->cb = GetSecurityDescriptorLength(pSD);
pctbSD->pb = (BYTE *) MIDL_user_allocate(pctbSD->cb);
if (NULL == pctbSD->pb)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "MIDL_user_allocate");
}
myRegisterMemFree(pctbSD->pb, CSM_MIDLUSERALLOC);
CopyMemory(pctbSD->pb, pSD, pctbSD->cb);
hr = g_CASD.Unlock();
_LeaveIfError(hr, "CProtectedSecurityDescriptor::Unlock");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return hr;
}
STDMETHODIMP
CCertAdminD::SetCASecurity(
IN WCHAR const *pwszAuthority,
IN CERTTRANSBLOB *pctbSD)
{
HRESULT hr;
PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR) pctbSD->pb;
LPWSTR pwszSD = NULL;
CAuditEvent audit(SE_AUDITID_CERTSRV_SETSECURITY, g_dwAuditFilter);
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::SetCASecurity(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "CheckAuthorityName");
__try
{
hr = audit.AddData(pctbSD->pb, pctbSD->cb); // %1 dump permissions as blob, we
// don't want to parse the blob unless
// access check succeeds
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.AccessCheck(
CA_ACCESS_ADMIN,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = CCertificateAuthoritySD::ConvertToString(pSD, pwszSD);
_LeaveIfError(hr, "CAuditEvent::ConvertToString");
audit.DeleteLastData(); // remove permissions blob to add a human friendly SD dump
hr = audit.AddData(pwszSD);
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = g_CASD.Set(pSD, g_fUseDS?true:false);
_LeaveIfError(hr, "CProtectedSecurityDescriptor::Set");
if (g_OfficerRightsSD.IsEnabled())
{
// adjust officer rights to match new CA SD; persistently save it
hr = g_OfficerRightsSD.Adjust(pSD);
_LeaveIfError(hr, "CProtectedSecurityDescriptor::Adjust");
hr = g_OfficerRightsSD.Save();
_LeaveIfError(hr, "CProtectedSecurityDescriptor::Save");
}
hr = g_CASD.Save();
_LeaveIfError(hr, "CProtectedSecurityDescriptor::Save");
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
if (HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE) == hr)
{
LogEventString(
EVENTLOG_ERROR_TYPE,
MSG_E_CANNOT_WRITE_TO_DS,
g_wszCommonName);
}
else
{
if(S_OK != hr)
{
LogEventHResult(
EVENTLOG_ERROR_TYPE,
MSG_E_CANNOT_SET_PERMISSIONS,
hr);
}
}
LOCAL_FREE(pwszSD);
CertSrvExitServer(State);
return hr;
}
// Constructor
CCertAdminD::CCertAdminD() : m_cRef(1), m_cNext(0)
{
InterlockedIncrement(&g_cAdminComponents);
m_pEnumCol = NULL;
m_pView = NULL;
m_pBackup = NULL;
}
// Destructor
CCertAdminD::~CCertAdminD()
{
InterlockedDecrement(&g_cAdminComponents);
if (NULL != m_pEnumCol)
{
m_pEnumCol->Release();
m_pEnumCol = NULL;
}
if (NULL != m_pView)
{
m_pView->Release();
m_pView = NULL;
}
if (NULL != m_pBackup)
{
m_pBackup->Release();
m_pBackup = NULL;
}
}
// IUnknown implementation
STDMETHODIMP
CCertAdminD::QueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown)
{
*ppv = static_cast<ICertAdminD *>(this);
}
else if (iid == IID_ICertAdminD)
{
*ppv = static_cast<ICertAdminD *>(this);
}
else if (iid == IID_ICertAdminD2)
{
*ppv = static_cast<ICertAdminD2 *>(this);
}
else
{
*ppv = NULL;
return(E_NOINTERFACE);
}
reinterpret_cast<IUnknown *>(*ppv)->AddRef();
return(S_OK);
}
ULONG STDMETHODCALLTYPE
CCertAdminD::AddRef()
{
return(InterlockedIncrement(&m_cRef));
}
ULONG STDMETHODCALLTYPE
CCertAdminD::Release()
{
ULONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
}
return(cRef);
}
CAdminFactory::~CAdminFactory()
{
if (m_cRef != 0)
{
DBGPRINT((
DBG_SS_CERTSRV,
"CAdminFactory has %d instances left over\n",
m_cRef));
}
}
// Class factory IUnknown implementation
STDMETHODIMP
CAdminFactory::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
CAdminFactory::AddRef()
{
return(InterlockedIncrement(&m_cRef));
}
ULONG STDMETHODCALLTYPE
CAdminFactory::Release()
{
ULONG cRef = InterlockedDecrement(&m_cRef);
if (0 == cRef)
{
delete this;
return(0);
}
return(cRef);
}
// IClassFactory implementation
STDMETHODIMP
CAdminFactory::CreateInstance(
IUnknown *pUnknownOuter,
const IID& iid,
void **ppv)
{
HRESULT hr;
CCertAdminD *pA;
// Cannot aggregate.
if (pUnknownOuter != NULL)
{
hr = CLASS_E_NOAGGREGATION;
_JumpError(hr, error, "pUnknownOuter");
}
// Create component.
pA = new CCertAdminD;
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
CAdminFactory::LockServer(
BOOL bLock)
{
if (bLock)
{
InterlockedIncrement(&g_cAdminServerLocks);
}
else
{
InterlockedDecrement(&g_cAdminServerLocks);
}
return(S_OK);
}
STDMETHODIMP
CAdminFactory::CanUnloadNow()
{
if (g_cAdminComponents || g_cAdminServerLocks)
{
return(S_FALSE);
}
return(S_OK);
}
STDMETHODIMP
CAdminFactory::StartFactory()
{
HRESULT hr;
g_pIAdminFactory = new CAdminFactory();
if (NULL == g_pIAdminFactory)
{
hr = E_OUTOFMEMORY;
_JumpError(hr, error, "alloc CAdminFactory");
}
hr = CoRegisterClassObject(
CLSID_CCertAdminD,
static_cast<IUnknown *>(g_pIAdminFactory),
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE,
&g_dwAdminRegister);
_JumpIfError(hr, error, "CoRegisterClassObject");
error:
if (S_OK != hr)
{
CAdminFactory::StopFactory();
}
CSASSERT(S_OK == hr || FAILED(hr));
return(hr);
}
VOID
CAdminFactory::StopFactory()
{
HRESULT hr;
if (0 != g_dwAdminRegister)
{
hr = CoRevokeClassObject(g_dwAdminRegister);
_PrintIfError(hr, "CoRevokeClassObject");
g_dwAdminRegister = 0;
}
if (NULL != g_pIAdminFactory)
{
g_pIAdminFactory->Release();
g_pIAdminFactory = NULL;
}
}
STDMETHODIMP
CCertAdminD::GetAuditFilter(
IN wchar_t const *pwszAuthority,
OUT DWORD *pdwFilter)
{
HRESULT hr;
DWORD State = 0;
CAuditEvent audit(0, g_dwAuditFilter);
*pdwFilter = 0;
if (!g_fAdvancedServer)
{
hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
_JumpError(hr, error, "g_fAdvancedServer");
}
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
*pdwFilter = g_dwAuditFilter;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return(hr);
}
STDMETHODIMP
CCertAdminD::SetAuditFilter(
IN wchar_t const *pwszAuthority,
IN DWORD dwFilter)
{
HRESULT hr;
CAuditEvent audit(SE_AUDITID_CERTSRV_SETAUDITFILTER, g_dwAuditFilter);
DWORD State = 0;
if (!g_fAdvancedServer)
{
hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
_JumpError(hr, error, "g_fAdvancedServer");
}
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
hr = audit.AddData(dwFilter); // %1 filter
_LeaveIfError(hr, "AddParam");
hr = audit.AccessCheck(
CA_ACCESS_AUDITOR,
audit.m_gcAuditSuccessOrFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
// save the audit filter using a dummy audit object
{
CAuditEvent dummyaudit(0, dwFilter);
hr = dummyaudit.SaveFilter(g_wszSanitizedName);
_LeaveIfError(hr, "CAuditEvent::SaveFilter");
}
g_dwAuditFilter = dwFilter;
// we can't catch service start/stop events generated
// by SCM, so we need to update the SACL on the service
hr = UpdateServiceSacl(g_dwAuditFilter&AUDIT_FILTER_STARTSTOP);
_LeaveIfError(hr, "UpdateServiceSacl");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return(hr);
}
STDMETHODIMP
CCertAdminD::GetOfficerRights(
IN wchar_t const *pwszAuthority,
OUT BOOL *pfEnabled,
OUT CERTTRANSBLOB *pctbSD)
{
HRESULT hr;
PSECURITY_DESCRIPTOR pSD = NULL;
CAuditEvent audit(0, g_dwAuditFilter);
DWORD State = 0;
pctbSD->pb = NULL;
pctbSD->cb = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::GetOfficerRights(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
if (!g_fAdvancedServer)
{
hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
_JumpError(hr, error, "g_fAdvancedServer");
}
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "CheckAuthorityName");
__try
{
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
*pfEnabled = g_OfficerRightsSD.IsEnabled();
// return the security descriptor only if the feature is enabled
if (g_OfficerRightsSD.IsEnabled())
{
// get current SD:
hr = g_OfficerRightsSD.LockGet(&pSD); // no free
_LeaveIfError(hr, "CProtectedSecurityDescriptor::LockGet");
pctbSD->cb = GetSecurityDescriptorLength(pSD);
pctbSD->pb = (BYTE *) MIDL_user_allocate(pctbSD->cb);
if (NULL == pctbSD->pb)
{
hr = E_OUTOFMEMORY;
_LeaveError(hr, "MIDL_user_allocate");
}
myRegisterMemFree(pctbSD->pb, CSM_MIDLUSERALLOC);
CopyMemory(pctbSD->pb, pSD, pctbSD->cb);
hr = g_OfficerRightsSD.Unlock();
_LeaveIfError(hr, "CProtectedSecurityDescriptor::Unlock");
}
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return hr;
}
STDMETHODIMP
CCertAdminD::SetOfficerRights(
IN wchar_t const *pwszAuthority,
IN BOOL fEnable,
IN CERTTRANSBLOB *pctbSD)
{
HRESULT hr;
PSECURITY_DESCRIPTOR pNewOfficerSD = (PSECURITY_DESCRIPTOR) pctbSD->pb;
PSECURITY_DESCRIPTOR pCASD = NULL;
LPWSTR pwszSD = NULL;
CAuditEvent audit(SE_AUDITID_CERTSRV_SETOFFICERRIGHTS, g_dwAuditFilter);
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::SetOfficerRights(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
if (!g_fAdvancedServer)
{
hr = HRESULT_FROM_WIN32(ERROR_CALL_NOT_IMPLEMENTED);
_JumpError(hr, error, "g_fAdvancedServer");
}
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "CheckAuthorityName");
__try
{
hr = audit.AddData(fEnable?true:false); // %1 Enable restrictions?
_LeaveIfError(hr, "CAuditEvent::AddData");
if(fEnable)
{
hr = audit.AddData(pctbSD->pb, pctbSD->cb); // %2 new permissions; add as
// blob, we don't convert to string
// unless access check passes
_LeaveIfError(hr, "CAuditEvent::AddData");
}
else
{
hr = audit.AddData(L""); // %2 no permissions if disabling
// the officer restrictions
_LeaveIfError(hr, "CAuditEvent::AddData");
}
hr = audit.AccessCheck(
CA_ACCESS_ADMIN,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
g_OfficerRightsSD.SetEnable(fEnable);
// ignore new security descriptor if asked to turn officer rights off
if (fEnable)
{
hr = g_CASD.LockGet(&pCASD); // no free
_LeaveIfError(hr, "CProtectedSecurityDescriptor::LockGet");
// adjust new officer rights based on the CA SD and set the
// officer rights SD to the new SD
hr = g_OfficerRightsSD.Merge(pNewOfficerSD, pCASD);
_LeaveIfError(hr, "COfficerRightsSD::Merge");
hr = g_CASD.Unlock();
_LeaveIfError(hr, "CProtectedSecurityDescriptor::Unlock");
}
// persistent save to registry
hr = g_OfficerRightsSD.Save();
_LeaveIfError(hr, "CProtectedSecurityDescriptor::Save");
if(fEnable)
{
hr = COfficerRightsSD::ConvertToString(pNewOfficerSD, pwszSD);
_LeaveIfError(hr, "COfficerRightsSD::ConvertToString");
audit.DeleteLastData(); // remove permissions blob
hr = audit.AddData(pwszSD); // %2 add human-friend permissions string
_LeaveIfError(hr, "CAuditEvent::AddData");
}
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
LOCAL_FREE(pwszSD);
CertSrvExitServer(State);
return hr;
}
STDMETHODIMP
CCertAdminD::GetConfigEntry(
wchar_t const *pwszAuthority,
wchar_t const *pwszNodePath,
wchar_t const *pwszEntry,
VARIANT *pVariant)
{
HRESULT hr;
CAuditEvent audit(0, g_dwAuditFilter);
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::GetConfigEntry(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority, true); // allow empty/null name
_JumpIfError(hr, error, "CheckAuthorityName");
__try
{
hr = audit.AccessCheck(
CA_ACCESS_ALLREADROLES,
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = g_ConfigStorage.GetEntry(
EmptyString(pwszAuthority)?
NULL : g_wszSanitizedName, // allow empty/null name
pwszNodePath,
pwszEntry,
pVariant);
_LeaveIfError2(
hr,
"CConfigStorage::GetConfigEntry",
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
myRegisterMemFree(pVariant, CSM_VARIANT);
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return hr;
}
STDMETHODIMP
CCertAdminD::SetConfigEntry(
wchar_t const *pwszAuthority,
wchar_t const *pwszNodePath,
wchar_t const *pwszEntry,
VARIANT *pVariant)
{
HRESULT hr;
CAuditEvent audit(SE_AUDITID_CERTSRV_SETCONFIGENTRY, g_dwAuditFilter);
DWORD State = 0;
DBGPRINT((
s_ssAdmin,
"CCertAdminD::SetConfigEntry(tid=%d, this=%x)\n",
GetCurrentThreadId(),
this));
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority, true); // allow empty/null name
_JumpIfError(hr, error, "CheckAuthorityName");
hr = audit.AddData(pwszNodePath); // %1 node
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.AddData(pwszEntry); // %2 entry
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.AddData(L""); // %3 empty data, we don't process the variant
// unless the access check passes
_JumpIfError(hr, error, "CAuditEvent::AddData");
__try
{
hr = audit.AccessCheck(
CA_ACCESS_ADMIN,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
hr = g_ConfigStorage.SetEntry(
EmptyString(pwszAuthority)?
NULL : g_wszSanitizedName, // allow empty/null name
pwszNodePath,
pwszEntry,
pVariant);
_LeaveIfError(hr, "CConfigStorage::SetConfigEntry");
// postpone adding the actual data to allow set entry to validate it
audit.DeleteLastData();
hr = audit.AddData(
pVariant, // %3 value
true); // true means convert % chars found in strings to %% (bug# 326248)
_LeaveIfError(hr, "CAuditEvent::AddData");
hr = audit.CachedGenerateAudit();
_LeaveIfError(hr, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return hr;
}
STDMETHODIMP
CCertAdminD::GetMyRoles(
IN wchar_t const *pwszAuthority,
OUT LONG *pdwRoles)
{
HRESULT hr;
CAuditEvent audit(0, g_dwAuditFilter);
DWORD dwRoles = 0;
DWORD State = 0;
*pdwRoles = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
hr = audit.GetMyRoles(&dwRoles);
_LeaveIfError(hr, "CAuditEvent::GetMyRoles");
*pdwRoles = dwRoles;
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return(hr);
}
HRESULT
adminDeleteRow(
IN DWORD dwRowId,
IN DWORD dwPropTable)
{
HRESULT hr;
ICertDBRow *prow = NULL;
BOOL fCommitted = FALSE;
hr = g_pCertDB->OpenRow(
PROPOPEN_DELETE | dwPropTable,
dwRowId,
NULL,
&prow);
_JumpIfError2(hr, error, "OpenRow", CERTSRV_E_PROPERTY_EMPTY);
hr = prow->Delete();
_JumpIfError(hr, error, "Delete");
hr = prow->CommitTransaction(TRUE);
_JumpIfError(hr, error, "CommitTransaction");
fCommitted = TRUE;
error:
if (NULL != prow)
{
if (S_OK != hr && !fCommitted)
{
HRESULT hr2 = prow->CommitTransaction(FALSE);
_PrintIfError(hr2, "CommitTransaction");
}
prow->Release();
}
return(hr);
}
HRESULT
adminDeleteByRowId(
IN DWORD dwRowId,
IN DWORD dwPropTable,
OUT LONG *pcDeleted)
{
HRESULT hr;
LONG cDeleted = 0;
LONG cDeletedExt = 0;
LONG cDeletedAttr = 0;
*pcDeleted = 0;
if (PROPTABLE_REQCERT == dwPropTable)
{
hr = adminDeleteByRowId(dwRowId, PROPTABLE_EXTENSION, &cDeletedExt);
_JumpIfError(hr, error, "adminDeleteByRowId(ext)");
DBGPRINT((
DBG_SS_CERTSRV,
"adminDeleteByRowId(Rowid=%u) deleted %u extension rows\n",
dwRowId,
cDeletedExt));
hr = adminDeleteByRowId(dwRowId, PROPTABLE_ATTRIBUTE, &cDeletedAttr);
_JumpIfError(hr, error, "adminDeleteByRowId(attrib)");
DBGPRINT((
DBG_SS_CERTSRV,
"adminDeleteByRowId(Rowid=%u) deleted %u attribute rows\n",
dwRowId,
cDeletedAttr));
}
while (TRUE)
{
hr = adminDeleteRow(dwRowId, dwPropTable);
if (CERTSRV_E_PROPERTY_EMPTY == hr)
{
break;
}
_JumpIfError(hr, error, "adminDeleteByRowId");
cDeleted++;
}
if (0 == cDeleted && 0 != (cDeletedExt + cDeletedAttr))
{
cDeleted++;
}
hr = S_OK;
error:
*pcDeleted += cDeleted;
return(hr);
}
#define ICOLDEL_DATE 0
#define ICOLDEL_DISPOSITION 1
HRESULT
adminDeleteRowsFromQuery(
IN DWORD dwPropTable,
IN DWORD DateColumn,
IN DWORD DispositionColumn,
IN BOOL fRequest,
IN FILETIME const *pft,
OUT LONG *pcDeleted)
{
HRESULT hr;
CERTVIEWRESTRICTION acvr[1];
CERTVIEWRESTRICTION *pcvr;
IEnumCERTDBRESULTROW *pView = NULL;
DWORD celtFetched;
DWORD i;
BOOL fEnd;
CERTDBRESULTROW aResult[10];
BOOL fResultActive = FALSE;
DWORD acol[2];
DWORD ccol;
DWORD cDeleted = 0;
*pcDeleted = 0;
// Set up restrictions as follows:
pcvr = acvr;
// DateColumn < *pft
pcvr->ColumnIndex = DateColumn;
pcvr->SeekOperator = CVR_SEEK_LT;
pcvr->SortOrder = CVR_SORT_ASCEND;
pcvr->pbValue = (BYTE *) pft;
pcvr->cbValue = sizeof(*pft);
pcvr++;
CSASSERT(ARRAYSIZE(acvr) == SAFE_SUBTRACT_POINTERS(pcvr, acvr));
ccol = 0;
acol[ccol++] = DateColumn;
if (0 != DispositionColumn)
{
acol[ccol++] = DispositionColumn;
}
hr = g_pCertDB->OpenView(
ARRAYSIZE(acvr),
acvr,
ccol,
acol,
0, // no worker thread
&pView);
_JumpIfError(hr, error, "OpenView");
fEnd = FALSE;
while (!fEnd)
{
hr = pView->Next(ARRAYSIZE(aResult), aResult, &celtFetched);
if (S_FALSE == hr)
{
fEnd = TRUE;
if (0 == celtFetched)
{
break;
}
hr = S_OK;
}
_JumpIfError(hr, error, "Next");
fResultActive = TRUE;
CSASSERT(ARRAYSIZE(aResult) >= celtFetched);
for (i = 0; i < celtFetched; i++)
{
BOOL fDelete = TRUE;
CERTDBRESULTROW *pResult = &aResult[i];
CSASSERT(ccol == pResult->ccol);
if (0 != DispositionColumn)
{
DWORD Disposition;
CSASSERT(NULL != pResult->acol[ICOLDEL_DISPOSITION].pbValue);
CSASSERT(PROPTYPE_LONG == (PROPTYPE_MASK & pResult->acol[ICOLDEL_DISPOSITION].Type));
CSASSERT(sizeof(Disposition) == pResult->acol[ICOLDEL_DISPOSITION].cbValue);
Disposition = *(DWORD *) pResult->acol[ICOLDEL_DISPOSITION].pbValue;
if (fRequest)
{
// Delete only pending and failed requests
if (DB_DISP_PENDING != Disposition &&
DB_DISP_LOG_FAILED_MIN > Disposition)
{
fDelete = FALSE;
}
}
else
{
// Delete only issued and revoked certs
if (DB_DISP_LOG_MIN > Disposition ||
DB_DISP_LOG_FAILED_MIN <= Disposition)
{
fDelete = FALSE;
}
}
}
CSASSERT(PROPTYPE_DATE == (PROPTYPE_MASK & pResult->acol[ICOLDEL_DATE].Type));
// If the date column is missing, delete the row.
#ifdef DBG_CERTSRV_DEBUG_PRINT
if (NULL != pResult->acol[ICOLDEL_DATE].pbValue &&
sizeof(FILETIME) == pResult->acol[ICOLDEL_DATE].cbValue)
{
WCHAR *pwszTime = NULL;
myGMTFileTimeToWszLocalTime(
(FILETIME *) pResult->acol[ICOLDEL_DATE].pbValue,
TRUE,
&pwszTime);
DBGPRINT((
DBG_SS_CERTSRV,
"adminDeleteRowsFromQuery(%ws)\n",
pwszTime));
if (NULL != pwszTime)
{
LocalFree(pwszTime);
}
}
#endif // DBG_CERTSRV_DEBUG_PRINT
if (fDelete)
{
LONG cDelT;
hr = adminDeleteByRowId(pResult->rowid, dwPropTable, &cDelT);
_JumpIfError(hr, error, "adminDeleteByRowId");
DBGPRINT((
DBG_SS_CERTSRV,
"adminDeleteByRowId(Rowid=%u) deleted %u Query rows\n",
pResult->rowid,
cDelT));
cDeleted += cDelT;
}
}
pView->ReleaseResultRow(celtFetched, aResult);
fResultActive = FALSE;
}
hr = S_OK;
error:
*pcDeleted = cDeleted;
if (NULL != pView)
{
if (fResultActive)
{
pView->ReleaseResultRow(celtFetched, aResult);
}
pView->Release();
}
return(hr);
}
#undef ICOLDEL_DATE
#undef ICOLDEL_DISPOSITION
STDMETHODIMP
CCertAdminD::DeleteRow(
IN wchar_t const *pwszAuthority,
IN DWORD dwFlags, // CDR_*
IN FILETIME FileTime,
IN DWORD dwTable, // CVRC_TABLE_*
IN DWORD dwRowId,
OUT LONG *pcDeleted)
{
HRESULT hr;
DWORD dwPropTable;
CAuditEvent audit(SE_AUDITID_CERTSRV_DELETEROW, g_dwAuditFilter);
DWORD DateColumn;
DWORD DispositionColumn;
BOOL fRequest;
DWORD State = 0;
*pcDeleted = 0;
hr = CertSrvEnterServer(&State);
_JumpIfError(hr, error, "CertSrvEnterServer");
hr = CheckAuthorityName(pwszAuthority);
_JumpIfError(hr, error, "No authority name");
__try
{
hr = audit.AddData(dwTable); // %1 table ID
_JumpIfError(hr, error, "CAuditEvent::AddData");
if (0 == dwRowId)
{
hr = audit.AddData(FileTime); // %2 filter (time)
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.AddData((DWORD)0); // %3 rows deleted
_JumpIfError(hr, error, "CAuditEvent::AddData");
// bulk deletion -- must be local admin
hr = audit.AccessCheck(
CA_ACCESS_LOCALADMIN,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
}
else
{
hr = audit.AddData(dwRowId); // %2 filter (request ID)
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.AddData((DWORD)0); // %3 rows deleted
_JumpIfError(hr, error, "CAuditEvent::AddData");
// individual deletion -- CA admin suffices
hr = audit.AccessCheck(
CA_ACCESS_ADMIN,
audit.m_gcNoAuditSuccess);
_LeaveIfError(hr, "CAuditEvent::AccessCheck");
}
hr = E_INVALIDARG;
if ((0 == FileTime.dwLowDateTime && 0 == FileTime.dwHighDateTime) ^
(0 != dwRowId))
{
_LeaveError(hr, "row OR date required");
}
DateColumn = 0;
DispositionColumn = 0;
fRequest = FALSE;
switch (dwTable)
{
case CVRC_TABLE_REQCERT:
dwPropTable = PROPTABLE_REQCERT;
switch (dwFlags)
{
case CDR_EXPIRED:
DateColumn = DTI_CERTIFICATETABLE | DTC_CERTIFICATENOTAFTERDATE;
DispositionColumn = DTI_REQUESTTABLE | DTR_REQUESTDISPOSITION;
break;
case CDR_REQUEST_LAST_CHANGED:
DateColumn = DTI_REQUESTTABLE | DTR_REQUESTRESOLVEDWHEN;
DispositionColumn = DTI_REQUESTTABLE | DTR_REQUESTDISPOSITION;
fRequest = TRUE;
break;
case 0:
break;
default:
_LeaveError(hr, "dwFlags");
break;
}
break;
case CVRC_TABLE_EXTENSIONS:
if (0 == dwRowId)
{
_LeaveError(hr, "no date field in Extension table");
}
if (0 != dwFlags)
{
_LeaveError(hr, "dwFlags");
}
dwPropTable = PROPTABLE_EXTENSION;
break;
case CVRC_TABLE_ATTRIBUTES:
if (0 == dwRowId)
{
_LeaveError(hr, "no date field in Request Attribute table");
}
if (0 != dwFlags)
{
_LeaveError(hr, "dwFlags");
}
dwPropTable = PROPTABLE_ATTRIBUTE;
break;
case CVRC_TABLE_CRL:
dwPropTable = PROPTABLE_CRL;
switch (dwFlags)
{
case CDR_EXPIRED:
DateColumn = DTI_CERTIFICATETABLE | DTC_CERTIFICATENOTAFTERDATE;
break;
case 0:
break;
default:
_LeaveError(hr, "dwFlags");
break;
}
DateColumn = DTI_CRLTABLE | DTL_NEXTUPDATEDATE;
break;
default:
_LeaveError(hr, "dwTable");
}
if (0 != dwRowId)
{
hr = adminDeleteByRowId(dwRowId, dwPropTable, pcDeleted);
_LeaveIfError(hr, "adminDeleteByRowId");
DBGPRINT((
DBG_SS_CERTSRV,
"adminDeleteByRowId(Rowid=%u) deleted %u rows\n",
dwRowId,
*pcDeleted));
}
else
{
CSASSERT(0 != DateColumn);
hr = adminDeleteRowsFromQuery(
dwPropTable,
DateColumn,
DispositionColumn,
fRequest,
&FileTime,
pcDeleted);
_LeaveIfError(hr, "adminDeleteRowsFromQuery");
}
audit.DeleteLastData();
hr = audit.AddData((DWORD)*pcDeleted); // %3 rows deleted
_JumpIfError(hr, error, "CAuditEvent::AddData");
hr = audit.CachedGenerateAudit();
_JumpIfError(hr, error, "CAuditEvent::CachedGenerateAudit");
}
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
{
_PrintError(hr, "Exception");
}
error:
CertSrvExitServer(State);
return(hr);
}