//+-------------------------------------------------------------------------- // // 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 #pragma hdrstop #include #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(1Skip(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(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(this); } else if (iid == IID_ICertAdminD) { *ppv = static_cast(this); } else if (iid == IID_ICertAdminD2) { *ppv = static_cast(this); } else { *ppv = NULL; return(E_NOINTERFACE); } reinterpret_cast(*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(this); } else { *ppv = NULL; return(E_NOINTERFACE); } reinterpret_cast(*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(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); }