mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4919 lines
110 KiB
4919 lines
110 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// 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);
|
|
}
|