You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4850 lines
121 KiB
4850 lines
121 KiB
//+--------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
//
|
|
// File: core.cpp
|
|
//
|
|
// Contents: Cert Server Core implementation
|
|
//
|
|
// History: 25-Jul-96 vich created
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <stdio.h>
|
|
#include <winldap.h>
|
|
#include <ntdsapi.h>
|
|
#include <dsgetdc.h>
|
|
#include <lm.h>
|
|
#include <esent.h>
|
|
|
|
#include "cscom.h"
|
|
#include "csprop.h"
|
|
#include "cspolicy.h"
|
|
#include "ciinit.h"
|
|
#include "csdisp.h"
|
|
#include "csldap.h"
|
|
#include "cainfop.h"
|
|
#include "elog.h"
|
|
#include "certlog.h"
|
|
#include "resource.h"
|
|
|
|
#define __dwFILE__ __dwFILE_CERTSRV_CORE_CPP__
|
|
|
|
|
|
#if DBG_COMTEST
|
|
#define DBG_COMTEST_CONST
|
|
#else
|
|
#define DBG_COMTEST_CONST const
|
|
#endif
|
|
|
|
#define DBSESSIONCOUNTMIN 4
|
|
#define DBSESSIONCOUNTMAX 1024
|
|
|
|
|
|
DBG_COMTEST_CONST BOOL fComTest = FALSE;
|
|
|
|
SERVERCALLBACKS ServerCallBacks = {
|
|
PropCIGetProperty,
|
|
PropCISetProperty,
|
|
PropCIGetExtension,
|
|
PropCISetExtension,
|
|
PropCIEnumSetup,
|
|
PropCIEnumNext,
|
|
PropCIEnumClose,
|
|
};
|
|
|
|
|
|
HINSTANCE g_hInstance;
|
|
WCHAR g_wszSharedFolder[MAX_PATH];
|
|
WCHAR g_wszSanitizedName[MAX_PATH];
|
|
WCHAR *g_pwszSanitizedDSName;
|
|
WCHAR g_wszCommonName[MAX_PATH];
|
|
WCHAR g_wszPolicyDCName[MAX_PATH];
|
|
DWORD g_cwcPolicyDCName = ARRAYSIZE(g_wszPolicyDCName);
|
|
WCHAR g_wszParentConfig[MAX_PATH];
|
|
|
|
WCHAR *g_pwszzAlternatePublishDomains = NULL;
|
|
WCHAR *g_pwszzSubjectTemplate = NULL;
|
|
WCHAR *g_pwszServerName = NULL;
|
|
|
|
DWORD g_dwClockSkewMinutes = CCLOCKSKEWMINUTESDEFAULT;
|
|
DWORD g_dwViewAgeMinutes = CVIEWAGEMINUTESDEFAULT;
|
|
DWORD g_dwViewIdleMinutes = CVIEWIDLEMINUTESDEFAULT;
|
|
DWORD g_dwLogLevel = CERTLOG_WARNING;
|
|
DWORD g_dwSessionCount = DBSESSIONCOUNTDEFAULT;
|
|
DWORD g_dwHighSerial = 0;
|
|
BYTE *g_pbHighSerial = NULL;
|
|
DWORD g_cbHighSerial;
|
|
DWORD g_cbMaxIncomingMessageSize = MAXINCOMINGMESSAGESIZEDEFAULT;
|
|
DWORD g_cbMaxIncomingAllocSize = MAXINCOMINGALLOCSIZEDEFAULT;
|
|
|
|
WCHAR const g_wszRegValidityPeriodString[] = wszREGVALIDITYPERIODSTRING;
|
|
WCHAR const g_wszRegValidityPeriodCount[] = wszREGVALIDITYPERIODCOUNT;
|
|
|
|
WCHAR const g_wszRegCAXchgValidityPeriodString[] = wszREGCAXCHGVALIDITYPERIODSTRING;
|
|
WCHAR const g_wszRegCAXchgValidityPeriodCount[] = wszREGCAXCHGVALIDITYPERIODCOUNT;
|
|
WCHAR const g_wszRegCAXchgOverlapPeriodString[] = wszREGCAXCHGOVERLAPPERIODSTRING;
|
|
WCHAR const g_wszRegCAXchgOverlapPeriodCount[] = wszREGCAXCHGOVERLAPPERIODCOUNT;
|
|
WCHAR const g_wszRegCAXchgCertHash[] = wszREGCAXCHGCERTHASH;
|
|
|
|
WCHAR const g_wszRegSubjectTemplate[] = wszREGSUBJECTTEMPLATE;
|
|
WCHAR const g_wszRegKeyConfigPath[] = wszREGKEYCONFIGPATH;
|
|
WCHAR const g_wszRegDirectory[] = wszREGDIRECTORY;
|
|
WCHAR const g_wszRegActive[] = wszREGACTIVE;
|
|
WCHAR const g_wszRegEnabled[] = wszREGENABLED;
|
|
WCHAR const g_wszRegPolicyFlags[] = wszREGPOLICYFLAGS;
|
|
WCHAR const g_wszCertSrvServiceName[] = wszSERVICE_NAME;
|
|
WCHAR const g_wszRegCertEnrollCompatible[] = wszREGCERTENROLLCOMPATIBLE;
|
|
WCHAR const g_wszRegEnforceX500NameLengths[] = wszREGENFORCEX500NAMELENGTHS;
|
|
WCHAR const g_wszRegForceTeletex[] = wszREGFORCETELETEX;
|
|
WCHAR const g_wszRegClockSkewMinutes[] = wszREGCLOCKSKEWMINUTES;
|
|
WCHAR const g_wszRegViewAgeMinutes[] = wszREGVIEWAGEMINUTES;
|
|
WCHAR const g_wszRegViewIdleMinutes[] = wszREGVIEWIDLEMINUTES;
|
|
WCHAR const g_wszRegLogLevel[] = wszREGLOGLEVEL;
|
|
WCHAR const g_wszRegHighSerial[] = wszREGHIGHSERIAL;
|
|
WCHAR const g_wszRegMaxIncomingMessageSize[] = wszREGMAXINCOMINGMESSAGESIZE;
|
|
WCHAR const g_wszRegMaxIncomingAllocSize[] = wszREGMAXINCOMINGALLOCSIZE;
|
|
|
|
BOOL g_fCertEnrollCompatible = TRUE;
|
|
BOOL g_fEnforceRDNNameLengths = TRUE;
|
|
DWORD g_KRAFlags = 0;
|
|
DWORD g_CRLEditFlags = EDITF_ENABLEAKIKEYID |
|
|
EDITF_ENABLEAKIISSUERNAME |
|
|
EDITF_ENABLEAKIISSUERSERIAL |
|
|
EDITF_ENABLEAKICRITICAL;
|
|
ENUM_FORCETELETEX g_fForceTeletex = ENUM_TELETEX_AUTO;
|
|
ENUM_CATYPES g_CAType = ENUM_UNKNOWN_CA;
|
|
|
|
BOOL g_fUseDS = FALSE;
|
|
BOOL g_fServerUpgraded = FALSE;
|
|
DWORD g_InterfaceFlags = IF_DEFAULT;
|
|
HRESULT g_hrJetVersionStoreOutOfMemory;
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Name properties:
|
|
|
|
WCHAR const g_wszPropDistinguishedName[] = wszPROPDISTINGUISHEDNAME;
|
|
WCHAR const g_wszPropRawName[] = wszPROPRAWNAME;
|
|
|
|
WCHAR const g_wszPropCountry[] = wszPROPCOUNTRY;
|
|
WCHAR const g_wszPropOrganization[] = wszPROPORGANIZATION;
|
|
WCHAR const g_wszPropOrgUnit[] = wszPROPORGUNIT;
|
|
WCHAR const g_wszPropCommonName[] = wszPROPCOMMONNAME;
|
|
WCHAR const g_wszPropLocality[] = wszPROPLOCALITY;
|
|
WCHAR const g_wszPropState[] = wszPROPSTATE;
|
|
WCHAR const g_wszPropTitle[] = wszPROPTITLE;
|
|
WCHAR const g_wszPropGivenName[] = wszPROPGIVENNAME;
|
|
WCHAR const g_wszPropInitials[] = wszPROPINITIALS;
|
|
WCHAR const g_wszPropSurName[] = wszPROPSURNAME;
|
|
WCHAR const g_wszPropDomainComponent[] = wszPROPDOMAINCOMPONENT;
|
|
WCHAR const g_wszPropEMail[] = wszPROPEMAIL;
|
|
WCHAR const g_wszPropStreetAddress[] = wszPROPSTREETADDRESS;
|
|
WCHAR const g_wszPropUnstructuredAddress[] = wszPROPUNSTRUCTUREDADDRESS;
|
|
WCHAR const g_wszPropUnstructuredName[] = wszPROPUNSTRUCTUREDNAME;
|
|
WCHAR const g_wszPropDeviceSerialNumber[] = wszPROPDEVICESERIALNUMBER;
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Subject Name properties:
|
|
|
|
WCHAR const g_wszPropSubjectDot[] = wszPROPSUBJECTDOT;
|
|
WCHAR const g_wszPropSubjectDistinguishedName[] = wszPROPSUBJECTDISTINGUISHEDNAME;
|
|
WCHAR const g_wszPropSubjectRawName[] = wszPROPSUBJECTRAWNAME;
|
|
|
|
WCHAR const g_wszPropSubjectCountry[] = wszPROPSUBJECTCOUNTRY;
|
|
WCHAR const g_wszPropSubjectOrganization[] = wszPROPSUBJECTORGANIZATION;
|
|
WCHAR const g_wszPropSubjectOrgUnit[] = wszPROPSUBJECTORGUNIT;
|
|
WCHAR const g_wszPropSubjectCommonName[] = wszPROPSUBJECTCOMMONNAME;
|
|
WCHAR const g_wszPropSubjectLocality[] = wszPROPSUBJECTLOCALITY;
|
|
WCHAR const g_wszPropSubjectState[] = wszPROPSUBJECTSTATE;
|
|
WCHAR const g_wszPropSubjectTitle[] = wszPROPSUBJECTTITLE;
|
|
WCHAR const g_wszPropSubjectGivenName[] = wszPROPSUBJECTGIVENNAME;
|
|
WCHAR const g_wszPropSubjectInitials[] = wszPROPSUBJECTINITIALS;
|
|
WCHAR const g_wszPropSubjectSurName[] = wszPROPSUBJECTSURNAME;
|
|
WCHAR const g_wszPropSubjectDomainComponent[] = wszPROPSUBJECTDOMAINCOMPONENT;
|
|
WCHAR const g_wszPropSubjectEMail[] = wszPROPSUBJECTEMAIL;
|
|
WCHAR const g_wszPropSubjectStreetAddress[] = wszPROPSUBJECTSTREETADDRESS;
|
|
WCHAR const g_wszPropSubjectUnstructuredAddress[] = wszPROPSUBJECTUNSTRUCTUREDADDRESS;
|
|
WCHAR const g_wszPropSubjectUnstructuredName[] = wszPROPSUBJECTUNSTRUCTUREDNAME;
|
|
WCHAR const g_wszPropSubjectDeviceSerialNumber[] = wszPROPSUBJECTDEVICESERIALNUMBER;
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Issuer Name properties:
|
|
|
|
WCHAR const g_wszPropIssuerDot[] = wszPROPISSUERDOT;
|
|
WCHAR const g_wszPropIssuerDistinguishedName[] = wszPROPISSUERDISTINGUISHEDNAME;
|
|
WCHAR const g_wszPropIssuerRawName[] = wszPROPISSUERRAWNAME;
|
|
|
|
WCHAR const g_wszPropIssuerCountry[] = wszPROPISSUERCOUNTRY;
|
|
WCHAR const g_wszPropIssuerOrganization[] = wszPROPISSUERORGANIZATION;
|
|
WCHAR const g_wszPropIssuerOrgUnit[] = wszPROPISSUERORGUNIT;
|
|
WCHAR const g_wszPropIssuerCommonName[] = wszPROPISSUERCOMMONNAME;
|
|
WCHAR const g_wszPropIssuerLocality[] = wszPROPISSUERLOCALITY;
|
|
WCHAR const g_wszPropIssuerState[] = wszPROPISSUERSTATE;
|
|
WCHAR const g_wszPropIssuerTitle[] = wszPROPISSUERTITLE;
|
|
WCHAR const g_wszPropIssuerGivenName[] = wszPROPISSUERGIVENNAME;
|
|
WCHAR const g_wszPropIssuerInitials[] = wszPROPISSUERINITIALS;
|
|
WCHAR const g_wszPropIssuerSurName[] = wszPROPISSUERSURNAME;
|
|
WCHAR const g_wszPropIssuerDomainComponent[] = wszPROPISSUERDOMAINCOMPONENT;
|
|
WCHAR const g_wszPropIssuerEMail[] = wszPROPISSUEREMAIL;
|
|
WCHAR const g_wszPropIssuerStreetAddress[] = wszPROPISSUERSTREETADDRESS;
|
|
WCHAR const g_wszPropIssuerUnstructuredAddress[] = wszPROPISSUERUNSTRUCTUREDADDRESS;
|
|
WCHAR const g_wszPropIssuerUnstructuredName[] = wszPROPISSUERUNSTRUCTUREDNAME;
|
|
WCHAR const g_wszPropIssuerDeviceSerialNumber[] = wszPROPISSUERDEVICESERIALNUMBER;
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Request properties:
|
|
|
|
WCHAR const g_wszPropRequestRequestID[] = wszPROPREQUESTREQUESTID;
|
|
WCHAR const g_wszPropRequestRawRequest[] = wszPROPREQUESTRAWREQUEST;
|
|
WCHAR const g_wszPropRequestRawArchivedKey[] = wszPROPREQUESTRAWARCHIVEDKEY;
|
|
WCHAR const g_wszPropRequestKeyRecoveryHashes[] = wszPROPREQUESTKEYRECOVERYHASHES;
|
|
WCHAR const g_wszPropRequestRawOldCertificate[] = wszPROPREQUESTRAWOLDCERTIFICATE;
|
|
WCHAR const g_wszPropRequestAttributes[] = wszPROPREQUESTATTRIBUTES;
|
|
WCHAR const g_wszPropRequestType[] = wszPROPREQUESTTYPE;
|
|
WCHAR const g_wszPropRequestFlags[] = wszPROPREQUESTFLAGS;
|
|
WCHAR const g_wszPropRequestStatusCode[] = wszPROPREQUESTSTATUSCODE;
|
|
WCHAR const g_wszPropRequestDisposition[] = wszPROPREQUESTDISPOSITION;
|
|
WCHAR const g_wszPropRequestDispositionMessage[] = wszPROPREQUESTDISPOSITIONMESSAGE;
|
|
WCHAR const g_wszPropRequestSubmittedWhen[] = wszPROPREQUESTSUBMITTEDWHEN;
|
|
WCHAR const g_wszPropRequestResolvedWhen[] = wszPROPREQUESTRESOLVEDWHEN;
|
|
WCHAR const g_wszPropRequestRevokedWhen[] = wszPROPREQUESTREVOKEDWHEN;
|
|
WCHAR const g_wszPropRequestRevokedEffectiveWhen[] = wszPROPREQUESTREVOKEDEFFECTIVEWHEN;
|
|
WCHAR const g_wszPropRequestRevokedReason[] = wszPROPREQUESTREVOKEDREASON;
|
|
WCHAR const g_wszPropRequesterName[] = wszPROPREQUESTERNAME;
|
|
WCHAR const g_wszPropCallerName[] = wszPROPCALLERNAME;
|
|
WCHAR const g_wszPropRequestOSVersion[] = wszPROPREQUESTOSVERSION;
|
|
WCHAR const g_wszPropRequestCSPProvider[] = wszPROPREQUESTCSPPROVIDER;
|
|
//+--------------------------------------------------------------------------
|
|
// Request attribute properties:
|
|
|
|
WCHAR const g_wszPropChallenge[] = wszPROPCHALLENGE;
|
|
WCHAR const g_wszPropExpectedChallenge[] = wszPROPEXPECTEDCHALLENGE;
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
// Certificate properties:
|
|
|
|
WCHAR const g_wszPropCertificateRequestID[] = wszPROPCERTIFICATEREQUESTID;
|
|
WCHAR const g_wszPropRawCertificate[] = wszPROPRAWCERTIFICATE;
|
|
WCHAR const g_wszPropCertificateHash[] = wszPROPCERTIFICATEHASH;
|
|
WCHAR const g_wszPropCertificateSerialNumber[] = wszPROPCERTIFICATESERIALNUMBER;
|
|
WCHAR const g_wszPropCertificateIssuerNameID[] = wszPROPCERTIFICATEISSUERNAMEID;
|
|
WCHAR const g_wszPropCertificateNotBeforeDate[] = wszPROPCERTIFICATENOTBEFOREDATE;
|
|
WCHAR const g_wszPropCertificateNotAfterDate[] = wszPROPCERTIFICATENOTAFTERDATE;
|
|
WCHAR const g_wszPropCertificateSubjectKeyIdentifier[] = wszPROPCERTIFICATESUBJECTKEYIDENTIFIER;
|
|
WCHAR const g_wszPropCertificateRawPublicKey[] = wszPROPCERTIFICATERAWPUBLICKEY;
|
|
WCHAR const g_wszPropCertificatePublicKeyLength[] = wszPROPCERTIFICATEPUBLICKEYLENGTH;
|
|
WCHAR const g_wszPropCertificatePublicKeyAlgorithm[] = wszPROPCERTIFICATEPUBLICKEYALGORITHM;
|
|
WCHAR const g_wszPropCertificateRawPublicKeyAlgorithmParameters[] = wszPROPCERTIFICATERAWPUBLICKEYALGORITHMPARAMETERS;
|
|
|
|
|
|
// Strings loaded from the resource file:
|
|
|
|
WCHAR const *g_pwszRequestedBy;
|
|
WCHAR const *g_pwszDeniedBy;
|
|
WCHAR const *g_pwszPublishedBy;
|
|
WCHAR const *g_pwszPolicyDeniedRequest;
|
|
WCHAR const *g_pwszIssued;
|
|
WCHAR const *g_pwszUnderSubmission;
|
|
WCHAR const *g_pwszCertConstructionError;
|
|
WCHAR const *g_pwszRequestParsingError;
|
|
WCHAR const *g_pwszRequestSigError;
|
|
WCHAR const *g_pwszKeyArchivalError;
|
|
WCHAR const *g_pwszArchiveSigningKeyError;
|
|
|
|
WCHAR const *g_pwszRevokedBy;
|
|
WCHAR const *g_pwszUnrevokedBy;
|
|
WCHAR const *g_pwszResubmittedBy;
|
|
WCHAR const *g_pwszPrintfCertRequestDisposition;
|
|
WCHAR const *g_pwszUnknownSubject;
|
|
WCHAR const *g_pwszIntermediateCAStore;
|
|
WCHAR const *g_pwszPublishError;
|
|
WCHAR const *g_pwszYes;
|
|
WCHAR const *g_pwszNo;
|
|
WCHAR const *g_pwszInvalidIssuancePolicies;
|
|
WCHAR const *g_pwszInvalidApplicationPolicies;
|
|
|
|
LPWSTR g_wszzSecuredAttributes = NULL;
|
|
|
|
LPCWSTR g_wszzSecuredAttributesDefault = wszzDEFAULTSIGNEDATTRIBUTES;
|
|
|
|
|
|
typedef struct _STRINGINITMAP
|
|
{
|
|
int idResource;
|
|
WCHAR const **ppwszResource;
|
|
} STRINGINITMAP;
|
|
|
|
STRINGINITMAP g_aStringInitStrings[] = {
|
|
{ IDS_REVOKEDBY, &g_pwszRevokedBy },
|
|
{ IDS_UNREVOKEDBY, &g_pwszUnrevokedBy },
|
|
{ IDS_RESUBMITTEDBY, &g_pwszResubmittedBy },
|
|
{ IDS_REQUESTEDBY, &g_pwszRequestedBy },
|
|
{ IDS_DENIEDBY, &g_pwszDeniedBy },
|
|
{ IDS_PUBLISHEDBY, &g_pwszPublishedBy },
|
|
{ IDS_POLICYDENIED, &g_pwszPolicyDeniedRequest },
|
|
{ IDS_ISSUED, &g_pwszIssued },
|
|
{ IDS_CERTCONSTRUCTIONERROR, &g_pwszCertConstructionError },
|
|
{ IDS_REQUESTPARSEERROR, &g_pwszRequestParsingError },
|
|
{ IDS_REQUESTSIGERROR, &g_pwszRequestSigError },
|
|
{ IDS_KEYARCHIVALERROR, &g_pwszKeyArchivalError },
|
|
{ IDS_ARCHIVESIGNINGKEYERROR, &g_pwszArchiveSigningKeyError },
|
|
{ IDS_UNDERSUBMISSION, &g_pwszUnderSubmission },
|
|
{ IDS_PRINTFCERTREQUESTDISPOSITION, &g_pwszPrintfCertRequestDisposition },
|
|
{ IDS_UNKNOWNSUBJECT, &g_pwszUnknownSubject },
|
|
{ IDS_INTERMEDIATECASTORE, &g_pwszIntermediateCAStore },
|
|
{ IDS_PUBLISHERROR, &g_pwszPublishError },
|
|
{ IDS_YES, &g_pwszYes },
|
|
{ IDS_NO, &g_pwszNo },
|
|
{ IDS_ALLOW, &g_pwszAuditResources[0] },
|
|
{ IDS_DENY, &g_pwszAuditResources[1] },
|
|
{ IDS_CAADMIN, &g_pwszAuditResources[2] },
|
|
{ IDS_OFFICER, &g_pwszAuditResources[3] },
|
|
{ IDS_READ, &g_pwszAuditResources[4] },
|
|
{ IDS_ENROLL, &g_pwszAuditResources[5] },
|
|
{ IDS_INVALIDISSUANCEPOLICIES, &g_pwszInvalidIssuancePolicies },
|
|
{ IDS_INVALIDAPPLICATIONPOLICIES, &g_pwszInvalidApplicationPolicies },
|
|
};
|
|
|
|
|
|
HANDLE *g_rgDSCache = NULL;
|
|
DWORD g_cDSCacheCur;
|
|
BOOL g_fcritsecDSCache = FALSE;
|
|
CRITICAL_SECTION g_critsecDSCache;
|
|
|
|
|
|
// Check if retriever is requester or subject of the cert being retrieved
|
|
HRESULT coreCheckRetrieveAccessRight(
|
|
ICertDBRow *prow,
|
|
IN WCHAR const *pcwszUserName)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszRequesterName = NULL;
|
|
WCHAR *pwszCallerName = NULL;
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropRequesterName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
(BYTE **) &pwszRequesterName);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpIfError(hr, error, "PKCSGetProperty RequesterName");
|
|
}
|
|
|
|
if (S_OK != hr ||
|
|
NULL == pwszRequesterName ||
|
|
0 != mylstrcmpiL(pcwszUserName, pwszRequesterName))
|
|
{
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropCallerName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
(BYTE **) &pwszCallerName);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpIfError(hr, error, "PKCSGetProperty CallerName");
|
|
}
|
|
|
|
if (S_OK != hr ||
|
|
NULL == pwszCallerName ||
|
|
0 != mylstrcmpiL(pcwszUserName, pwszCallerName))
|
|
{
|
|
CAuditEvent audit(0, g_dwAuditFilter);
|
|
|
|
hr = audit.AccessCheck(
|
|
CA_ACCESS_ALLREADROLES,
|
|
audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
|
|
_JumpIfError(hr, error, "CAuditEvent::AccessCheck");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
LOCAL_FREE(pwszRequesterName);
|
|
LOCAL_FREE(pwszCallerName);
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreDSInitCache()
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = S_OK;
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&g_critsecDSCache);
|
|
g_fcritsecDSCache = TRUE;
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
_JumpIfError(hr, error, "InitializeCriticalSection");
|
|
|
|
g_rgDSCache = (HANDLE *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
g_dwSessionCount * sizeof(g_rgDSCache[0]));
|
|
if (NULL == g_rgDSCache)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
g_cDSCacheCur = 0;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreDSGetHandle(
|
|
OUT HANDLE *phDS,
|
|
OUT BOOL *pfCached)
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hDS;
|
|
|
|
*phDS = NULL;
|
|
*pfCached = TRUE;
|
|
|
|
hDS = NULL;
|
|
|
|
EnterCriticalSection(&g_critsecDSCache);
|
|
if (0 != g_cDSCacheCur)
|
|
{
|
|
hDS = g_rgDSCache[--g_cDSCacheCur];
|
|
}
|
|
LeaveCriticalSection(&g_critsecDSCache);
|
|
|
|
if (NULL == hDS)
|
|
{
|
|
*pfCached = FALSE;
|
|
hr = DsBind(NULL, NULL, &hDS);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
_JumpError(hr, error, "DsBind");
|
|
}
|
|
}
|
|
*phDS = hDS;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
DWORD
|
|
coreDSUnbindWorker(
|
|
OPTIONAL IN OUT VOID *pvparms)
|
|
{
|
|
HANDLE hDS = (HANDLE) pvparms;
|
|
|
|
DsUnBind(&hDS);
|
|
return(0);
|
|
}
|
|
|
|
|
|
VOID
|
|
coreDSUnbind(
|
|
IN HANDLE hDS,
|
|
IN BOOL fSynchronous)
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hThread = NULL;
|
|
DWORD ThreadId;
|
|
|
|
if (NULL != hDS)
|
|
{
|
|
if (!fSynchronous)
|
|
{
|
|
hThread = CreateThread(
|
|
NULL, // lpThreadAttributes (Security Attr)
|
|
0, // dwStackSize
|
|
coreDSUnbindWorker,
|
|
hDS, // lpParameter
|
|
0, // dwCreationFlags
|
|
&ThreadId);
|
|
if (NULL == hThread)
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError(hr, "CreateThread");
|
|
}
|
|
}
|
|
if (NULL == hThread)
|
|
{
|
|
coreDSUnbindWorker(hDS);
|
|
}
|
|
}
|
|
|
|
//error:
|
|
if (NULL != hThread)
|
|
{
|
|
CloseHandle(hThread);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
coreDSEmptyCache(
|
|
IN BOOL fSynchronous)
|
|
{
|
|
EnterCriticalSection(&g_critsecDSCache);
|
|
while (0 != g_cDSCacheCur)
|
|
{
|
|
coreDSUnbind(g_rgDSCache[--g_cDSCacheCur], fSynchronous);
|
|
}
|
|
LeaveCriticalSection(&g_critsecDSCache);
|
|
}
|
|
|
|
|
|
VOID
|
|
coreDSReleaseHandle(
|
|
IN HANDLE hDS)
|
|
{
|
|
// only cache g_dwSessionCount DS handles. They're all equivalent,
|
|
// so if the one being released won't fit in the array, toss it.
|
|
|
|
EnterCriticalSection(&g_critsecDSCache);
|
|
CSASSERT(0 != g_dwSessionCount);
|
|
if (g_cDSCacheCur < g_dwSessionCount)
|
|
{
|
|
g_rgDSCache[g_cDSCacheCur++] = hDS;
|
|
hDS = NULL;
|
|
}
|
|
LeaveCriticalSection(&g_critsecDSCache);
|
|
|
|
if (NULL != hDS)
|
|
{
|
|
coreDSUnbind(hDS, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
typedef struct _LDAPCACHE
|
|
{
|
|
_LDAPCACHE *plcNext;
|
|
WCHAR *pwszDomainDns;
|
|
LDAP *pld;
|
|
} LDAPCACHE;
|
|
|
|
|
|
typedef struct _FORESTLDAPCACHE
|
|
{
|
|
LDAPCACHE *plc;
|
|
DWORD clc;
|
|
WCHAR *pwszDomainDns;
|
|
BOOL fcritsec;
|
|
CRITICAL_SECTION critsec;
|
|
} FORESTLDAPCACHE;
|
|
|
|
FORESTLDAPCACHE *g_rgForestLdapCache = NULL;
|
|
DWORD g_cForestLdapCache = 0;
|
|
|
|
|
|
HRESULT
|
|
coreLdapInitCache()
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwsz;
|
|
FORESTLDAPCACHE *pflcEnd;
|
|
FORESTLDAPCACHE *pflc;
|
|
|
|
g_cForestLdapCache = 1; // local Forest
|
|
if (NULL != g_pwszzAlternatePublishDomains)
|
|
{
|
|
for (
|
|
pwsz = g_pwszzAlternatePublishDomains;
|
|
L'\0' != *pwsz;
|
|
pwsz += wcslen(pwsz) + 1)
|
|
{
|
|
g_cForestLdapCache++;
|
|
}
|
|
}
|
|
g_rgForestLdapCache = (FORESTLDAPCACHE *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
g_cForestLdapCache * sizeof(g_rgForestLdapCache[0]));
|
|
if (NULL == g_rgForestLdapCache)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
pwsz = g_pwszzAlternatePublishDomains;
|
|
pflcEnd = &g_rgForestLdapCache[g_cForestLdapCache];
|
|
for (pflc = g_rgForestLdapCache; pflc < pflcEnd; pflc++)
|
|
{
|
|
if (pflc > g_rgForestLdapCache)
|
|
{
|
|
pflc->pwszDomainDns = pwsz;
|
|
pwsz += wcslen(pwsz) + 1;
|
|
}
|
|
hr = S_OK;
|
|
__try
|
|
{
|
|
InitializeCriticalSection(&pflc->critsec);
|
|
pflc->fcritsec = TRUE;
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
_JumpIfError(hr, error, "InitializeCriticalSection");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
coreLdapUnbind(
|
|
IN OUT LDAPCACHE *plc)
|
|
{
|
|
if (NULL != plc->pld)
|
|
{
|
|
ldap_unbind(plc->pld);
|
|
plc->pld = NULL;
|
|
}
|
|
if (NULL != plc->pwszDomainDns)
|
|
{
|
|
LocalFree(plc->pwszDomainDns);
|
|
plc->pwszDomainDns = NULL;
|
|
}
|
|
LocalFree(plc);
|
|
}
|
|
|
|
|
|
VOID
|
|
coreLdapFreeCache()
|
|
{
|
|
if (NULL != g_rgForestLdapCache)
|
|
{
|
|
FORESTLDAPCACHE *pflcEnd = &g_rgForestLdapCache[g_cForestLdapCache];
|
|
FORESTLDAPCACHE *pflc;
|
|
|
|
for (pflc = g_rgForestLdapCache; pflc < pflcEnd; pflc++)
|
|
{
|
|
if (pflc->fcritsec)
|
|
{
|
|
LDAPCACHE *plc;
|
|
|
|
EnterCriticalSection(&pflc->critsec);
|
|
|
|
while (NULL != pflc->plc)
|
|
{
|
|
plc = pflc->plc;
|
|
pflc->plc = plc->plcNext;
|
|
plc->plcNext = NULL;
|
|
coreLdapUnbind(plc);
|
|
}
|
|
|
|
LeaveCriticalSection(&pflc->critsec);
|
|
|
|
DeleteCriticalSection(&pflc->critsec);
|
|
pflc->fcritsec = FALSE;
|
|
}
|
|
}
|
|
LocalFree(g_rgForestLdapCache);
|
|
g_rgForestLdapCache = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreLdapGetCachedHandle(
|
|
IN DWORD iForest,
|
|
OPTIONAL IN WCHAR const *pwszDomainDns,
|
|
OUT WCHAR const **ppwszDomainDns,
|
|
OUT LDAPCACHE **pplc)
|
|
{
|
|
HRESULT hr;
|
|
FORESTLDAPCACHE *pflc = NULL;
|
|
BOOL fCritSecEntered = FALSE;
|
|
LDAPCACHE *plc;
|
|
LDAPCACHE **pplcPrev;
|
|
|
|
*ppwszDomainDns = NULL;
|
|
*pplc = NULL;
|
|
|
|
if (NULL == g_rgForestLdapCache || iForest >= g_cForestLdapCache)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "g_rgForestLdapCache");
|
|
}
|
|
pflc = &g_rgForestLdapCache[iForest];
|
|
*ppwszDomainDns = pflc->pwszDomainDns;
|
|
|
|
EnterCriticalSection(&pflc->critsec);
|
|
fCritSecEntered = TRUE;
|
|
|
|
pplcPrev = &pflc->plc;
|
|
for (plc = pflc->plc; ; plc = plc->plcNext)
|
|
{
|
|
if (NULL == plc)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError2(hr, error, "pflc->plc", hr);
|
|
}
|
|
if (NULL == pwszDomainDns ||
|
|
0 == mylstrcmpiL(plc->pwszDomainDns, pwszDomainDns))
|
|
{
|
|
break;
|
|
}
|
|
pplcPrev = &plc->plcNext;
|
|
}
|
|
*pplcPrev = plc->plcNext;
|
|
plc->plcNext = NULL;
|
|
*pplc = plc;
|
|
CSASSERT(0 < pflc->clc);
|
|
pflc->clc--;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pflc && fCritSecEntered)
|
|
{
|
|
LeaveCriticalSection(&pflc->critsec);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreLdapBindHandle(
|
|
IN WCHAR const *pwszDomainDns,
|
|
OUT LDAPCACHE **pplc)
|
|
{
|
|
HRESULT hr;
|
|
LDAPCACHE *plc = NULL;
|
|
|
|
plc = (LDAPCACHE *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*plc));
|
|
if (NULL == plc)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CSASSERT(NULL != pwszDomainDns);
|
|
|
|
hr = myDupString(pwszDomainDns, &plc->pwszDomainDns);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
hr = myRobustLdapBindEx(
|
|
0, // dwFlags1
|
|
RLBF_REQUIRE_SECURE_LDAP, // dwFlags2
|
|
LDAP_VERSION2, // uVersion
|
|
pwszDomainDns, // pwszDomainName
|
|
&plc->pld, // ppld
|
|
NULL); // ppwszForestDNSName
|
|
_JumpIfError(hr, error, "myRobustLdapBindEx");
|
|
|
|
*pplc = plc;
|
|
plc = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != plc)
|
|
{
|
|
coreLdapUnbind(plc);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreLdapGetHandle(
|
|
IN DWORD iForest,
|
|
OPTIONAL IN WCHAR const *pwszDomainDns, // NULL for 0 < iForest
|
|
OUT LDAPCACHE **pplc,
|
|
OUT BOOL *pfCached)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *pwszForestDomainDns;
|
|
|
|
CSASSERT(NULL != pplc);
|
|
*pplc = NULL;
|
|
*pfCached = TRUE;
|
|
|
|
hr = coreLdapGetCachedHandle(
|
|
iForest,
|
|
pwszDomainDns,
|
|
&pwszForestDomainDns,
|
|
pplc);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "coreGetLdapCache");
|
|
*pfCached = FALSE;
|
|
if (NULL == pwszDomainDns)
|
|
{
|
|
CSASSERT(0 < iForest);
|
|
if (NULL == pwszForestDomainDns)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
_JumpError(hr, error, "pwszForestDomainDns NULL");
|
|
}
|
|
pwszDomainDns = pwszForestDomainDns;
|
|
}
|
|
hr = coreLdapBindHandle(pwszDomainDns, pplc);
|
|
_JumpIfError(hr, error, "coreBindLdapHandle");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
coreLdapReleaseHandle(
|
|
IN DWORD iForest,
|
|
IN LDAPCACHE *plc)
|
|
{
|
|
if (NULL != g_rgForestLdapCache && iForest < g_cForestLdapCache)
|
|
{
|
|
FORESTLDAPCACHE *pflc = &g_rgForestLdapCache[iForest];
|
|
|
|
if (pflc->fcritsec)
|
|
{
|
|
EnterCriticalSection(&pflc->critsec);
|
|
plc->plcNext = pflc->plc;
|
|
pflc->plc = plc;
|
|
pflc->clc++;
|
|
LeaveCriticalSection(&pflc->critsec);
|
|
plc = NULL;
|
|
}
|
|
}
|
|
if (NULL != plc)
|
|
{
|
|
coreLdapUnbind(plc);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
myAddDomainName(
|
|
IN WCHAR const *pwszSamName,
|
|
OUT WCHAR **ppwszSamName, // *ppwszSamName is NULL if unchanged
|
|
OUT WCHAR const **ppwszUserName)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *pwszUserName;
|
|
WCHAR wszDomain[MAX_PATH];
|
|
|
|
*ppwszSamName = NULL;
|
|
*ppwszUserName = NULL;
|
|
|
|
if (L'\0' == *pwszSamName)
|
|
{
|
|
hr = E_ACCESSDENIED; // can't have a zero length name
|
|
_JumpError(hr, error, "zero length name");
|
|
}
|
|
|
|
// See if it includes a domain name.
|
|
|
|
pwszUserName = wcschr(pwszSamName, L'\\');
|
|
if (NULL == pwszUserName)
|
|
{
|
|
DWORD cwc = ARRAYSIZE(wszDomain);
|
|
WCHAR *pwsz;
|
|
|
|
// There was no domain portion, so assume part of the current domain.
|
|
|
|
if (GetUserNameEx(NameSamCompatible, wszDomain, &cwc))
|
|
{
|
|
// Fix NULL termination bug
|
|
|
|
if (0 != cwc)
|
|
{
|
|
cwc--;
|
|
}
|
|
wszDomain[cwc] = L'\0';
|
|
pwsz = wcschr(wszDomain, L'\\');
|
|
if (NULL != pwsz)
|
|
{
|
|
pwsz++;
|
|
wcsncpy(pwsz, pwszSamName, ARRAYSIZE(wszDomain) - cwc);
|
|
|
|
hr = myDupString(wszDomain, ppwszSamName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pwszSamName = *ppwszSamName;
|
|
}
|
|
}
|
|
}
|
|
pwszUserName = wcschr(pwszSamName, L'\\');
|
|
if (NULL == pwszUserName)
|
|
{
|
|
pwszUserName = pwszSamName;
|
|
}
|
|
else
|
|
{
|
|
pwszUserName++;
|
|
}
|
|
*ppwszUserName = pwszUserName;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreGetDNFromSamName(
|
|
IN WCHAR const *pwszSamName,
|
|
OUT WCHAR **ppwszDN)
|
|
{
|
|
HRESULT hr;
|
|
HANDLE hDS = NULL;
|
|
DS_NAME_RESULT *pNameResults = NULL;
|
|
|
|
CSASSERT(NULL != ppwszDN);
|
|
*ppwszDN = NULL;
|
|
|
|
for (;;)
|
|
{
|
|
BOOL fCached;
|
|
|
|
if (NULL != hDS)
|
|
{
|
|
coreDSUnbind(hDS, FALSE);
|
|
hDS = NULL;
|
|
coreDSEmptyCache(FALSE);
|
|
}
|
|
hr = coreDSGetHandle(&hDS, &fCached);
|
|
_JumpIfError(hr, error, "coreGetDSHandle");
|
|
|
|
// Got a connection. Crack the name:
|
|
|
|
hr = DsCrackNames(
|
|
hDS,
|
|
DS_NAME_NO_FLAGS,
|
|
DS_NT4_ACCOUNT_NAME,
|
|
DS_FQDN_1779_NAME,
|
|
1, // one name
|
|
&pwszSamName, // one name (IN)
|
|
&pNameResults); // OUT
|
|
if (S_OK != hr)
|
|
{
|
|
// It's probably not worth flushing the DS cache only when certain
|
|
// errors are detected.
|
|
|
|
hr = myHError(hr);
|
|
if (fCached)
|
|
{
|
|
_PrintError(hr, "DsCrackNames");
|
|
continue;
|
|
}
|
|
_JumpError(hr, error, "DsCrackNames");
|
|
}
|
|
if (1 > pNameResults->cItems ||
|
|
DS_NAME_NO_ERROR != pNameResults->rItems[0].status)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
|
|
_JumpError(hr, error, "DsCrackNames result");
|
|
}
|
|
break;
|
|
}
|
|
hr = myDupString(pNameResults->rItems[0].pName, ppwszDN);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
error:
|
|
if (NULL != pNameResults)
|
|
{
|
|
DsFreeNameResult(pNameResults);
|
|
}
|
|
if (NULL != hDS)
|
|
{
|
|
coreDSReleaseHandle(hDS);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreGetComContextUserDNFromSamName(
|
|
IN BOOL fDeleteUserDNOnly,
|
|
OPTIONAL IN WCHAR const *pwszSamName,
|
|
IN LONG Context,
|
|
IN DWORD dwComContextIndex,
|
|
OPTIONAL OUT WCHAR const **ppwszDN) // do NOT free!
|
|
{
|
|
HRESULT hr;
|
|
CERTSRV_COM_CONTEXT *pComContext;
|
|
|
|
hr = ComGetClientInfo(Context, dwComContextIndex, &pComContext);
|
|
_JumpIfError(hr, error, "ComGetClientInfo");
|
|
|
|
if (fDeleteUserDNOnly)
|
|
{
|
|
if (NULL != pComContext->pwszUserDN)
|
|
{
|
|
LocalFree(pComContext->pwszUserDN);
|
|
pComContext->pwszUserDN = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (NULL == pComContext->pwszUserDN)
|
|
{
|
|
hr = coreGetDNFromSamName(pwszSamName, &pComContext->pwszUserDN);
|
|
_JumpIfError(hr, error, "coreGetDNFromSamName");
|
|
}
|
|
}
|
|
if (NULL != ppwszDN)
|
|
{
|
|
*ppwszDN = pComContext->pwszUserDN;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CoreSetComContextUserDN(
|
|
IN DWORD dwRequestId,
|
|
IN LONG Context,
|
|
IN DWORD dwComContextIndex,
|
|
OPTIONAL OUT WCHAR const **ppwszDN) // do NOT free!
|
|
{
|
|
HRESULT hr;
|
|
ICertDBRow *prow = NULL;
|
|
WCHAR *pwszSamName = NULL;
|
|
WCHAR *pwszSamNamePatched = NULL;
|
|
WCHAR const *pwszUserName;
|
|
|
|
hr = g_pCertDB->OpenRow(
|
|
PROPOPEN_READONLY | PROPTABLE_REQCERT,
|
|
dwRequestId,
|
|
NULL,
|
|
&prow);
|
|
_JumpIfError(hr, error, "OpenRow");
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropRequesterName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
(BYTE **) &pwszSamName);
|
|
_JumpIfError(hr, error, "PKCSGetProperty");
|
|
|
|
hr = myAddDomainName(pwszSamName, &pwszSamNamePatched, &pwszUserName);
|
|
_JumpIfError(hr, error, "myAddDomainName");
|
|
|
|
hr = coreGetComContextUserDNFromSamName(
|
|
FALSE, // fDeleteUserDNOnly
|
|
NULL != pwszSamNamePatched? pwszSamNamePatched : pwszSamName,
|
|
Context,
|
|
dwComContextIndex,
|
|
ppwszDN);
|
|
_JumpIfError(hr, error, "coreGetComContextUserDNFromSamName");
|
|
|
|
error:
|
|
if (NULL != pwszSamName)
|
|
{
|
|
LocalFree(pwszSamName);
|
|
}
|
|
if (NULL != pwszSamNamePatched)
|
|
{
|
|
LocalFree(pwszSamNamePatched);
|
|
}
|
|
if (NULL != prow)
|
|
{
|
|
prow->Release();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CoreSetArchivedKey(
|
|
IN OUT CERTSRV_COM_CONTEXT *pComContext)
|
|
{
|
|
HRESULT hr;
|
|
ICertDBRow *prow = NULL;
|
|
DWORD cb;
|
|
|
|
CSASSERT(0 ==
|
|
((CCCF_KEYARCHIVEDSET | CCCF_KEYARCHIVED) & pComContext->dwFlags));
|
|
|
|
hr = g_pCertDB->OpenRow(
|
|
PROPOPEN_READONLY | PROPTABLE_REQCERT,
|
|
pComContext->RequestId,
|
|
NULL,
|
|
&prow);
|
|
_JumpIfError(hr, error, "OpenRow");
|
|
|
|
cb = 0;
|
|
hr = prow->GetProperty(
|
|
g_wszPropRequestRawArchivedKey,
|
|
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
&cb,
|
|
NULL);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpIfError(hr, error, "PKCSGetProperty");
|
|
|
|
if (0 < cb)
|
|
{
|
|
pComContext->dwFlags |= CCCF_KEYARCHIVED;
|
|
}
|
|
}
|
|
pComContext->dwFlags |= CCCF_KEYARCHIVEDSET;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != prow)
|
|
{
|
|
prow->Release();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
DWORD g_PolicyFlags;
|
|
|
|
|
|
HRESULT
|
|
CoreSetDisposition(
|
|
IN ICertDBRow *prow,
|
|
IN DWORD Disposition)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = prow->SetProperty(
|
|
g_wszPropRequestDisposition,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
sizeof(Disposition),
|
|
(BYTE const *) &Disposition);
|
|
_JumpIfError(hr, error, "SetProperty(disposition)");
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
DWORD
|
|
coreRegGetTimePeriod(
|
|
IN HKEY hkeyCN,
|
|
IN WCHAR const *pwszRegPeriodCount,
|
|
IN WCHAR const *pwszRegPeriodString,
|
|
OUT enum ENUM_PERIOD *penumPeriod,
|
|
OUT LONG *plCount)
|
|
{
|
|
HRESULT hr;
|
|
LONG lCount;
|
|
DWORD dwType;
|
|
DWORD cbValue;
|
|
|
|
cbValue = sizeof(lCount);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
pwszRegPeriodCount,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &lCount,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(lCount) == cbValue)
|
|
{
|
|
WCHAR awcPeriod[10];
|
|
|
|
cbValue = sizeof(awcPeriod);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
pwszRegPeriodString,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) awcPeriod,
|
|
&cbValue);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
_JumpIfError(hr, error, "RegQueryValueEx");
|
|
}
|
|
else
|
|
{
|
|
|
|
if (REG_SZ != dwType || sizeof(awcPeriod) <= cbValue)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpIfErrorStr(hr, error, "time period string", pwszRegPeriodString);
|
|
}
|
|
hr = myTranslatePeriodUnits(
|
|
awcPeriod,
|
|
lCount,
|
|
penumPeriod,
|
|
plCount);
|
|
_JumpIfError(hr, error, "myTranslatePeriodUnits");
|
|
}
|
|
}
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// Converts a REG_SZ Subject template into a double null terminated REG_MULTI_SZ type string
|
|
|
|
DWORD
|
|
coreConvertSubjectTemplate(
|
|
OUT WCHAR* pwszz,
|
|
IN WCHAR* pwszTemplate,
|
|
IN DWORD cwc)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszToken;
|
|
WCHAR *pwszRemain = pwszTemplate;
|
|
WCHAR *pwszzNew = pwszz;
|
|
DWORD cwszzNew = 0;
|
|
BOOL fSplit;
|
|
|
|
for (;;)
|
|
{
|
|
pwszToken = PKCSSplitToken(&pwszRemain, wszNAMESEPARATORDEFAULT, &fSplit);
|
|
if (NULL == pwszToken)
|
|
{
|
|
*pwszzNew = L'\0';
|
|
break;
|
|
}
|
|
cwszzNew += (1 + wcslen(pwszToken)) * sizeof(WCHAR);
|
|
if (cwszzNew > cwc)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
_JumpError(hr, error, "overflow");
|
|
}
|
|
wcscpy(pwszzNew, pwszToken);
|
|
pwszzNew = wcschr(pwszzNew, L'\0');
|
|
pwszzNew++;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreReadRegStringValue(
|
|
IN HKEY hkey,
|
|
IN WCHAR const *pwszName,
|
|
OUT WCHAR **ppwszzValue)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb;
|
|
DWORD cwc;
|
|
DWORD dwType;
|
|
WCHAR *pwszzValue = NULL;
|
|
|
|
*ppwszzValue = NULL;
|
|
cb = 0;
|
|
cwc = 0;
|
|
for (;;)
|
|
{
|
|
hr = RegQueryValueEx(
|
|
hkey,
|
|
pwszName,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) pwszzValue,
|
|
&cb);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
_JumpErrorStr(hr, error, "RegQueryValueEx", pwszName);
|
|
}
|
|
if (NULL != pwszzValue)
|
|
{
|
|
pwszzValue[cwc] = L'\0';
|
|
pwszzValue[cwc + 1] = L'\0';
|
|
break;
|
|
}
|
|
if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "RegQueryValueEx: value type");
|
|
}
|
|
cwc = (cb + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
|
|
pwszzValue = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(cwc + 2) * sizeof(WCHAR));
|
|
if (NULL == pwszzValue)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
}
|
|
*ppwszzValue = pwszzValue;
|
|
pwszzValue = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszzValue)
|
|
{
|
|
LocalFree(pwszzValue);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CoreInit(
|
|
IN BOOL fAuditEnabled)
|
|
{
|
|
HRESULT hr;
|
|
HKEY hkeyConfig = NULL;
|
|
HKEY hkeyCN = NULL;
|
|
BYTE abbuf[MAX_PATH * sizeof(TCHAR)];
|
|
WCHAR awcTemplate[MAX_PATH];
|
|
DWORD cbbuf;
|
|
DWORD dwType;
|
|
WCHAR *pwsz;
|
|
DWORD dw, dwCASetupStatus;
|
|
BOOL fLogError = TRUE;
|
|
DWORD LogMsg = MSG_BAD_REGISTRY;
|
|
WCHAR const *pwszLog = NULL;
|
|
WCHAR *pwszHighSerial = NULL;
|
|
int i;
|
|
DWORD cbValue;
|
|
DWORD dwEnabled;
|
|
CAuditEvent AuditSettings;
|
|
WCHAR *pwszFullRequestFileName = NULL;
|
|
|
|
hr = myGetMachineDnsName(&g_pwszServerName);
|
|
_JumpIfError(hr, error, "myGetMachineDnsName");
|
|
|
|
for (i = 0; i < ARRAYSIZE(g_aStringInitStrings); i++)
|
|
{
|
|
WCHAR const *pwszT;
|
|
|
|
pwszT = myLoadResourceString(g_aStringInitStrings[i].idResource);
|
|
if (NULL == pwszT)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myLoadResourceString");
|
|
}
|
|
*g_aStringInitStrings[i].ppwszResource = pwszT;
|
|
}
|
|
g_hrJetVersionStoreOutOfMemory = myJetHResult(JET_errVersionStoreOutOfMemory);
|
|
|
|
hr = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
g_wszRegKeyConfigPath,
|
|
0, // dwReserved
|
|
KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_QUERY_VALUE,
|
|
&hkeyConfig);
|
|
_JumpIfError(hr, error, "RegOpenKeyEx(Config)");
|
|
|
|
cbbuf = sizeof(abbuf);
|
|
hr = RegQueryValueEx(
|
|
hkeyConfig,
|
|
g_wszRegDirectory,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
abbuf,
|
|
&cbbuf);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
}
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
|
|
{
|
|
_JumpIfError(hr, error, "RegQueryValueEx(Base)");
|
|
|
|
if (REG_SZ != dwType)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "RegQueryValueEx(Base)");
|
|
}
|
|
if (sizeof(abbuf) < cbbuf)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
|
|
_JumpError(hr, error, "RegQueryValueEx(Base)");
|
|
}
|
|
CopyMemory(g_wszSharedFolder, abbuf, cbbuf);
|
|
}
|
|
DBGPRINT((DBG_SS_CERTSRVI, "Shared Folder = '%ws'\n", g_wszSharedFolder));
|
|
|
|
cbbuf = sizeof(g_dwSessionCount);
|
|
hr = RegQueryValueEx(
|
|
hkeyConfig,
|
|
wszREGDBSESSIONCOUNT,
|
|
NULL,
|
|
NULL,
|
|
(BYTE *) &g_dwSessionCount,
|
|
&cbbuf);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr(hr, "RegQueryValueEx", wszREGDBSESSIONCOUNT);
|
|
g_dwSessionCount = DBSESSIONCOUNTDEFAULT;
|
|
}
|
|
if (DBSESSIONCOUNTMIN > g_dwSessionCount)
|
|
{
|
|
g_dwSessionCount = DBSESSIONCOUNTMIN;
|
|
}
|
|
if (DBSESSIONCOUNTMAX < g_dwSessionCount)
|
|
{
|
|
g_dwSessionCount = DBSESSIONCOUNTMAX;
|
|
}
|
|
|
|
// Find out the name of the active CA(s)
|
|
|
|
g_wszSanitizedName[0] = L'\0';
|
|
cbbuf = sizeof(g_wszSanitizedName);
|
|
hr = RegQueryValueEx(
|
|
hkeyConfig,
|
|
g_wszRegActive,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) g_wszSanitizedName,
|
|
&cbbuf);
|
|
if ((HRESULT) ERROR_FILE_NOT_FOUND == hr)
|
|
{
|
|
#define szForgotSetup "\n\nDid you forget to setup the Cert Server?\n\n\n"
|
|
|
|
CONSOLEPRINT0((MAXDWORD, szForgotSetup));
|
|
}
|
|
_JumpIfError(hr, error, "RegQueryValueEx(Base)");
|
|
|
|
if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "RegQueryValueEx: value type");
|
|
}
|
|
g_wszSanitizedName[cbbuf / sizeof(WCHAR)] = L'\0';
|
|
if (REG_MULTI_SZ == dwType)
|
|
{
|
|
i = wcslen(g_wszSanitizedName);
|
|
if (L'\0' != g_wszSanitizedName[i + 1])
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "RegQueryValueEx: multiple Active CAs");
|
|
}
|
|
}
|
|
DBGPRINT((DBG_SS_CERTSRVI, "Active CA (Sanitized Name) = '%ws'\n", g_wszSanitizedName));
|
|
|
|
pwszLog = g_wszSanitizedName;
|
|
|
|
hr = mySanitizedNameToDSName(g_wszSanitizedName, &g_pwszSanitizedDSName);
|
|
_JumpIfError(hr, error, "mySanitizedNameToDSName");
|
|
|
|
hr = RegOpenKeyEx(
|
|
hkeyConfig,
|
|
g_wszSanitizedName,
|
|
0, // dwReserved
|
|
KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_QUERY_VALUE,
|
|
&hkeyCN);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
_JumpError(hr, error, "RegOpenKeyEx");
|
|
}
|
|
|
|
cbValue = sizeof(g_wszCommonName) - 2 * sizeof(WCHAR);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGCOMMONNAME,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *)g_wszCommonName,
|
|
&cbValue);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
_JumpError(hr, error, "RegOpenKeyEx");
|
|
}
|
|
if (REG_SZ != dwType)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "Couldn't find CA common name");
|
|
}
|
|
g_wszCommonName[cbValue / sizeof(WCHAR)] = L'\0';
|
|
|
|
pwszLog = g_wszCommonName;
|
|
|
|
cbValue = sizeof(dwEnabled);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegEnabled,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dwEnabled,
|
|
&cbValue);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
_JumpError(hr, error, "RegQueryValueEx");
|
|
}
|
|
if (REG_DWORD == dwType &&
|
|
sizeof(dwEnabled) == cbValue &&
|
|
0 == dwEnabled)
|
|
{
|
|
DBGPRINT((DBG_SS_CERTSRVI, "CN = '%ws' DISABLED!\n", g_wszSanitizedName));
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "RegQueryValueEx: Active CA DISABLED!");
|
|
}
|
|
DBGPRINT((DBG_SS_CERTSRVI, "CN = '%ws': Enabled\n", g_wszSanitizedName));
|
|
|
|
// to check machine setup status
|
|
hr = GetSetupStatus(NULL, &dw);
|
|
_JumpIfError(hr, error, "GetSetupStatus");
|
|
|
|
if (!(SETUP_SERVER_FLAG & dw))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE);
|
|
_JumpError(hr, error, "Server installation was not complete");
|
|
}
|
|
if (SETUP_SERVER_UPGRADED_FLAG & dw)
|
|
{
|
|
g_fServerUpgraded = TRUE;
|
|
DBGPRINT((
|
|
DBG_SS_CERTSRV,
|
|
"CoreInit: read SETUP_SERVER_UPGRADED_FLAG\n"));
|
|
}
|
|
|
|
// check per ca
|
|
hr = GetSetupStatus(g_wszSanitizedName, &dwCASetupStatus);
|
|
_JumpIfError(hr, error, "GetSetupStatus");
|
|
|
|
dw = dwCASetupStatus;
|
|
|
|
if (SETUP_SUSPEND_FLAG & dw)
|
|
{
|
|
LogMsg = MSG_E_INCOMPLETE_HIERARCHY;
|
|
hr = myGetCARegFileNameTemplate(
|
|
wszREGREQUESTFILENAME,
|
|
g_pwszServerName,
|
|
g_wszSanitizedName,
|
|
0,
|
|
0,
|
|
&pwszFullRequestFileName);
|
|
_JumpIfErrorStr(hr, error, "myGetCARegFileNameTemplate wszREGREQUESTFILENAME",
|
|
g_wszSanitizedName);
|
|
|
|
pwszLog = pwszFullRequestFileName;
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INSTALL_SUSPEND);
|
|
_JumpError(hr, error, "Hierarchy setup incomplete");
|
|
}
|
|
if (!(SETUP_SERVER_FLAG & dw))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE);
|
|
_JumpError(hr, error, "Server installation was not complete");
|
|
}
|
|
if (SETUP_FORCECRL_FLAG & dw)
|
|
{
|
|
// Don't clear SETUP_FORCECRL_FLAG until CRLs successfully generated
|
|
|
|
hr = myDeleteCertRegValue(
|
|
g_wszSanitizedName,
|
|
NULL,
|
|
NULL,
|
|
wszREGCRLNEXTPUBLISH);
|
|
_PrintIfErrorStr2(
|
|
hr,
|
|
"myDeleteCertRegValue",
|
|
wszREGCRLNEXTPUBLISH,
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
|
|
}
|
|
|
|
// update the CA DS object with the server type flags
|
|
|
|
if (SETUP_UPDATE_CAOBJECT_SVRTYPE & dw)
|
|
{
|
|
hr = SetCAObjectFlags(
|
|
g_fAdvancedServer? CA_FLAG_CA_SERVERTYPE_ADVANCED : 0);
|
|
_PrintIfError(hr, "SetCAObjectFlags");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = SetSetupStatus(
|
|
g_wszSanitizedName,
|
|
SETUP_UPDATE_CAOBJECT_SVRTYPE,
|
|
FALSE);
|
|
_PrintIfError(hr, "SetSetupStatus");
|
|
}
|
|
}
|
|
|
|
hr = coreReadRegStringValue(
|
|
hkeyCN,
|
|
wszREGALTERNATEPUBLISHDOMAINS,
|
|
&g_pwszzAlternatePublishDomains);
|
|
_PrintIfError2(
|
|
hr,
|
|
"coreReadRegStringValue",
|
|
HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
|
|
|
|
coreDSInitCache();
|
|
coreLdapInitCache();
|
|
|
|
cbValue = sizeof(g_PolicyFlags);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegPolicyFlags,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &g_PolicyFlags,
|
|
&cbValue);
|
|
if (S_OK != hr ||
|
|
REG_DWORD != dwType ||
|
|
sizeof(g_PolicyFlags) != cbValue)
|
|
{
|
|
g_PolicyFlags = 0;
|
|
}
|
|
|
|
cbValue = sizeof(awcTemplate);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegSubjectTemplate,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) awcTemplate,
|
|
&cbValue);
|
|
if (S_OK == hr &&
|
|
(REG_SZ == dwType || REG_MULTI_SZ == dwType) &&
|
|
sizeof(WCHAR) < cbValue &&
|
|
L'\0' != awcTemplate[0])
|
|
{
|
|
if (L'\0' != awcTemplate[cbValue/sizeof(WCHAR) - 1] ||
|
|
(REG_MULTI_SZ == dwType &&
|
|
L'\0' != awcTemplate[cbValue/sizeof(WCHAR) - 2]) ||
|
|
sizeof(awcTemplate) < cbValue)
|
|
{
|
|
LogMsg = MSG_E_REG_BAD_SUBJECT_TEMPLATE;
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "Bad Subject Template length/termination");
|
|
}
|
|
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cbValue + sizeof(WCHAR));
|
|
if (NULL != pwsz)
|
|
{
|
|
if (dwType == REG_MULTI_SZ)
|
|
{
|
|
CopyMemory(pwsz, awcTemplate, cbValue);
|
|
}
|
|
else
|
|
{
|
|
hr = coreConvertSubjectTemplate(pwsz, awcTemplate, cbValue);
|
|
if (S_OK != hr)
|
|
{
|
|
LocalFree(pwsz);
|
|
}
|
|
_JumpIfError(hr, error, "coreConvertSubjectTemplate");
|
|
}
|
|
g_pwszzSubjectTemplate = pwsz;
|
|
}
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegCertEnrollCompatible,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr &&
|
|
REG_DWORD == dwType &&
|
|
sizeof(dw) == cbValue)
|
|
{
|
|
g_fCertEnrollCompatible = dw? TRUE : FALSE;
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegEnforceX500NameLengths,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr &&
|
|
REG_DWORD == dwType &&
|
|
sizeof(dw) == cbValue)
|
|
{
|
|
g_fEnforceRDNNameLengths = dw? TRUE : FALSE;
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGCRLEDITFLAGS,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr &&
|
|
REG_DWORD == dwType &&
|
|
sizeof(dw) == cbValue)
|
|
{
|
|
g_CRLEditFlags = dw;
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGKRAFLAGS,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr &&
|
|
REG_DWORD == dwType &&
|
|
sizeof(dw) == cbValue)
|
|
{
|
|
g_KRAFlags = dw;
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGKRACERTCOUNT,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr &&
|
|
REG_DWORD == dwType &&
|
|
sizeof(dw) == cbValue)
|
|
{
|
|
g_cKRACertsRoundRobin = dw;
|
|
}
|
|
|
|
hr = coreRegGetTimePeriod(
|
|
hkeyCN,
|
|
g_wszRegValidityPeriodCount,
|
|
g_wszRegValidityPeriodString,
|
|
&g_enumValidityPeriod,
|
|
&g_lValidityPeriodCount);
|
|
if (S_OK != hr)
|
|
{
|
|
LogMsg = MSG_E_REG_BAD_CERT_PERIOD;
|
|
_JumpError(hr, error, "Bad Registry ValidityPeriod");
|
|
}
|
|
|
|
hr = coreRegGetTimePeriod(
|
|
hkeyCN,
|
|
g_wszRegCAXchgValidityPeriodCount,
|
|
g_wszRegCAXchgValidityPeriodString,
|
|
&g_enumCAXchgValidityPeriod,
|
|
&g_lCAXchgValidityPeriodCount);
|
|
_PrintIfError(hr, "Bad Registry CA Xchg Validity Period");
|
|
|
|
hr = coreRegGetTimePeriod(
|
|
hkeyCN,
|
|
g_wszRegCAXchgOverlapPeriodCount,
|
|
g_wszRegCAXchgOverlapPeriodString,
|
|
&g_enumCAXchgOverlapPeriod,
|
|
&g_lCAXchgOverlapPeriodCount);
|
|
_PrintIfError(hr, "Bad Registry CA Xchg Overlap Period");
|
|
|
|
hr = PKCSUpdateXchgValidityPeriods(NULL);
|
|
_PrintIfError(hr, "PKCSUpdateXchgValidityPeriods");
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegForceTeletex,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
|
|
{
|
|
switch (ENUM_TELETEX_MASK & dw)
|
|
{
|
|
case ENUM_TELETEX_OFF:
|
|
case ENUM_TELETEX_ON:
|
|
g_fForceTeletex =
|
|
(enum ENUM_FORCETELETEX) (ENUM_TELETEX_MASK & dw);
|
|
break;
|
|
|
|
default:
|
|
g_fForceTeletex = ENUM_TELETEX_AUTO;
|
|
break;
|
|
}
|
|
if (ENUM_TELETEX_UTF8 & dw)
|
|
{
|
|
*(DWORD *) &g_fForceTeletex |= ENUM_TELETEX_UTF8;
|
|
}
|
|
}
|
|
|
|
cbValue = sizeof(g_CAType);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGCATYPE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) &g_CAType,
|
|
&cbValue);
|
|
_JumpIfError(hr, error, "RegQueryValueEx");
|
|
|
|
cbValue = sizeof(g_fUseDS);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGCAUSEDS,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) &g_fUseDS,
|
|
&cbValue);
|
|
_JumpIfError(hr, error, "RegQueryValueEx");
|
|
|
|
|
|
cbValue = sizeof(g_wszParentConfig) - 2 * sizeof(WCHAR);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGPARENTCAMACHINE,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) g_wszParentConfig,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_SZ == dwType)
|
|
{
|
|
g_wszParentConfig[cbValue / sizeof(WCHAR)] = L'\0';
|
|
pwsz = &g_wszParentConfig[wcslen(g_wszParentConfig)];
|
|
|
|
*pwsz++ = L'\\';
|
|
*pwsz = L'\0';
|
|
|
|
cbValue =
|
|
sizeof(g_wszParentConfig) -
|
|
(SAFE_SUBTRACT_POINTERS(pwsz, g_wszParentConfig) + 1) *
|
|
sizeof(WCHAR);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGPARENTCANAME,
|
|
NULL,
|
|
&dwType,
|
|
(BYTE *) pwsz,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_SZ == dwType)
|
|
{
|
|
pwsz[cbValue / sizeof(WCHAR)] = L'\0';
|
|
}
|
|
else
|
|
{
|
|
g_wszParentConfig[0] = L'\0';
|
|
}
|
|
}
|
|
else
|
|
{
|
|
g_wszParentConfig[0] = L'\0';
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegClockSkewMinutes,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
|
|
{
|
|
g_dwClockSkewMinutes = dw;
|
|
}
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegViewAgeMinutes,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
|
|
{
|
|
g_dwViewAgeMinutes = dw;
|
|
}
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegViewIdleMinutes,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
|
|
{
|
|
g_dwViewIdleMinutes = dw;
|
|
}
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegMaxIncomingMessageSize,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
|
|
{
|
|
g_cbMaxIncomingMessageSize = dw;
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegMaxIncomingAllocSize,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
|
|
{
|
|
g_cbMaxIncomingAllocSize = dw;
|
|
}
|
|
|
|
// load CRL globals
|
|
hr = CRLInit(g_wszSanitizedName);
|
|
_JumpIfError(hr, error, "CRLInitializeGlobals");
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegLogLevel,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
|
|
{
|
|
g_dwLogLevel = dw;
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
g_wszRegHighSerial,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr)
|
|
{
|
|
if (REG_DWORD == dwType)
|
|
{
|
|
if (sizeof(dw) == cbValue)
|
|
{
|
|
g_dwHighSerial = dw;
|
|
}
|
|
}
|
|
else if (REG_SZ == dwType)
|
|
{
|
|
hr = coreReadRegStringValue(
|
|
hkeyCN,
|
|
g_wszRegHighSerial,
|
|
&pwszHighSerial);
|
|
_JumpIfError(hr, error, "coreReadRegStringValue");
|
|
|
|
hr = WszToMultiByteInteger(
|
|
FALSE,
|
|
pwszHighSerial,
|
|
&g_cbHighSerial,
|
|
&g_pbHighSerial);
|
|
_JumpIfError(hr, error, "WszToMultiByteInteger");
|
|
}
|
|
}
|
|
|
|
cbValue = sizeof(dw);
|
|
hr = RegQueryValueEx(
|
|
hkeyCN,
|
|
wszREGINTERFACEFLAGS,
|
|
NULL, // lpdwReserved
|
|
&dwType,
|
|
(BYTE *) &dw,
|
|
&cbValue);
|
|
if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
|
|
{
|
|
g_InterfaceFlags = dw;
|
|
}
|
|
|
|
|
|
hr = g_CASD.Initialize(g_wszSanitizedName);
|
|
if(S_OK!=hr)
|
|
{
|
|
LogMsg = MSG_BAD_PERMISSIONS;
|
|
_JumpError(hr, error, "CProtectedSecurityDescriptor::Initialize");
|
|
}
|
|
|
|
// Security has changed while certsrv was stopped. We need to update security on
|
|
// DS & service to make sure they are in sync with the CA permissions
|
|
|
|
if(dwCASetupStatus & SETUP_SECURITY_CHANGED)
|
|
{
|
|
hr = g_CASD.MapAndSetDaclOnObjects(g_fUseDS?true:false);
|
|
_PrintIfError(hr, "CProtectedSecurityDescriptor::MapAndSetDaclOnObjects");
|
|
|
|
// clear the flag only if successful
|
|
if(S_OK==hr)
|
|
{
|
|
hr = SetSetupStatus(g_wszSanitizedName, SETUP_SECURITY_CHANGED, FALSE);
|
|
_PrintIfError(hr, "SetSetupStatus SETUP_SECURITY_CHANGED FALSE");
|
|
}
|
|
}
|
|
|
|
g_CASD.ImportResourceStrings(g_pwszAuditResources);
|
|
|
|
// Functionality available only on advanced server:
|
|
// - restricted officers
|
|
// - enforce role separation
|
|
|
|
if (g_fAdvancedServer)
|
|
{
|
|
hr = g_OfficerRightsSD.Initialize(g_wszSanitizedName);
|
|
_JumpIfError(hr, error, "CProtectedSecurityDescriptor::Initialize");
|
|
|
|
g_OfficerRightsSD.ImportResourceStrings(g_pwszAuditResources);
|
|
|
|
hr = AuditSettings.RoleSeparationFlagLoad(g_wszSanitizedName);
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
|
|
{
|
|
_JumpIfError(hr, error, "CAuditEvent::RoleSeparationFlagLoad");
|
|
}
|
|
|
|
}
|
|
|
|
hr = AuditSettings.LoadFilter(g_wszSanitizedName);
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
|
|
{
|
|
_JumpIfError(hr, error, "CAuditEvent::LoadFilter");
|
|
}
|
|
|
|
if (fAuditEnabled)
|
|
{
|
|
g_dwAuditFilter = AuditSettings.GetFilter();
|
|
}
|
|
|
|
if (NULL != g_pwszzSubjectTemplate)
|
|
{
|
|
hr = PKCSSetSubjectTemplate(g_pwszzSubjectTemplate);
|
|
if (S_OK != hr)
|
|
{
|
|
LogMsg = MSG_E_REG_BAD_SUBJECT_TEMPLATE;
|
|
pwszLog = g_wszSanitizedName;
|
|
_JumpError(hr, error, "PKCSSetSubjectTemplate");
|
|
}
|
|
}
|
|
hr = PKCSSetup(g_wszCommonName, g_wszSanitizedName);
|
|
if (S_OK != hr)
|
|
{
|
|
fLogError = FALSE; // PKCSSetup logs a specific error
|
|
_JumpError(hr, error, "PKCSSetup");
|
|
}
|
|
|
|
hr = CertificateInterfaceInit(
|
|
&ServerCallBacks,
|
|
sizeof(ServerCallBacks));
|
|
if (S_OK != hr)
|
|
{
|
|
LogMsg = MSG_CERTIF_MISMATCH;
|
|
_JumpError(hr, error, "CertificateInterfaceInit");
|
|
}
|
|
|
|
hr = ComInit();
|
|
_JumpIfError(hr, error, "ComInit");
|
|
|
|
hr = RequestInitCAPropertyInfo();
|
|
_JumpIfError(hr, error, "RequestInitCAPropertyInfo");
|
|
|
|
// We must have a policy module to continue.
|
|
hr = PolicyInit(g_wszCommonName, g_wszSanitizedName);
|
|
if (S_OK != hr)
|
|
{
|
|
LogMsg = MSG_NO_POLICY;
|
|
_JumpError(hr, error, "PolicyInit");
|
|
}
|
|
CSASSERT(g_fEnablePolicy);
|
|
|
|
// On error, silently leave exit module(s) disabled.
|
|
hr = ExitInit(g_wszCommonName, g_wszSanitizedName);
|
|
_PrintIfError(hr, "ExitInit");
|
|
|
|
hr = myGetCertRegMultiStrValue(
|
|
g_wszSanitizedName,
|
|
NULL,
|
|
NULL,
|
|
wszSECUREDATTRIBUTES,
|
|
&g_wszzSecuredAttributes);
|
|
if (S_OK != hr)
|
|
{
|
|
// Force defaults
|
|
g_wszzSecuredAttributes = (LPWSTR)g_wszzSecuredAttributesDefault;
|
|
}
|
|
|
|
if (g_fServerUpgraded)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTSRV,
|
|
"CoreInit: clearing SETUP_SERVER_UPGRADED_FLAG\n"));
|
|
|
|
hr = SetSetupStatus(NULL, SETUP_SERVER_UPGRADED_FLAG, FALSE);
|
|
_PrintIfError(hr, "SetSetupStatus");
|
|
}
|
|
fLogError = FALSE;
|
|
|
|
error:
|
|
if (fLogError)
|
|
{
|
|
LogEventString(EVENTLOG_ERROR_TYPE, LogMsg, pwszLog);
|
|
}
|
|
if (NULL != pwszFullRequestFileName)
|
|
{
|
|
LocalFree(pwszFullRequestFileName);
|
|
}
|
|
if (NULL != pwszHighSerial)
|
|
{
|
|
LocalFree(pwszHighSerial);
|
|
}
|
|
if (NULL != hkeyCN)
|
|
{
|
|
RegCloseKey(hkeyCN);
|
|
}
|
|
if (NULL != hkeyConfig)
|
|
{
|
|
RegCloseKey(hkeyConfig);
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
CoreTerminate();
|
|
g_CASD.Uninitialize();
|
|
g_OfficerRightsSD.Uninitialize();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
CoreTerminate(VOID)
|
|
{
|
|
if (g_fcritsecDSCache)
|
|
{
|
|
coreDSEmptyCache(TRUE);
|
|
DeleteCriticalSection(&g_critsecDSCache);
|
|
g_fcritsecDSCache = FALSE;
|
|
}
|
|
if (NULL != g_rgDSCache)
|
|
{
|
|
LocalFree(g_rgDSCache);
|
|
g_rgDSCache = NULL;
|
|
}
|
|
coreLdapFreeCache();
|
|
DBShutDown(FALSE);
|
|
ComShutDown();
|
|
PKCSTerminate();
|
|
CRLTerminate();
|
|
if (NULL != g_pwszServerName)
|
|
{
|
|
LocalFree(g_pwszServerName);
|
|
g_pwszServerName = NULL;
|
|
}
|
|
if (NULL != g_pwszzAlternatePublishDomains)
|
|
{
|
|
LocalFree(g_pwszzAlternatePublishDomains);
|
|
g_pwszzAlternatePublishDomains = NULL;
|
|
}
|
|
if (NULL != g_pwszzSubjectTemplate)
|
|
{
|
|
LocalFree(g_pwszzSubjectTemplate);
|
|
g_pwszzSubjectTemplate = NULL;
|
|
}
|
|
if (NULL != g_pwszSanitizedDSName)
|
|
{
|
|
LocalFree(g_pwszSanitizedDSName);
|
|
g_pwszSanitizedDSName = NULL;
|
|
}
|
|
if (NULL != g_pbHighSerial)
|
|
{
|
|
LocalFree(g_pbHighSerial);
|
|
g_pbHighSerial = NULL;
|
|
}
|
|
|
|
// free only if it points to memory that isn't the default static buffer
|
|
|
|
if (NULL != g_wszzSecuredAttributes &&
|
|
g_wszzSecuredAttributes != g_wszzSecuredAttributesDefault)
|
|
{
|
|
LocalFree(g_wszzSecuredAttributes);
|
|
g_wszzSecuredAttributes = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CoreSetRequestDispositionFields(
|
|
IN ICertDBRow *prow,
|
|
IN DWORD ErrCode,
|
|
IN DWORD Disposition,
|
|
IN WCHAR const *pwszDisposition)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = CoreSetDisposition(prow, Disposition);
|
|
_JumpIfError(hr, error, "CoreSetDisposition");
|
|
|
|
hr = prow->SetProperty(
|
|
g_wszPropRequestStatusCode,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
sizeof(ErrCode),
|
|
(BYTE const *) &ErrCode);
|
|
_JumpIfError(hr, error, "SetProperty(status code)");
|
|
|
|
if (NULL != pwszDisposition)
|
|
{
|
|
hr = prow->SetProperty(
|
|
g_wszPropRequestDispositionMessage,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
MAXDWORD,
|
|
(BYTE const *) pwszDisposition);
|
|
_JumpIfError(hr, error, "SetProperty(disposition message)");
|
|
}
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreFindOldArchivedKey(
|
|
IN OUT CERTSRV_RESULT_CONTEXT *pResult)
|
|
{
|
|
HRESULT hr;
|
|
ICertDBRow *prow = NULL;
|
|
|
|
if (NULL != pResult->strRenewalCertHash &&
|
|
NULL == pResult->pbArchivedKey &&
|
|
NULL == pResult->pwszKRAHashes)
|
|
{
|
|
hr = g_pCertDB->OpenRow(
|
|
PROPOPEN_READONLY | PROPTABLE_REQCERT | PROPOPEN_CERTHASH,
|
|
0, // RequestId
|
|
pResult->strRenewalCertHash,
|
|
&prow);
|
|
_JumpIfErrorStr(hr, error, "OpenRow", pResult->strRenewalCertHash);
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropRequestRawArchivedKey,
|
|
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
&pResult->cbArchivedKey,
|
|
(BYTE **) &pResult->pbArchivedKey);
|
|
_JumpIfError(hr, error, "PKCSGetProperty");
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropRequestKeyRecoveryHashes,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
(BYTE **) &pResult->pwszKRAHashes);
|
|
_JumpIfError(hr, error, "PKCSGetProperty");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != prow)
|
|
{
|
|
prow->Release();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreCreateRequest(
|
|
IN DWORD dwFlags,
|
|
IN WCHAR const *pwszUserName,
|
|
IN DWORD cbRequest,
|
|
IN BYTE const *pbRequest,
|
|
IN WCHAR const *pwszAttributes,
|
|
IN DWORD dwComContextIndex,
|
|
OUT ICertDBRow **pprow, // may return non-NULL on error
|
|
IN OUT CERTSRV_RESULT_CONTEXT *pResult)
|
|
{
|
|
HRESULT hr;
|
|
DWORD dwRequestFlags;
|
|
DWORD cb;
|
|
WCHAR *pwszAttrAlloc = NULL;
|
|
|
|
ICertDBRow *prow = NULL;
|
|
|
|
hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, NULL, pprow);
|
|
_JumpIfError(hr, error, "OpenRow");
|
|
|
|
prow = *pprow;
|
|
|
|
hr = PropSetRequestTimeProperty(prow, g_wszPropRequestSubmittedWhen);
|
|
_JumpIfError(hr, error, "PropSetRequestTimeProperty");
|
|
|
|
hr = CoreSetDisposition(prow, DB_DISP_ACTIVE);
|
|
_JumpIfError(hr, error, "CoreSetDisposition");
|
|
|
|
hr = prow->SetProperty(
|
|
g_wszPropRequestType,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
sizeof(dwFlags),
|
|
(BYTE const *) &dwFlags);
|
|
_JumpIfError(hr, error, "SetProperty(type)");
|
|
|
|
if (L'\0' != *pwszUserName)
|
|
{
|
|
hr = prow->SetProperty(
|
|
g_wszPropRequesterName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
MAXDWORD,
|
|
(BYTE const *) pwszUserName);
|
|
_JumpIfError(hr, error, "SetProperty(requester)");
|
|
|
|
hr = prow->SetProperty(
|
|
g_wszPropCallerName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
MAXDWORD,
|
|
(BYTE const *) pwszUserName);
|
|
_JumpIfError(hr, error, "SetProperty(caller)");
|
|
}
|
|
|
|
if (NULL != pwszAttributes && L'\0' != *pwszAttributes)
|
|
{
|
|
WCHAR const *pwszAttrSave = pwszAttributes;
|
|
|
|
if (wcslen(pwszAttrSave) > CCH_DBMAXTEXT_ATTRSTRING)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTSRV,
|
|
"coreCreateRequest: truncating Attributes %u -> %u chars\n",
|
|
wcslen(pwszAttrSave),
|
|
CCH_DBMAXTEXT_ATTRSTRING));
|
|
|
|
hr = myDupString(pwszAttrSave, &pwszAttrAlloc);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pwszAttrAlloc[CCH_DBMAXTEXT_ATTRSTRING] = L'\0';
|
|
pwszAttrSave = pwszAttrAlloc;
|
|
}
|
|
hr = prow->SetProperty(
|
|
g_wszPropRequestAttributes,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
MAXDWORD,
|
|
(BYTE const *) pwszAttrSave);
|
|
_JumpIfError(hr, error, "SetProperty(attrib)");
|
|
}
|
|
|
|
hr = PropParseRequest(prow, dwFlags, cbRequest, pbRequest, pResult);
|
|
_JumpIfError(hr, error, "PropParseRequest");
|
|
|
|
hr = PKCSParseAttributes(
|
|
prow,
|
|
pwszAttributes,
|
|
FALSE,
|
|
FALSE,
|
|
PROPTABLE_REQUEST,
|
|
NULL);
|
|
_JumpIfError(hr, error, "PKCSParseAttributes");
|
|
|
|
hr = coreFindOldArchivedKey(pResult);
|
|
_PrintIfError(hr, "coreFindOldArchivedKey");
|
|
|
|
hr = prow->CopyRequestNames(); // after parsing request attributes!
|
|
_JumpIfError(hr, error, "CopyRequestNames");
|
|
|
|
hr = PKCSVerifyChallengeString(prow);
|
|
_JumpIfError(hr, error, "PKCSVerifyChallengeString");
|
|
|
|
cb = sizeof(dwRequestFlags);
|
|
hr = prow->GetProperty(
|
|
g_wszPropRequestFlags,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
&cb,
|
|
(BYTE *) &dwRequestFlags);
|
|
_JumpIfError(hr, error, "GetProperty");
|
|
|
|
if (CR_FLG_ENROLLONBEHALFOF & dwRequestFlags)
|
|
{
|
|
hr = coreGetComContextUserDNFromSamName(
|
|
TRUE, // fDeleteUserDNOnly
|
|
NULL, // pwszSamName
|
|
0, // Context
|
|
dwComContextIndex,
|
|
NULL); // pwszDN
|
|
_JumpIfError(hr, error, "coreGetComContextUserDNFromSamName");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszAttrAlloc)
|
|
{
|
|
LocalFree(pwszAttrAlloc);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreFetchCertificate(
|
|
IN ICertDBRow *prow,
|
|
OUT CERTTRANSBLOB *pctbCert) // CoTaskMem*
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbProp;
|
|
|
|
pctbCert->pb = NULL;
|
|
cbProp = 0;
|
|
hr = prow->GetProperty(
|
|
g_wszPropRawCertificate,
|
|
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
|
|
NULL,
|
|
&cbProp,
|
|
NULL);
|
|
_JumpIfError(hr, error, "GetProperty(raw cert size)");
|
|
|
|
pctbCert->pb = (BYTE *) CoTaskMemAlloc(cbProp);
|
|
if (NULL == pctbCert->pb)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "CoTaskMemAlloc(raw cert)");
|
|
}
|
|
hr = prow->GetProperty(
|
|
g_wszPropRawCertificate,
|
|
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
|
|
NULL,
|
|
&cbProp,
|
|
pctbCert->pb);
|
|
_JumpIfError(hr, error, "GetProperty(raw cert)");
|
|
|
|
error:
|
|
if (S_OK != hr && NULL != pctbCert->pb)
|
|
{
|
|
CoTaskMemFree(pctbCert->pb);
|
|
pctbCert->pb = NULL;
|
|
}
|
|
pctbCert->cb = cbProp;
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreRetrievePending(
|
|
IN ICertDBRow *prow,
|
|
IN BOOL fIncludeCRLs,
|
|
OUT WCHAR **ppwszDisposition, // LocalAlloc
|
|
OUT CACTX **ppCAContext,
|
|
IN OUT CERTSRV_RESULT_CONTEXT *pResult) // CoTaskMem*
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbProp;
|
|
WCHAR *pwszDisposition = NULL;
|
|
DWORD Disposition;
|
|
HRESULT hrRequest;
|
|
BOOL fIssued;
|
|
|
|
*ppwszDisposition = NULL;
|
|
*ppCAContext = NULL;
|
|
cbProp = sizeof(Disposition);
|
|
hr = prow->GetProperty(
|
|
g_wszPropRequestDisposition,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
&cbProp,
|
|
(BYTE *) &Disposition);
|
|
_JumpIfError(hr, error, "GetProperty(disposition)");
|
|
|
|
cbProp = sizeof(hrRequest);
|
|
hr = prow->GetProperty(
|
|
g_wszPropRequestStatusCode,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
&cbProp,
|
|
(BYTE *) &hrRequest);
|
|
_JumpIfError(hr, error, "GetProperty(status code)");
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropRequestDispositionMessage,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
(BYTE **) &pwszDisposition);
|
|
_PrintIfError2(hr, "PKCSGetProperty", CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
fIssued = FALSE;
|
|
switch (Disposition)
|
|
{
|
|
FILETIME FileTime;
|
|
|
|
case DB_DISP_ACTIVE:
|
|
case DB_DISP_PENDING:
|
|
*pResult->pdwDisposition = CR_DISP_UNDER_SUBMISSION;
|
|
break;
|
|
|
|
case DB_DISP_ISSUED:
|
|
case DB_DISP_CA_CERT:
|
|
case DB_DISP_CA_CERT_CHAIN:
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
if (DB_DISP_CA_CERT == Disposition && IsRootCA(g_CAType))
|
|
{
|
|
cbProp = sizeof(FileTime);
|
|
hr = prow->GetProperty(
|
|
g_wszPropRequestRevokedEffectiveWhen,
|
|
PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
&cbProp,
|
|
(BYTE *) &FileTime);
|
|
}
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
*pResult->pdwDisposition = CR_DISP_ISSUED;
|
|
fIssued = TRUE;
|
|
break;
|
|
}
|
|
// FALLTHROUGH
|
|
|
|
case DB_DISP_REVOKED:
|
|
*pResult->pdwDisposition = CR_DISP_REVOKED;
|
|
fIssued = TRUE;
|
|
break;
|
|
|
|
case DB_DISP_ERROR:
|
|
*pResult->pdwDisposition = CR_DISP_ERROR;
|
|
break;
|
|
|
|
case DB_DISP_DENIED:
|
|
*pResult->pdwDisposition = CR_DISP_DENIED;
|
|
if (FAILED(hrRequest))
|
|
{
|
|
*pResult->pdwDisposition = hrRequest;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
*pResult->pdwDisposition = CR_DISP_INCOMPLETE;
|
|
break;
|
|
}
|
|
if (fIssued)
|
|
{
|
|
BOOL fErrorLogged = FALSE;
|
|
|
|
hr = coreFetchCertificate(prow, pResult->pctbCert);
|
|
_JumpIfError(hr, error, "coreFetchCertificate");
|
|
|
|
CSASSERT(NULL != pResult->pctbCert && NULL != pResult->pctbCert->pb);
|
|
hr = PKCSCreateCertificate(
|
|
prow,
|
|
Disposition,
|
|
fIncludeCRLs,
|
|
FALSE, // fCrossCert
|
|
NULL, // use default signing CACTX
|
|
&fErrorLogged,
|
|
ppCAContext,
|
|
NULL, // ppwszDispositionCreateCert
|
|
pResult);
|
|
|
|
CSASSERT(!fErrorLogged);
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
if (CERTLOG_ERROR <= g_dwLogLevel)
|
|
{
|
|
LogEventHResult(
|
|
EVENTLOG_ERROR_TYPE,
|
|
MSG_E_CANNOT_BUILD_CERT_OR_CHAIN,
|
|
hr);
|
|
}
|
|
_JumpError(hr, error, "PKCSCreateCertificate");
|
|
}
|
|
}
|
|
*ppwszDisposition = pwszDisposition;
|
|
pwszDisposition = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr && NULL != pResult->pctbCert->pb)
|
|
{
|
|
CoTaskMemFree(pResult->pctbCert->pb);
|
|
pResult->pctbCert->pb = NULL;
|
|
}
|
|
if (NULL != pwszDisposition)
|
|
{
|
|
LocalFree(pwszDisposition);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
CoreLogRequestStatus(
|
|
IN ICertDBRow *prow,
|
|
IN DWORD LogMsg,
|
|
IN DWORD ErrCode,
|
|
OPTIONAL IN WCHAR const *pwszDisposition)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszSubject = NULL;
|
|
WCHAR const *pwszSubject2;
|
|
WCHAR wszRequestId[cwcDWORDSPRINTF];
|
|
WCHAR awchr[cwcHRESULTSTRING];
|
|
WORD cString = 0;
|
|
WCHAR const *apwsz[4];
|
|
DWORD ReqId;
|
|
DWORD infotype = EVENTLOG_INFORMATION_TYPE;
|
|
WCHAR const *pwszMessageText = NULL;
|
|
DWORD LogMsg2;
|
|
|
|
prow->GetRowId(&ReqId);
|
|
wsprintf(wszRequestId, L"%u", ReqId);
|
|
apwsz[cString++] = wszRequestId;
|
|
|
|
LogMsg2 = LogMsg;
|
|
switch (LogMsg)
|
|
{
|
|
case MSG_DN_CERT_ISSUED:
|
|
LogMsg2 = MSG_DN_CERT_ISSUED_WITH_INFO;
|
|
break;
|
|
|
|
case MSG_DN_CERT_PENDING:
|
|
LogMsg2 = MSG_DN_CERT_PENDING_WITH_INFO;
|
|
break;
|
|
|
|
case MSG_DN_CERT_ADMIN_DENIED:
|
|
LogMsg2 = MSG_DN_CERT_ADMIN_DENIED_WITH_INFO;
|
|
break;
|
|
|
|
case MSG_DN_CERT_DENIED:
|
|
LogMsg2 = MSG_DN_CERT_DENIED_WITH_INFO;
|
|
infotype = EVENTLOG_WARNING_TYPE;
|
|
break;
|
|
|
|
case MSG_E_PROCESS_REQUEST_FAILED:
|
|
LogMsg2 = MSG_E_PROCESS_REQUEST_FAILED_WITH_INFO;
|
|
infotype = EVENTLOG_ERROR_TYPE;
|
|
break;
|
|
}
|
|
if (EVENTLOG_INFORMATION_TYPE != infotype)
|
|
{
|
|
if (S_OK == ErrCode)
|
|
{
|
|
ErrCode = (DWORD) SEC_E_CERT_UNKNOWN; // unknown error
|
|
}
|
|
pwszMessageText = myGetErrorMessageText(ErrCode, TRUE);
|
|
if (NULL == pwszMessageText)
|
|
{
|
|
pwszMessageText = myHResultToStringRaw(awchr, ErrCode);
|
|
}
|
|
apwsz[cString++] = pwszMessageText;
|
|
}
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropSubjectDistinguishedName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
|
|
NULL,
|
|
(BYTE **) &pwszSubject);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropSubjectDistinguishedName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
(BYTE **) &pwszSubject);
|
|
}
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropRequesterName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
(BYTE **) &pwszSubject);
|
|
}
|
|
pwszSubject2 = pwszSubject;
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "GetProperty(DN/Requester)");
|
|
pwszSubject2 = g_pwszUnknownSubject;
|
|
}
|
|
apwsz[cString++] = pwszSubject2;
|
|
|
|
if (NULL != pwszDisposition)
|
|
{
|
|
LogMsg = LogMsg2;
|
|
apwsz[cString++] = pwszDisposition;
|
|
}
|
|
|
|
if (CERTLOG_VERBOSE <= g_dwLogLevel ||
|
|
(EVENTLOG_WARNING_TYPE == infotype && CERTLOG_WARNING <= g_dwLogLevel) ||
|
|
(EVENTLOG_ERROR_TYPE == infotype && CERTLOG_ERROR <= g_dwLogLevel))
|
|
{
|
|
LogEvent(infotype, LogMsg, cString, apwsz);
|
|
}
|
|
|
|
#if 0 == i386
|
|
# define IOBUNALIGNED(pf) ((sizeof(WCHAR) - 1) & (DWORD) (ULONG_PTR) (pf)->_ptr)
|
|
# define ALIGNIOB(pf) \
|
|
{ \
|
|
if (IOBUNALIGNED(pf)) \
|
|
{ \
|
|
fflush(pf); /* fails when running as a service */ \
|
|
} \
|
|
if (IOBUNALIGNED(pf)) \
|
|
{ \
|
|
fprintf(pf, " "); \
|
|
fflush(pf); \
|
|
} \
|
|
}
|
|
#else
|
|
# define IOBUNALIGNED(pf) FALSE
|
|
# define ALIGNIOB(pf)
|
|
#endif
|
|
|
|
{
|
|
BOOL fRetried = FALSE;
|
|
|
|
for (;;)
|
|
{
|
|
ALIGNIOB(stdout);
|
|
__try
|
|
{
|
|
wprintf(
|
|
// L"\nCertSrv Request %u: rc=%x: %ws: %ws '%ws'\n"
|
|
g_pwszPrintfCertRequestDisposition,
|
|
ReqId,
|
|
ErrCode,
|
|
NULL != pwszMessageText? pwszMessageText : L"",
|
|
NULL != pwszDisposition? pwszDisposition : L"",
|
|
pwszSubject);
|
|
hr = S_OK;
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
}
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4127) // conditional expression is constant
|
|
if (S_OK == hr || fRetried || !IOBUNALIGNED(stdout))
|
|
#pragma warning(pop)
|
|
{
|
|
break;
|
|
}
|
|
ALIGNIOB(stdout);
|
|
fRetried = TRUE;
|
|
}
|
|
}
|
|
if (NULL != pwszMessageText && awchr != pwszMessageText)
|
|
{
|
|
LocalFree(const_cast<WCHAR *>(pwszMessageText));
|
|
}
|
|
if (NULL != pwszSubject)
|
|
{
|
|
LocalFree(pwszSubject);
|
|
}
|
|
}
|
|
|
|
|
|
WCHAR *
|
|
CoreBuildDispositionString(
|
|
OPTIONAL IN WCHAR const *pwszDispositionBase,
|
|
OPTIONAL IN WCHAR const *pwszUserName,
|
|
OPTIONAL IN WCHAR const *pwszDispositionDetail,
|
|
OPTIONAL IN WCHAR const *pwszDispositionDetail2,
|
|
OPTIONAL IN WCHAR const *pwszBy,
|
|
IN HRESULT hrFail,
|
|
IN BOOL fPublishError)
|
|
{
|
|
DWORD cwc = 0;
|
|
WCHAR *pwsz = NULL;
|
|
WCHAR const *pwszMessageText = NULL;
|
|
WCHAR awchr[cwcHRESULTSTRING];
|
|
|
|
if (NULL == pwszUserName)
|
|
{
|
|
pwszUserName = L"";
|
|
}
|
|
if (NULL != pwszDispositionBase)
|
|
{
|
|
cwc += wcslen(pwszDispositionBase) + wcslen(pwszUserName);
|
|
}
|
|
if (NULL != pwszDispositionDetail)
|
|
{
|
|
if (0 != cwc)
|
|
{
|
|
cwc += 2; // spaces
|
|
}
|
|
cwc += wcslen(pwszDispositionDetail);
|
|
}
|
|
if (NULL != pwszDispositionDetail2)
|
|
{
|
|
if (0 != cwc)
|
|
{
|
|
cwc += 2; // spaces
|
|
}
|
|
cwc += wcslen(pwszDispositionDetail2);
|
|
}
|
|
if (NULL != pwszBy)
|
|
{
|
|
if (0 != cwc)
|
|
{
|
|
cwc += 2; // spaces
|
|
}
|
|
cwc += wcslen(pwszBy) + wcslen(pwszUserName);
|
|
}
|
|
if (S_OK != hrFail)
|
|
{
|
|
pwszMessageText = myGetErrorMessageText(hrFail, TRUE);
|
|
if (NULL == pwszMessageText)
|
|
{
|
|
pwszMessageText = myHResultToStringRaw(awchr, hrFail);
|
|
}
|
|
if (0 != cwc)
|
|
{
|
|
cwc += 2; // spaces
|
|
}
|
|
if (fPublishError)
|
|
{
|
|
cwc += wcslen(g_pwszPublishError);
|
|
cwc += 2; // spaces
|
|
}
|
|
cwc += wcslen(pwszMessageText);
|
|
}
|
|
if (0 != cwc)
|
|
{
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
|
|
if (NULL != pwsz)
|
|
{
|
|
pwsz[0] = L'\0';
|
|
if (NULL != pwszDispositionBase)
|
|
{
|
|
wsprintf(pwsz, pwszDispositionBase, pwszUserName);
|
|
}
|
|
if (NULL != pwszDispositionDetail)
|
|
{
|
|
if (L'\0' != pwsz[0])
|
|
{
|
|
wcscat(pwsz, L" ");
|
|
}
|
|
wcscat(pwsz, pwszDispositionDetail);
|
|
}
|
|
if (NULL != pwszDispositionDetail2)
|
|
{
|
|
if (L'\0' != pwsz[0])
|
|
{
|
|
wcscat(pwsz, L" ");
|
|
}
|
|
wcscat(pwsz, pwszDispositionDetail2);
|
|
}
|
|
if (NULL != pwszBy)
|
|
{
|
|
if (L'\0' != pwsz[0])
|
|
{
|
|
wcscat(pwsz, L" ");
|
|
}
|
|
wsprintf(&pwsz[wcslen(pwsz)], pwszBy, pwszUserName);
|
|
}
|
|
if (S_OK != hrFail)
|
|
{
|
|
if (L'\0' != pwsz[0] && L'\n' != pwsz[wcslen(pwsz) - 1])
|
|
{
|
|
wcscat(pwsz, L" ");
|
|
}
|
|
if (fPublishError)
|
|
{
|
|
wcscat(pwsz, g_pwszPublishError);
|
|
wcscat(pwsz, L" ");
|
|
}
|
|
wcscat(pwsz, pwszMessageText);
|
|
}
|
|
}
|
|
CSASSERT(wcslen(pwsz) <= cwc);
|
|
}
|
|
|
|
//error:
|
|
if (NULL != pwszMessageText && awchr != pwszMessageText)
|
|
{
|
|
LocalFree(const_cast<WCHAR *>(pwszMessageText));
|
|
}
|
|
return(pwsz);
|
|
}
|
|
|
|
|
|
VOID
|
|
coreLogPublishError(
|
|
IN DWORD RequestId,
|
|
IN LDAP *pld,
|
|
IN WCHAR const *pwszDN,
|
|
IN BOOL fDelete,
|
|
OPTIONAL IN WCHAR const *pwszError,
|
|
IN HRESULT hrPublish)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *apwsz[6];
|
|
WORD cpwsz;
|
|
WCHAR wszRequestId[cwcDWORDSPRINTF];
|
|
WCHAR awchr[cwcHRESULTSTRING];
|
|
WCHAR const *pwszMessageText = NULL;
|
|
WCHAR *pwszHostName = NULL;
|
|
DWORD LogMsg;
|
|
|
|
wsprintf(wszRequestId, L"%u", RequestId);
|
|
if (NULL != pld)
|
|
{
|
|
myLdapGetDSHostName(pld, &pwszHostName);
|
|
}
|
|
pwszMessageText = myGetErrorMessageText(hrPublish, TRUE);
|
|
if (NULL == pwszMessageText)
|
|
{
|
|
pwszMessageText = myHResultToStringRaw(awchr, hrPublish);
|
|
}
|
|
cpwsz = 0;
|
|
apwsz[cpwsz++] = wszRequestId;
|
|
apwsz[cpwsz++] = pwszDN;
|
|
apwsz[cpwsz++] = pwszMessageText;
|
|
|
|
LogMsg = fDelete? MSG_E_CERT_DELETION : MSG_E_CERT_PUBLICATION;
|
|
if (NULL != pwszHostName)
|
|
{
|
|
LogMsg = fDelete?
|
|
MSG_E_CERT_DELETION_HOST_NAME : MSG_E_CERT_PUBLICATION_HOST_NAME;
|
|
}
|
|
else
|
|
{
|
|
pwszHostName = L"";
|
|
}
|
|
apwsz[cpwsz++] = pwszHostName;
|
|
apwsz[cpwsz++] = NULL != pwszError? L"\n" : L"";
|
|
apwsz[cpwsz++] = NULL != pwszError? pwszError : L"";
|
|
CSASSERT(ARRAYSIZE(apwsz) >= cpwsz);
|
|
|
|
if (CERTLOG_WARNING <= g_dwLogLevel)
|
|
{
|
|
hr = LogEvent(EVENTLOG_WARNING_TYPE, LogMsg, cpwsz, apwsz);
|
|
_PrintIfError(hr, "LogEvent");
|
|
}
|
|
|
|
//error:
|
|
if (NULL != pwszMessageText && awchr != pwszMessageText)
|
|
{
|
|
LocalFree(const_cast<WCHAR *>(pwszMessageText));
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
corePublishKRACertificate(
|
|
IN DWORD RequestId,
|
|
IN CERT_CONTEXT const *pcc)
|
|
{
|
|
HRESULT hr;
|
|
LDAP *pld = NULL;
|
|
HCERTSTORE hStore = NULL;
|
|
DWORD dwDisposition;
|
|
WCHAR *pwszError = NULL;
|
|
|
|
hr = myRobustLdapBindEx(
|
|
0, // dwFlags1
|
|
RLBF_REQUIRE_SECURE_LDAP, // dwFlags2
|
|
LDAP_VERSION2, // uVersion
|
|
NULL, // pwszDomainName
|
|
&pld,
|
|
NULL); // ppwszForestDNSName
|
|
_JumpIfError(hr, error, "myRobustLdapBindEx");
|
|
|
|
hStore = CertOpenStore(
|
|
CERT_STORE_PROV_SYSTEM_REGISTRY_W,
|
|
X509_ASN_ENCODING,
|
|
NULL, // hProv
|
|
CERT_SYSTEM_STORE_LOCAL_MACHINE,
|
|
wszKRA_CERTSTORE);
|
|
if (NULL == hStore)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpErrorStr(hr, error, "CertOpenStore", wszKRA_CERTSTORE);
|
|
}
|
|
|
|
// It's a new cert. CERT_STORE_ADD_ALWAYS is faster.
|
|
|
|
if (!CertAddCertificateContextToStore(
|
|
hStore,
|
|
pcc,
|
|
CERT_STORE_ADD_ALWAYS,
|
|
NULL))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertAddCertificateContextToStore");
|
|
}
|
|
|
|
hr = myLdapPublishCertToDS(
|
|
pld,
|
|
pcc,
|
|
g_pwszKRAPublishURL,
|
|
wszDSKRACERTATTRIBUTE,
|
|
LPC_KRAOBJECT,
|
|
FALSE, // fDelete
|
|
&dwDisposition,
|
|
&pwszError);
|
|
_JumpIfError(hr, error, "myLdapPublishCertToDS");
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
coreLogPublishError(
|
|
RequestId,
|
|
pld,
|
|
g_pwszKRAPublishURL,
|
|
FALSE, // fDelete
|
|
pwszError,
|
|
hr);
|
|
}
|
|
if (NULL != pwszError)
|
|
{
|
|
LocalFree(pwszError);
|
|
}
|
|
if (NULL != hStore)
|
|
{
|
|
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
if (NULL != pld)
|
|
{
|
|
ldap_unbind(pld);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CorePublishCrossCertificate(
|
|
IN DWORD RequestId,
|
|
IN CERT_CONTEXT const *pcc,
|
|
IN BOOL fCreateDSObject,
|
|
IN BOOL fDelete)
|
|
{
|
|
HRESULT hr;
|
|
LDAP *pld = NULL;
|
|
DWORD dwDisposition;
|
|
WCHAR *pwszError = NULL;
|
|
CAutoLPWSTR pwszCN;
|
|
CAutoLPWSTR pwszSanitizedCN;
|
|
CAutoLPWSTR pwszDSSanitizedCN;
|
|
CAutoLPWSTR pwszDN;
|
|
CAutoLPWSTR pwszSubject;
|
|
WCHAR const *pwszFormatDN = L"ldap:///CN=%ws%ws";
|
|
WCHAR *pwcRelDN;
|
|
|
|
hr = myGetCommonName(&pcc->pCertInfo->Subject, TRUE, &pwszCN);
|
|
_JumpIfError(hr, error, "myGetCommonName");
|
|
|
|
hr = mySanitizeName(pwszCN, &pwszSanitizedCN);
|
|
_JumpIfError(hr, error, "mySanitizeName");
|
|
|
|
hr = mySanitizedNameToDSName(pwszSanitizedCN, &pwszDSSanitizedCN);
|
|
_JumpIfError(hr, error, "mySanitizedNameToDSName");
|
|
|
|
if (NULL == g_pwszAIACrossCertPublishURL)
|
|
{
|
|
// Actually, something went wrong with pkcsExpandURL!
|
|
|
|
hr = ERROR_DS_INVALID_DN_SYNTAX;
|
|
_JumpError(hr, error, "g_pwszAIACrossCertPublishURL");
|
|
}
|
|
pwcRelDN = wcschr(g_pwszAIACrossCertPublishURL, L',');
|
|
if (NULL == pwcRelDN)
|
|
{
|
|
// Actually, something went wrong with pkcsExpandURL!
|
|
|
|
hr = ERROR_DS_INVALID_DN_SYNTAX;
|
|
_JumpError(hr, error, "g_pwszAIACrossCertPublishURL");
|
|
}
|
|
pwszDN = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(wcslen(pwszFormatDN) +
|
|
wcslen(pwszDSSanitizedCN) +
|
|
wcslen(pwcRelDN)) * sizeof(WCHAR));
|
|
if (pwszDN == NULL)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wsprintf(pwszDN, pwszFormatDN, pwszDSSanitizedCN, pwcRelDN);
|
|
|
|
hr = myRobustLdapBindEx(
|
|
0, // dwFlags1
|
|
RLBF_REQUIRE_SECURE_LDAP, // dwFlags2
|
|
LDAP_VERSION2, // uVersion
|
|
NULL, // pwszDomainName
|
|
&pld,
|
|
NULL); // ppwszForestDNSName
|
|
_JumpIfError(hr, error, "myRobustLdapBindEx");
|
|
|
|
hr = myLdapPublishCertToDS(
|
|
pld,
|
|
pcc,
|
|
pwszDN,
|
|
wszDSCROSSCERTPAIRATTRIBUTE,
|
|
LPC_CAOBJECT | (fCreateDSObject? LPC_CREATEOBJECT : 0),
|
|
fDelete,
|
|
&dwDisposition,
|
|
&pwszError);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr(hr, "myLdapPublishCertToDS", pwszDN);
|
|
if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr &&
|
|
IsRootCA(g_CAType))
|
|
{
|
|
if (NULL != pwszError)
|
|
{
|
|
LocalFree(pwszError);
|
|
pwszError = NULL;
|
|
}
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
_JumpIfErrorStr(hr, error, "myLdapPublishCertToDS", pwszDN);
|
|
|
|
if (!fDelete)
|
|
{
|
|
hr = myCertNameToStr(
|
|
X509_ASN_ENCODING,
|
|
&pcc->pCertInfo->Subject,
|
|
CERT_X500_NAME_STR, //| CERT_NAME_STR_REVERSE_FLAG,
|
|
&pwszSubject);
|
|
_JumpIfError(hr, error, "myCertNameToStr");
|
|
|
|
hr = myLDAPSetStringAttribute(
|
|
pld,
|
|
pwszDN,
|
|
CA_PROP_CERT_DN,
|
|
pwszSubject,
|
|
&dwDisposition,
|
|
&pwszError);
|
|
_JumpIfErrorStr(hr, error, "myLDAPSetStringAttribute", pwszDN);
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
coreLogPublishError(RequestId, pld, pwszDN, fDelete, pwszError, hr);
|
|
}
|
|
if (NULL != pwszError)
|
|
{
|
|
LocalFree(pwszError);
|
|
}
|
|
if (NULL != pld)
|
|
{
|
|
ldap_unbind(pld);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
#define wszCONTACTFILTER L"(&(&(objectCategory=contact)(objectClass=contact))(mail=%s))"
|
|
|
|
HRESULT
|
|
coreGetDNFromEMailName(
|
|
IN LDAP *pld,
|
|
IN WCHAR const *pwszEMailName,
|
|
OUT WCHAR **ppwszDN,
|
|
OUT DWORD *pdwDisposition,
|
|
OPTIONAL OUT WCHAR **ppwszError)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cres;
|
|
LDAP_TIMEVAL timeval;
|
|
LDAPMessage *pmsg = NULL;
|
|
LDAPMessage *pres;
|
|
WCHAR *apwszAttrs[2];
|
|
WCHAR **ppwszValues = NULL;
|
|
CAutoLPWSTR pwszFilter;
|
|
CAutoBSTR strDomainDN;
|
|
|
|
pwszFilter = (LPWSTR) LocalAlloc(LMEM_FIXED,
|
|
sizeof(WCHAR)*(wcslen(wszCONTACTFILTER)+wcslen(pwszEMailName)));
|
|
_JumpIfAllocFailed(pwszFilter, error);
|
|
|
|
wsprintf(pwszFilter, wszCONTACTFILTER, pwszEMailName);
|
|
|
|
hr = myGetAuthoritativeDomainDn(pld, &strDomainDN, NULL);
|
|
_JumpIfError(hr, error, "myGetAuthoritativeDomainDn");
|
|
|
|
*ppwszDN = NULL;
|
|
*pdwDisposition = LDAP_OTHER;
|
|
if (NULL != ppwszError)
|
|
{
|
|
*ppwszError = NULL;
|
|
}
|
|
apwszAttrs[0] = wszDSDNATTRIBUTE;
|
|
apwszAttrs[1] = NULL;
|
|
|
|
timeval.tv_sec = csecLDAPTIMEOUT;
|
|
timeval.tv_usec = 0;
|
|
|
|
hr = ldap_search_st(
|
|
pld, // ld
|
|
strDomainDN, // base
|
|
LDAP_SCOPE_SUBTREE, // scope
|
|
pwszFilter, // filter
|
|
apwszAttrs, // attrs
|
|
FALSE, // attrsonly
|
|
&timeval, // timeout
|
|
&pmsg); // res
|
|
if (S_OK != hr)
|
|
{
|
|
*pdwDisposition = hr;
|
|
hr = myHLdapError(pld, hr, ppwszError);
|
|
_JumpErrorStr(hr, error, "ldap_search_st", pwszFilter);
|
|
}
|
|
hr = HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND);
|
|
cres = ldap_count_entries(pld, pmsg);
|
|
if (0 == cres)
|
|
{
|
|
_JumpError(hr, error, "ldap_count_entries");
|
|
}
|
|
pres = ldap_first_entry(pld, pmsg);
|
|
if (NULL == pres)
|
|
{
|
|
_JumpError(hr, error, "ldap_first_entry");
|
|
}
|
|
ppwszValues = ldap_get_values(pld, pres, wszDSDNATTRIBUTE);
|
|
if (NULL == ppwszValues || NULL == ppwszValues[0])
|
|
{
|
|
_JumpError(hr, error, "ldap_get_values");
|
|
}
|
|
hr = myDupString(ppwszValues[0], ppwszDN);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
*pdwDisposition = LDAP_SUCCESS;
|
|
|
|
error:
|
|
if (NULL != ppwszValues)
|
|
{
|
|
ldap_value_free(ppwszValues);
|
|
}
|
|
if (NULL != pmsg)
|
|
{
|
|
ldap_msgfree(pmsg);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreGetEMailNameFromDN(
|
|
IN LDAP *pld,
|
|
IN WCHAR const *pwszDN,
|
|
OUT WCHAR **ppwszEMailName,
|
|
OUT DWORD *pdwDisposition,
|
|
OPTIONAL OUT WCHAR **ppwszError)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cres;
|
|
LDAP_TIMEVAL timeval;
|
|
LDAPMessage *pmsg = NULL;
|
|
LDAPMessage *pres;
|
|
WCHAR *apwszAttrs[2];
|
|
WCHAR **ppwszValues = NULL;
|
|
|
|
*pdwDisposition = LDAP_OTHER;
|
|
if (NULL != ppwszError)
|
|
{
|
|
*ppwszError = NULL;
|
|
}
|
|
apwszAttrs[0] = wszDSMAILATTRIBUTE;
|
|
apwszAttrs[1] = NULL;
|
|
|
|
timeval.tv_sec = csecLDAPTIMEOUT;
|
|
timeval.tv_usec = 0;
|
|
|
|
hr = ldap_search_st(
|
|
pld, // ld
|
|
const_cast<WCHAR *>(pwszDN), // base
|
|
LDAP_SCOPE_BASE, // scope
|
|
NULL, // filter
|
|
apwszAttrs, // attrs
|
|
FALSE, // attrsonly
|
|
&timeval, // timeout
|
|
&pmsg); // res
|
|
if (S_OK != hr)
|
|
{
|
|
*pdwDisposition = hr;
|
|
hr = myHLdapError(pld, hr, ppwszError);
|
|
_JumpErrorStr(hr, error, "ldap_search_st", pwszDN);
|
|
}
|
|
hr = CERTSRV_E_PROPERTY_EMPTY;
|
|
cres = ldap_count_entries(pld, pmsg);
|
|
if (0 == cres)
|
|
{
|
|
_JumpError(hr, error, "ldap_count_entries");
|
|
}
|
|
pres = ldap_first_entry(pld, pmsg);
|
|
if (NULL == pres)
|
|
{
|
|
_JumpError(hr, error, "ldap_first_entry");
|
|
}
|
|
ppwszValues = ldap_get_values(pld, pres, wszDSMAILATTRIBUTE);
|
|
if (NULL == ppwszValues || NULL == ppwszValues[0])
|
|
{
|
|
_JumpError(hr, error, "ldap_get_values");
|
|
}
|
|
hr = myDupString(ppwszValues[0], ppwszEMailName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
*pdwDisposition = LDAP_SUCCESS;
|
|
|
|
error:
|
|
if (NULL != ppwszValues)
|
|
{
|
|
ldap_value_free(ppwszValues);
|
|
}
|
|
if (NULL != pmsg)
|
|
{
|
|
ldap_msgfree(pmsg);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
corePublishCertToForest(
|
|
IN DWORD iForest,
|
|
IN DWORD RequestId,
|
|
OPTIONAL IN WCHAR const *pwszDomainDns, // NULL for 0 < iForest
|
|
OPTIONAL IN WCHAR const *pwszDN, // NULL for 0 < iForest
|
|
OPTIONAL IN WCHAR const *pwszEMailName, // NULL for 0 == iForest
|
|
IN CERT_CONTEXT const *pcc,
|
|
IN DWORD dwObjectType, // LPC_*
|
|
OPTIONAL OUT WCHAR **ppwszEMailName) // NULL for 0 < iForest
|
|
{
|
|
HRESULT hr;
|
|
LDAPCACHE *plc = NULL;
|
|
DWORD dwDisposition;
|
|
WCHAR *pwszContactDN = NULL;
|
|
WCHAR *pwszError = NULL;
|
|
|
|
if (NULL != ppwszEMailName)
|
|
{
|
|
*ppwszEMailName = NULL;
|
|
}
|
|
hr = S_OK;
|
|
__try
|
|
{
|
|
for (;;)
|
|
{
|
|
BOOL fCached;
|
|
|
|
if (NULL != pwszError)
|
|
{
|
|
LocalFree(pwszError);
|
|
pwszError = NULL;
|
|
}
|
|
if (NULL != plc)
|
|
{
|
|
coreLdapUnbind(plc);
|
|
plc = NULL;
|
|
//coreLdapEmptyCache(iForest);
|
|
}
|
|
hr = coreLdapGetHandle(iForest, pwszDomainDns, &plc, &fCached);
|
|
_LeaveIfError(hr, "coreLdapGetHandle");
|
|
|
|
if (NULL != pwszEMailName)
|
|
{
|
|
CSASSERT(NULL == pwszDN);
|
|
hr = coreGetDNFromEMailName(
|
|
plc->pld,
|
|
pwszEMailName,
|
|
&pwszContactDN,
|
|
&dwDisposition,
|
|
&pwszError);
|
|
_PrintIfErrorStr(
|
|
hr,
|
|
fCached?
|
|
"coreGetDNFromEMailName(cached)" :
|
|
"coreGetDNFromEMailName(noncached)",
|
|
pwszDN);
|
|
if (!fCached ||
|
|
!myLdapRebindRequired(dwDisposition, plc->pld))
|
|
{
|
|
_LeaveIfError(hr, "myLdapPublishCertToDS");
|
|
}
|
|
|
|
if (S_OK == hr)
|
|
{
|
|
pwszDN = pwszContactDN;
|
|
}
|
|
}
|
|
|
|
hr = myLdapPublishCertToDS(
|
|
plc->pld,
|
|
pcc,
|
|
pwszDN,
|
|
wszDSUSERCERTATTRIBUTE,
|
|
dwObjectType, // LPC_*
|
|
FALSE, // fDelete
|
|
&dwDisposition,
|
|
&pwszError);
|
|
if (S_OK == hr)
|
|
{
|
|
break;
|
|
}
|
|
_PrintErrorStr(
|
|
hr,
|
|
fCached?
|
|
"myLdapPublishCertToDS(cached)" :
|
|
"myLdapPublishCertToDS(noncached)",
|
|
pwszDN);
|
|
if (!fCached ||
|
|
!myLdapRebindRequired(dwDisposition, plc->pld))
|
|
{
|
|
_LeaveError(hr, "myLdapPublishCertToDS");
|
|
}
|
|
}
|
|
if (NULL != ppwszEMailName)
|
|
{
|
|
hr = coreGetEMailNameFromDN(
|
|
plc->pld,
|
|
pwszDN,
|
|
ppwszEMailName,
|
|
&dwDisposition,
|
|
&pwszError);
|
|
_PrintIfErrorStr(hr, "coreGetEMailNameFromDN", pwszDN);
|
|
}
|
|
}
|
|
__except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
_PrintError(hr, "Exception");
|
|
}
|
|
|
|
//error:
|
|
if (S_OK != hr)
|
|
{
|
|
coreLogPublishError(
|
|
RequestId,
|
|
NULL != plc? plc->pld : NULL,
|
|
pwszDN,
|
|
FALSE, // fDelete
|
|
pwszError,
|
|
hr);
|
|
}
|
|
if (NULL != plc)
|
|
{
|
|
coreLdapReleaseHandle(iForest, plc);
|
|
}
|
|
if (NULL != pwszContactDN)
|
|
{
|
|
LocalFree(pwszContactDN);
|
|
}
|
|
if (NULL != pwszError)
|
|
{
|
|
LocalFree(pwszError);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreGetDomainDnsNameFromDN(
|
|
IN WCHAR const *pwszDN,
|
|
OUT WCHAR **ppwszDomainDns)
|
|
{
|
|
HRESULT hr;
|
|
DS_NAME_RESULT *pNameResults = NULL;
|
|
WCHAR const *pwc;
|
|
DWORD cwc;
|
|
|
|
CSASSERT(NULL != ppwszDomainDns);
|
|
*ppwszDomainDns = NULL;
|
|
|
|
hr = DsCrackNames(
|
|
NULL, // hDS
|
|
DS_NAME_FLAG_SYNTACTICAL_ONLY,
|
|
DS_FQDN_1779_NAME,
|
|
DS_CANONICAL_NAME,
|
|
1, // one name
|
|
&pwszDN, // one name (IN)
|
|
&pNameResults); // OUT
|
|
if (S_OK != hr)
|
|
{
|
|
hr = myHError(hr);
|
|
_JumpError(hr, error, "DsCrackNames");
|
|
}
|
|
if (1 > pNameResults->cItems ||
|
|
DS_NAME_NO_ERROR != pNameResults->rItems[0].status)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
|
|
_JumpError(hr, error, "DsCrackNames result");
|
|
}
|
|
pwc = wcschr(pNameResults->rItems[0].pName, L'/');
|
|
if (NULL == pwc)
|
|
{
|
|
cwc = wcslen(pNameResults->rItems[0].pName);
|
|
}
|
|
else
|
|
{
|
|
cwc = SAFE_SUBTRACT_POINTERS(pwc, pNameResults->rItems[0].pName);
|
|
}
|
|
*ppwszDomainDns = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(cwc + 1) * sizeof(WCHAR));
|
|
if (NULL == *ppwszDomainDns)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CopyMemory(
|
|
*ppwszDomainDns,
|
|
pNameResults->rItems[0].pName,
|
|
cwc * sizeof(WCHAR));
|
|
(*ppwszDomainDns)[cwc] = L'\0';
|
|
|
|
error:
|
|
if (NULL != pNameResults)
|
|
{
|
|
DsFreeNameResult(pNameResults);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
corePublishUserCertificate(
|
|
IN DWORD RequestId,
|
|
IN DWORD dwComContextIndex,
|
|
IN WCHAR const *pwszSamName,
|
|
IN CERT_CONTEXT const *pcc,
|
|
IN DWORD dwObjectType) // LPC_*
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszSamNamePatched = NULL;
|
|
WCHAR *pwszDomainDns = NULL;
|
|
WCHAR const *pwszUserName;
|
|
WCHAR const *pwszDN;
|
|
WCHAR *pwszEMailName = NULL;
|
|
DWORD i;
|
|
|
|
hr = myAddDomainName(pwszSamName, &pwszSamNamePatched, &pwszUserName);
|
|
_JumpIfError(hr, error, "myAddDomainName");
|
|
|
|
if (NULL != pwszSamNamePatched)
|
|
{
|
|
pwszSamName = pwszSamNamePatched;
|
|
}
|
|
hr = coreGetComContextUserDNFromSamName(
|
|
FALSE, // fDeleteUserDNOnly
|
|
pwszSamName,
|
|
0, // Context
|
|
dwComContextIndex,
|
|
&pwszDN);
|
|
_JumpIfError(hr, error, "coreGetComContextUserDNFromSamName");
|
|
|
|
hr = coreGetDomainDnsNameFromDN(pwszDN, &pwszDomainDns);
|
|
_JumpIfError(hr, error, "coreGetDomainDnsNameFromDN");
|
|
|
|
// For the domestic forest, pass the User object's native domain and DN,
|
|
// and collect the EMail name (if any alternate forests were specified).
|
|
|
|
hr = corePublishCertToForest(
|
|
0, // iForest
|
|
RequestId,
|
|
pwszDomainDns,
|
|
pwszDN,
|
|
NULL, // pwszEMailName
|
|
pcc,
|
|
dwObjectType, // LPC_*
|
|
1 < g_cForestLdapCache? &pwszEMailName : NULL);
|
|
_PrintIfError(hr, "corePublishCertToForest");
|
|
|
|
// For alternate forests, pass a NULL domain, the Contact object's EMail
|
|
// name, and do not collect the EMail name.
|
|
|
|
for (i = 1; i < g_cForestLdapCache; i++)
|
|
{
|
|
if (NULL == pwszEMailName)
|
|
{
|
|
break; // EMail name needed to publish to alternate Forests
|
|
}
|
|
hr = corePublishCertToForest(
|
|
i, // iForest
|
|
RequestId,
|
|
NULL, // pwszDomainDns
|
|
NULL, // pwszDN
|
|
pwszEMailName,
|
|
pcc,
|
|
dwObjectType, // LPC_*
|
|
NULL); // ppwszEMailName
|
|
_PrintIfError(hr, "corePublishCertToForest");
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszEMailName)
|
|
{
|
|
LocalFree(pwszEMailName);
|
|
}
|
|
if (NULL != pwszDomainDns)
|
|
{
|
|
LocalFree(pwszDomainDns);
|
|
}
|
|
if (NULL != pwszSamNamePatched)
|
|
{
|
|
LocalFree(pwszSamNamePatched);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CorePublishCertificate(
|
|
IN ICertDBRow *prow,
|
|
IN DWORD dwComContextIndex)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbProp;
|
|
DWORD RequestId;
|
|
DWORD GeneralFlags;
|
|
DWORD EnrollmentFlags;
|
|
DWORD cbCert;
|
|
BYTE *pbCert = NULL;
|
|
CERT_CONTEXT const *pcc = NULL;
|
|
WCHAR *pwszSamName = NULL;
|
|
|
|
prow->GetRowId(&RequestId);
|
|
|
|
cbProp = sizeof(EnrollmentFlags);
|
|
hr = prow->GetProperty(
|
|
wszPROPCERTIFICATEENROLLMENTFLAGS,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
|
|
NULL,
|
|
&cbProp,
|
|
(BYTE *) &EnrollmentFlags);
|
|
_PrintIfError2(hr, "GetProperty", CERTSRV_E_PROPERTY_EMPTY);
|
|
if (S_OK != hr)
|
|
{
|
|
EnrollmentFlags = 0;
|
|
}
|
|
|
|
if (0 == ((CT_FLAG_PUBLISH_TO_DS | CT_FLAG_PUBLISH_TO_KRA_CONTAINER) &
|
|
EnrollmentFlags))
|
|
{
|
|
hr = S_OK;
|
|
goto error;
|
|
}
|
|
|
|
cbProp = sizeof(GeneralFlags);
|
|
hr = prow->GetProperty(
|
|
wszPROPCERTIFICATEGENERALFLAGS,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
|
|
NULL,
|
|
&cbProp,
|
|
(BYTE *) &GeneralFlags);
|
|
_PrintIfError2(hr, "GetProperty", CERTSRV_E_PROPERTY_EMPTY);
|
|
if (S_OK != hr)
|
|
{
|
|
GeneralFlags = 0;
|
|
}
|
|
|
|
// Get the name of the user or machine
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropRequesterName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
(BYTE **) &pwszSamName);
|
|
_JumpIfError(hr, error, "PKCSGetProperty");
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
g_wszPropRawCertificate,
|
|
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
|
|
&cbCert,
|
|
&pbCert);
|
|
_JumpIfError(hr, error, "PKCSGetProperty(raw cert)");
|
|
|
|
pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
|
|
if (NULL == pcc)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
|
|
hr = S_OK;
|
|
if (CT_FLAG_PUBLISH_TO_DS & EnrollmentFlags)
|
|
{
|
|
if (CT_FLAG_IS_CROSS_CA & GeneralFlags)
|
|
{
|
|
hr = CorePublishCrossCertificate(
|
|
RequestId,
|
|
pcc,
|
|
TRUE, // fCreateDSObject
|
|
FALSE); // fDelete
|
|
_PrintIfError(hr, "CorePublishCrossCertificate"); // DS object if necessary
|
|
}
|
|
else
|
|
{
|
|
hr = corePublishUserCertificate(
|
|
RequestId,
|
|
dwComContextIndex,
|
|
pwszSamName,
|
|
pcc,
|
|
(CT_FLAG_MACHINE_TYPE & GeneralFlags)?
|
|
LPC_MACHINEOBJECT : LPC_USEROBJECT);
|
|
_PrintIfError(hr, "corePublishUserCertificate");
|
|
}
|
|
}
|
|
|
|
if (CT_FLAG_PUBLISH_TO_KRA_CONTAINER & EnrollmentFlags)
|
|
{
|
|
HRESULT hr2;
|
|
|
|
hr2 = corePublishKRACertificate(RequestId, pcc);
|
|
_PrintIfError(hr2, "corePublishKRACertificate");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
_JumpIfError(hr, error, "CorePublishCertificate");
|
|
|
|
error:
|
|
if (NULL != pwszSamName)
|
|
{
|
|
LocalFree(pwszSamName);
|
|
}
|
|
if (NULL != pcc)
|
|
{
|
|
CertFreeCertificateContext(pcc);
|
|
}
|
|
if (NULL != pbCert)
|
|
{
|
|
LocalFree(pbCert);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreAcceptRequest(
|
|
IN ICertDBRow *prow,
|
|
IN BOOL fIncludeCRLs,
|
|
IN DWORD dwComContextIndex,
|
|
OUT BOOL *pfErrorLogged,
|
|
OUT CACTX **ppCAContext,
|
|
IN OUT CERTSRV_RESULT_CONTEXT *pResult, // CoTaskMem*
|
|
OUT WCHAR **ppwszDispositionCreateCert,
|
|
OUT HRESULT *phrPublish)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*ppCAContext = NULL;
|
|
*ppwszDispositionCreateCert = NULL;
|
|
*phrPublish = S_OK;
|
|
|
|
// Force Cert creation:
|
|
CSASSERT(NULL == pResult->pctbCert || NULL == pResult->pctbCert->pb);
|
|
|
|
hr = CoreValidateRequestId(prow, DB_DISP_ACTIVE);
|
|
_JumpIfError(hr, error, "CoreValidateRequestId");
|
|
|
|
hr = PKCSCreateCertificate(
|
|
prow,
|
|
DB_DISP_ACTIVE,
|
|
fIncludeCRLs,
|
|
FALSE, // fAllowCASubject
|
|
NULL, // use default signing CACTX
|
|
pfErrorLogged,
|
|
ppCAContext,
|
|
ppwszDispositionCreateCert,
|
|
pResult);
|
|
_JumpIfError(hr, error, "PKCSCreateCertificate");
|
|
|
|
*phrPublish = CorePublishCertificate(prow, dwComContextIndex);
|
|
_PrintIfError(*phrPublish, "CorePublishCertificate");
|
|
if (S_OK != *phrPublish)
|
|
{
|
|
hr = PKCSSetRequestFlags(prow, TRUE, CR_FLG_PUBLISHERROR);
|
|
_JumpIfError(hr, error, "PKCSSetRequestFlags");
|
|
}
|
|
CSASSERT(S_OK == hr);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreVerifyRequest(
|
|
IN OUT ICertDBRow **pprow,
|
|
IN DWORD OpRequest,
|
|
IN BOOL fIncludeCRLs,
|
|
OPTIONAL IN WCHAR const *pwszUserName,
|
|
IN DWORD dwComContextIndex,
|
|
OUT DWORD *pReqId,
|
|
OUT LONG *pExitEvent,
|
|
OUT WCHAR **ppwszDisposition, // LocalAlloc
|
|
OUT CACTX **ppCAContext,
|
|
IN OUT CERTSRV_RESULT_CONTEXT *pResult) // CoTaskMem*
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
HRESULT hrRequest = S_OK;
|
|
HRESULT hrPublish = S_OK;
|
|
DWORD VerifyStatus;
|
|
DWORD DBDisposition;
|
|
BOOL fResolved;
|
|
LONG ExitEvent;
|
|
BOOL fPending;
|
|
BOOL fSubmit;
|
|
BOOL fRetrieve;
|
|
BOOL fDenied;
|
|
BOOL fUpdateDisposition = FALSE;
|
|
WCHAR *pwszDispositionCreateCert = NULL;
|
|
|
|
WCHAR *pwszDispositionRetrieved = NULL;
|
|
WCHAR const *pwszDispositionBase = NULL;
|
|
WCHAR *pwszDispositionDetail = NULL;
|
|
WCHAR *pwszDisposition = NULL;
|
|
WCHAR const *pwszBy = NULL;
|
|
|
|
DWORD LogMsg = MSG_E_PROCESS_REQUEST_FAILED;
|
|
BOOL fErrorLogged = FALSE;
|
|
DWORD ReqId;
|
|
ICertDBRow *prow = *pprow;
|
|
|
|
prow->GetRowId(&ReqId);
|
|
|
|
*ppCAContext = NULL;
|
|
*pResult->pdwDisposition = CR_DISP_ERROR;
|
|
DBDisposition = DB_DISP_ERROR;
|
|
*ppwszDisposition = NULL;
|
|
|
|
ExitEvent = EXITEVENT_INVALID;
|
|
|
|
fSubmit = CR_IN_NEW == OpRequest || CR_IN_RESUBMIT == OpRequest;
|
|
fPending = CR_IN_DENY == OpRequest || CR_IN_RESUBMIT == OpRequest;
|
|
fRetrieve = CR_IN_RETRIEVE == OpRequest;
|
|
|
|
#if DBG_COMTEST
|
|
if (fSubmit && fComTest && !ComTest((LONG) ReqId))
|
|
{
|
|
_PrintError(0, "ComTest");
|
|
}
|
|
#endif
|
|
|
|
if (fRetrieve)
|
|
{
|
|
hr = coreCheckRetrieveAccessRight(
|
|
prow,
|
|
pwszUserName);
|
|
_JumpIfError(hr, error, "coreCheckRetrieveAccessRight");
|
|
|
|
hr = coreRetrievePending(
|
|
prow,
|
|
fIncludeCRLs,
|
|
&pwszDispositionRetrieved,
|
|
ppCAContext,
|
|
pResult); // CoTaskMem*
|
|
_JumpIfError(hr, error, "coreRetrievePending");
|
|
|
|
pwszDispositionBase = pwszDispositionRetrieved;
|
|
ExitEvent = EXITEVENT_CERTRETRIEVEPENDING;
|
|
}
|
|
else
|
|
{
|
|
// If the current status is expected to be pending, verify that now,
|
|
// and make the request active.
|
|
//
|
|
// If it was already marked active, then something went wrong last time
|
|
// we processed the request (out of disk space?), and we can try to
|
|
// pick up where we left off, by resubmitting or denying the request.
|
|
|
|
if (fPending)
|
|
{
|
|
hr = CoreValidateRequestId(prow, DB_DISP_PENDING);
|
|
if (CERTSRV_E_BAD_REQUESTSTATUS == hr)
|
|
{
|
|
hr = CoreValidateRequestId(prow, DB_DISP_ACTIVE);
|
|
}
|
|
if (CERTSRV_E_BAD_REQUESTSTATUS == hr && fSubmit)
|
|
{
|
|
hr = CoreValidateRequestId(prow, DB_DISP_DENIED);
|
|
if (S_OK == hr)
|
|
{
|
|
DBGPRINT((
|
|
DBG_SS_CERTSRV,
|
|
"Resubmit failed request %u\n",
|
|
ReqId));
|
|
pResult->dwResultFlags |= CRCF_PREVIOUSLYDENIED;
|
|
if (CRCF_FAILDENIEDREQUEST & pResult->dwResultFlags)
|
|
{
|
|
hr = CERTSRV_E_BAD_REQUESTSTATUS;
|
|
}
|
|
}
|
|
}
|
|
_JumpIfError(hr, error, "CoreValidateRequestId");
|
|
|
|
hr = CoreSetDisposition(prow, DB_DISP_ACTIVE);
|
|
_JumpIfError(hr, error, "CoreSetDisposition");
|
|
}
|
|
fUpdateDisposition = TRUE;
|
|
if (fSubmit)
|
|
{
|
|
if (fPending)
|
|
{
|
|
pwszBy = g_pwszResubmittedBy;
|
|
|
|
hr = PKCSSetServerProperties(
|
|
prow,
|
|
NULL, // use default signing CACTX
|
|
NULL, // pftNotBefore
|
|
NULL, // pftNotAfter
|
|
g_lValidityPeriodCount,
|
|
g_enumValidityPeriod);
|
|
_JumpIfError(hr, error, "PKCSSetServerProperties");
|
|
}
|
|
|
|
hr = prow->CommitTransaction(TRUE);
|
|
_JumpIfError(hr, error, "CommitTransaction");
|
|
|
|
prow->Release();
|
|
prow = NULL;
|
|
*pprow = NULL;
|
|
|
|
hr = PolicyVerifyRequest(
|
|
g_wszCommonName,
|
|
ReqId,
|
|
g_PolicyFlags,
|
|
CR_IN_NEW == OpRequest,
|
|
CR_IN_NEW == OpRequest? pResult : NULL,
|
|
dwComContextIndex,
|
|
&pwszDispositionDetail,
|
|
&VerifyStatus);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "PolicyVerifyRequest");
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (S_FALSE == hr)
|
|
{
|
|
hr = E_UNEXPECTED;
|
|
}
|
|
else
|
|
{
|
|
hr = myHError(hr);
|
|
}
|
|
}
|
|
VerifyStatus = hr;
|
|
}
|
|
|
|
hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, ReqId, NULL, &prow);
|
|
_JumpIfError(hr, error, "OpenRow");
|
|
|
|
CSASSERT(NULL != prow);
|
|
*pprow = prow;
|
|
}
|
|
else // else we're denying the request!
|
|
{
|
|
VerifyStatus = VR_INSTANT_BAD;
|
|
}
|
|
|
|
fResolved = FALSE;
|
|
fDenied = FALSE;
|
|
switch (VerifyStatus)
|
|
{
|
|
case VR_PENDING:
|
|
hr = S_OK;
|
|
DBDisposition = DB_DISP_PENDING;
|
|
ExitEvent = EXITEVENT_CERTPENDING;
|
|
LogMsg = MSG_DN_CERT_PENDING;
|
|
*pResult->pdwDisposition = CR_DISP_UNDER_SUBMISSION;
|
|
pwszDispositionBase = g_pwszUnderSubmission;
|
|
break;
|
|
|
|
case VR_INSTANT_OK:
|
|
hr = coreAcceptRequest(
|
|
prow,
|
|
fIncludeCRLs,
|
|
dwComContextIndex,
|
|
&fErrorLogged,
|
|
ppCAContext,
|
|
pResult,
|
|
&pwszDispositionCreateCert,
|
|
&hrPublish);
|
|
if (S_OK != hr)
|
|
{
|
|
CSASSERT(FAILED(hr));
|
|
_PrintError(hr, "coreAcceptRequest");
|
|
pwszDispositionBase = g_pwszCertConstructionError;
|
|
VerifyStatus = hr;
|
|
hr = S_OK;
|
|
fDenied = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fResolved = TRUE;
|
|
DBDisposition = DB_DISP_ISSUED;
|
|
ExitEvent = EXITEVENT_CERTISSUED;
|
|
LogMsg = MSG_DN_CERT_ISSUED;
|
|
*pResult->pdwDisposition = CR_DISP_ISSUED;
|
|
pwszDispositionBase = g_pwszIssued;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (SUCCEEDED(VerifyStatus))
|
|
{
|
|
CSASSERT(
|
|
VerifyStatus == VR_PENDING ||
|
|
VerifyStatus == VR_INSTANT_OK ||
|
|
VerifyStatus == VR_INSTANT_BAD);
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "VerifyStatus");
|
|
}
|
|
// FALLTHROUGH
|
|
|
|
case VR_INSTANT_BAD:
|
|
hr = CoreValidateRequestId(prow, DB_DISP_ACTIVE);
|
|
_JumpIfError(hr, error, "CoreValidateRequestId");
|
|
|
|
fDenied = TRUE;
|
|
break;
|
|
}
|
|
if (fDenied)
|
|
{
|
|
fResolved = TRUE;
|
|
DBDisposition = DB_DISP_DENIED;
|
|
ExitEvent = EXITEVENT_CERTDENIED;
|
|
|
|
*pResult->pdwDisposition = CR_DISP_DENIED;
|
|
if (FAILED(VerifyStatus))
|
|
{
|
|
*pResult->pdwDisposition = VerifyStatus;
|
|
hrRequest = VerifyStatus;
|
|
}
|
|
|
|
if (fSubmit)
|
|
{
|
|
if (NULL == pwszDispositionBase)
|
|
{
|
|
pwszDispositionBase = g_pwszPolicyDeniedRequest;
|
|
}
|
|
LogMsg = MSG_DN_CERT_DENIED;
|
|
}
|
|
else
|
|
{
|
|
pwszDispositionBase = g_pwszDeniedBy;
|
|
LogMsg = MSG_DN_CERT_ADMIN_DENIED;
|
|
}
|
|
}
|
|
if (fResolved)
|
|
{
|
|
hr = PropSetRequestTimeProperty(prow, g_wszPropRequestResolvedWhen);
|
|
_JumpIfError(hr, error, "PropSetRequestTimeProperty");
|
|
}
|
|
}
|
|
|
|
error:
|
|
*pReqId = ReqId;
|
|
*pExitEvent = ExitEvent;
|
|
|
|
// If we verified or denied the request, set the status & disposition
|
|
|
|
// Build the full disposition string
|
|
|
|
pwszDisposition = CoreBuildDispositionString(
|
|
pwszDispositionBase,
|
|
pwszUserName,
|
|
pwszDispositionDetail,
|
|
pwszDispositionCreateCert,
|
|
pwszBy,
|
|
hrPublish,
|
|
TRUE);
|
|
|
|
if (NULL != pwszDispositionDetail)
|
|
{
|
|
LocalFree(pwszDispositionDetail);
|
|
}
|
|
|
|
if (S_OK == hrRequest && S_OK != hr)
|
|
{
|
|
hrRequest = hr;
|
|
}
|
|
if (fUpdateDisposition && NULL != prow)
|
|
{
|
|
hr2 = CoreSetRequestDispositionFields(
|
|
prow,
|
|
hrRequest,
|
|
DBDisposition,
|
|
pwszDisposition);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
|
|
if (!fErrorLogged &&
|
|
NULL != prow &&
|
|
(fUpdateDisposition || S_OK != hr))
|
|
{
|
|
CoreLogRequestStatus(prow, LogMsg, hrRequest, pwszDisposition);
|
|
}
|
|
|
|
if (NULL != ppwszDisposition)
|
|
{
|
|
*ppwszDisposition = pwszDisposition;
|
|
}
|
|
else if (NULL != pwszDisposition)
|
|
{
|
|
LocalFree(pwszDisposition);
|
|
}
|
|
if (NULL != pwszDispositionRetrieved)
|
|
{
|
|
LocalFree(pwszDispositionRetrieved);
|
|
}
|
|
if (NULL != pwszDispositionCreateCert)
|
|
{
|
|
LocalFree(pwszDispositionCreateCert);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreAuditAddStringProperty(
|
|
IN ICertDBRow *prow,
|
|
IN WCHAR const *pwszPropName,
|
|
IN CertSrv::CAuditEvent *pevent)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR const *pwszLogValue = L"";
|
|
WCHAR *pwszPropValue = NULL;
|
|
|
|
hr = PKCSGetProperty(
|
|
prow,
|
|
pwszPropName,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
|
|
NULL,
|
|
(BYTE **) &pwszPropValue);
|
|
_PrintIfErrorStr2(hr, "PKCSGetProperty", pwszPropName, CERTSRV_E_PROPERTY_EMPTY);
|
|
if (S_OK == hr)
|
|
{
|
|
pwszLogValue = pwszPropValue;
|
|
}
|
|
hr = pevent->AddData(pwszLogValue);
|
|
_JumpIfError(hr, error, "CAuditEvent::AddData");
|
|
|
|
error:
|
|
if (NULL != pwszPropValue)
|
|
{
|
|
LocalFree(pwszPropValue);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreAuditRequestDisposition(
|
|
OPTIONAL IN ICertDBRow *prow,
|
|
IN DWORD ReqId,
|
|
IN WCHAR const *pwszUserName,
|
|
IN WCHAR const *pwszAttributes,
|
|
IN DWORD dwDisposition)
|
|
{
|
|
HRESULT hr;
|
|
|
|
CertSrv::CAuditEvent
|
|
audit(0, g_dwAuditFilter);
|
|
|
|
hr = audit.AddData(ReqId); // %1 request ID
|
|
_JumpIfError(hr, error, "CAuditEvent::AddData");
|
|
|
|
hr = audit.AddData(pwszUserName); // %2 requester
|
|
_JumpIfError(hr, error, "CAuditEvent::AddData");
|
|
|
|
hr = audit.AddData(pwszAttributes); // %3 attributes
|
|
_JumpIfError(hr, error, "CAuditEvent::AddData");
|
|
|
|
hr = audit.AddData(dwDisposition); // %4 disposition
|
|
_JumpIfError(hr, error, "CAuditEvent::AddData");
|
|
|
|
if (NULL != prow)
|
|
{
|
|
hr = coreAuditAddStringProperty(
|
|
prow,
|
|
g_wszPropCertificateSubjectKeyIdentifier,
|
|
&audit); // %5 SKI
|
|
_JumpIfError(hr, error, "coreAuditAddStringProperty");
|
|
|
|
hr = coreAuditAddStringProperty(
|
|
prow,
|
|
g_wszPropSubjectDistinguishedName,
|
|
&audit); // %6 Subject
|
|
_JumpIfError(hr, error, "coreAuditAddStringProperty");
|
|
}
|
|
else // we need to guarantee the same number of audit params
|
|
{
|
|
hr = audit.AddData(L""); // %5 SKI
|
|
_JumpIfError(hr, error, "");
|
|
|
|
hr = audit.AddData(L""); // %6 Subject
|
|
_JumpIfError(hr, error, "");
|
|
}
|
|
|
|
switch (dwDisposition)
|
|
{
|
|
case CR_DISP_ISSUED:
|
|
audit.SetEventID(SE_AUDITID_CERTSRV_REQUESTAPPROVED);
|
|
hr = audit.Report();
|
|
_JumpIfError(hr, error, "CAuditEvent::Report");
|
|
|
|
break;
|
|
|
|
case CR_DISP_UNDER_SUBMISSION:
|
|
audit.SetEventID(SE_AUDITID_CERTSRV_REQUESTPENDING);
|
|
hr = audit.Report();
|
|
_JumpIfError(hr, error, "CAuditEvent::Report");
|
|
|
|
break;
|
|
|
|
case CR_DISP_DENIED: // fail over
|
|
default:
|
|
audit.SetEventID(SE_AUDITID_CERTSRV_REQUESTDENIED);
|
|
hr = audit.Report(false);
|
|
_JumpIfError(hr, error, "CAuditEvent::Report");
|
|
break;
|
|
|
|
}
|
|
CSASSERT(S_OK == hr);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreValidateMessageSize(
|
|
IN OPTIONAL LPCWSTR pwszUser,
|
|
IN DWORD cbRequest)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (cbRequest > g_cbMaxIncomingMessageSize)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_MESSAGE_EXCEEDS_MAX_SIZE);
|
|
|
|
if (CERTLOG_VERBOSE <= g_dwLogLevel)
|
|
{
|
|
LogEventStringHResult(
|
|
EVENTLOG_ERROR_TYPE,
|
|
MSG_E_POSSIBLE_DENIAL_OF_SERVICE_ATTACK,
|
|
NULL != pwszUser? pwszUser : g_pwszUnknownSubject,
|
|
hr);
|
|
}
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
coreInitRequest(
|
|
IN DWORD dwFlags,
|
|
OPTIONAL IN WCHAR const *pwszUserName,
|
|
IN DWORD cbRequest,
|
|
OPTIONAL IN BYTE const *pbRequest,
|
|
OPTIONAL IN WCHAR const *pwszAttributes,
|
|
OPTIONAL IN WCHAR const *pwszSerialNumber,
|
|
IN DWORD dwComContextIndex,
|
|
OUT DWORD *pOpRequest,
|
|
OUT ICertDBRow **pprow, // may return non-NULL on error
|
|
OUT WCHAR **ppwszDisposition,
|
|
IN OUT CERTSRV_RESULT_CONTEXT *pResult)
|
|
{
|
|
HRESULT hr;
|
|
|
|
*pprow = NULL;
|
|
*ppwszDisposition = NULL;
|
|
|
|
// for Denial-of-Service reasons, don't do anything with a too-long message
|
|
|
|
hr = coreValidateMessageSize(pwszUserName, cbRequest);
|
|
_JumpIfError(hr, error, "coreValidateMessageSize");
|
|
|
|
// Called in several cases:
|
|
//
|
|
// - CR_IN_NEW: Create a new request and return error/pending/etc &
|
|
// possibly the cert:
|
|
// NULL != pbRequest && NULL != pResult->pctbCert, etc.
|
|
//
|
|
// - CR_IN_DENY: Deny a pending request:
|
|
// NULL == pbRequest && NULL == pResult->pctbCert, etc.
|
|
//
|
|
// - CR_IN_RESUBMIT: Resubmit a pending request and return hr/pending/etc.
|
|
// NULL == pbRequest && NULL == pResult->pctbCert, etc.
|
|
//
|
|
// - CR_IN_RETRIEVE: Retrieve a cert for a processed request and return
|
|
// error/pending/etc & possibly the cert:
|
|
// NULL == pbRequest && NULL != pResult->pctbCert, etc.
|
|
|
|
*pOpRequest = (CR_IN_COREMASK & dwFlags);
|
|
switch (*pOpRequest)
|
|
{
|
|
// Process a new request:
|
|
|
|
case CR_IN_NEW:
|
|
CSASSERT(NULL != pwszUserName);
|
|
CSASSERT(0 != cbRequest);
|
|
CSASSERT(NULL != pbRequest);
|
|
|
|
CSASSERT(0 == *pResult->pdwRequestId);
|
|
*pResult->pdwRequestId = 0;
|
|
|
|
hr = coreCreateRequest(
|
|
~CR_IN_COREMASK & dwFlags,
|
|
pwszUserName,
|
|
cbRequest,
|
|
pbRequest,
|
|
pwszAttributes,
|
|
dwComContextIndex,
|
|
pprow,
|
|
pResult);
|
|
_JumpIfError(hr, error, "coreCreateRequest");
|
|
|
|
(*pprow)->GetRowId(pResult->pdwRequestId);
|
|
{
|
|
CertSrv::CAuditEvent
|
|
audit(SE_AUDITID_CERTSRV_NEWREQUEST, g_dwAuditFilter);
|
|
|
|
hr = audit.AddData(*pResult->pdwRequestId); // %1 request ID
|
|
_JumpIfError(hr, error, "CAuditEvent::AddData");
|
|
|
|
hr = audit.AddData(pwszUserName); // %2 requester
|
|
_JumpIfError(hr, error, "CAuditEvent::AddData");
|
|
|
|
hr = audit.AddData(pwszAttributes); // %3 attributes
|
|
_JumpIfError(hr, error, "CAuditEvent::AddData");
|
|
|
|
hr = audit.Report();
|
|
_JumpIfError(hr, error, "CAuditEvent::Report");
|
|
}
|
|
break;
|
|
|
|
// Deny a request:
|
|
// Resubmit a request:
|
|
|
|
case CR_IN_DENY:
|
|
case CR_IN_RESUBMIT:
|
|
break;
|
|
|
|
// Retrieve a cert:
|
|
|
|
case CR_IN_RETRIEVE:
|
|
break;
|
|
|
|
default:
|
|
CSASSERT(*pOpRequest != *pOpRequest);
|
|
break;
|
|
}
|
|
if (CR_IN_NEW != *pOpRequest)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
if (0 != cbRequest || NULL != pbRequest)
|
|
{
|
|
_JumpError(hr, error, "unexpected request");
|
|
}
|
|
if ((0 != *pResult->pdwRequestId) ^ (NULL == pwszSerialNumber))
|
|
{
|
|
_JumpError(hr, error, "expected RequestId or SerialNumber");
|
|
}
|
|
|
|
// RetrievePending by RequestId OR SerialNumber in pwszSerialNumber
|
|
|
|
hr = g_pCertDB->OpenRow(
|
|
PROPTABLE_REQCERT,
|
|
*pResult->pdwRequestId,
|
|
pwszSerialNumber,
|
|
pprow);
|
|
_JumpIfError(hr, error, "OpenRow");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr)
|
|
{
|
|
HRESULT hr2;
|
|
|
|
hr2 = myDupString(
|
|
(CRCF_SIGNATUREERROR & pResult->dwResultFlags)?
|
|
g_pwszRequestSigError :
|
|
((CRCF_ARCHIVESIGNINGKEYERROR & pResult->dwResultFlags)?
|
|
g_pwszArchiveSigningKeyError :
|
|
((CRCF_KEYARCHIVALERROR & pResult->dwResultFlags)?
|
|
g_pwszKeyArchivalError :
|
|
g_pwszRequestParsingError)),
|
|
ppwszDisposition);
|
|
_PrintIfError(hr2, "myDupString");
|
|
|
|
if (NULL != pResult->pwszExtendedErrorInfo)
|
|
{
|
|
hr2 = myAppendString(
|
|
pResult->pwszExtendedErrorInfo,
|
|
L" ",
|
|
ppwszDisposition);
|
|
_PrintIfError(hr2, "myAppendString");
|
|
}
|
|
|
|
if (NULL != *pprow)
|
|
{
|
|
hr2 = CoreSetRequestDispositionFields(
|
|
*pprow,
|
|
hr,
|
|
DB_DISP_ERROR,
|
|
*ppwszDisposition);
|
|
_PrintIfError(hr2, "CoreSetRequestDispositionFields");
|
|
|
|
CoreLogRequestStatus(
|
|
*pprow,
|
|
MSG_E_PROCESS_REQUEST_FAILED,
|
|
hr,
|
|
*ppwszDisposition);
|
|
}
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CoreProcessRequest(
|
|
IN DWORD dwFlags,
|
|
OPTIONAL IN WCHAR const *pwszUserName,
|
|
IN DWORD cbRequest,
|
|
OPTIONAL IN BYTE const *pbRequest,
|
|
OPTIONAL IN WCHAR const *pwszAttributes,
|
|
OPTIONAL IN WCHAR const *pwszSerialNumber,
|
|
IN DWORD dwComContextIndex,
|
|
IN DWORD dwRequestId,
|
|
OUT CERTSRV_RESULT_CONTEXT *pResult)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
WCHAR *pwszDisposition = NULL;
|
|
DWORD OpRequest;
|
|
ICertDBRow *prow = NULL;
|
|
DWORD ReqId;
|
|
LONG ExitEvent = EXITEVENT_INVALID;
|
|
BOOL fCoInitialized = FALSE;
|
|
CACTX *pCAContext;
|
|
BOOL fCommitted = FALSE;
|
|
|
|
CSASSERT(NULL != pResult->pdwRequestId);
|
|
CSASSERT(NULL != pResult->pdwDisposition);
|
|
|
|
if (MAXDWORD == dwRequestId)
|
|
{
|
|
dwRequestId = 0;
|
|
}
|
|
*pResult->pdwRequestId = dwRequestId;
|
|
*pResult->pdwDisposition = CR_DISP_ERROR;
|
|
|
|
OpRequest = CR_IN_RETRIEVE;
|
|
ReqId = 0;
|
|
hr = CoInitializeEx(NULL, GetCertsrvComThreadingModel());
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
_JumpError(hr, error, "CoInitializeEx");
|
|
}
|
|
fCoInitialized = TRUE;
|
|
|
|
hr = coreInitRequest(
|
|
dwFlags,
|
|
pwszUserName,
|
|
cbRequest,
|
|
pbRequest,
|
|
pwszAttributes,
|
|
pwszSerialNumber,
|
|
dwComContextIndex,
|
|
&OpRequest,
|
|
&prow,
|
|
&pwszDisposition,
|
|
pResult);
|
|
_PrintIfError(hr, "coreInitRequest");
|
|
|
|
pCAContext = NULL;
|
|
if (S_OK == hr)
|
|
{
|
|
CSASSERT(NULL == pwszDisposition); // error string only
|
|
if (CR_IN_NEW != OpRequest)
|
|
{
|
|
DWORD cb;
|
|
DWORD dw;
|
|
|
|
cb = sizeof(dw);
|
|
hr = prow->GetProperty(
|
|
g_wszPropRequestType,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
&cb,
|
|
(BYTE *) &dw);
|
|
if (S_OK == hr)
|
|
{
|
|
dwFlags |= (CR_IN_CRLS & dw);
|
|
}
|
|
}
|
|
hr = coreVerifyRequest(
|
|
&prow,
|
|
OpRequest,
|
|
0 != (CR_IN_CRLS & dwFlags),
|
|
pwszUserName,
|
|
dwComContextIndex,
|
|
&ReqId,
|
|
&ExitEvent,
|
|
&pwszDisposition,
|
|
&pCAContext,
|
|
pResult); // CoTaskMem
|
|
_PrintIfError(hr, "coreVerifyRequest");
|
|
}
|
|
else
|
|
{
|
|
WCHAR *pwszDisposition2 = CoreBuildDispositionString(
|
|
pwszDisposition,
|
|
NULL, // pwszUserName
|
|
NULL, // pwszDispositionDetail
|
|
NULL, // pwszDispositionDetail2
|
|
NULL, // pwszBy
|
|
hr,
|
|
FALSE);
|
|
if (NULL != pwszDisposition2)
|
|
{
|
|
if (NULL != pwszDisposition)
|
|
{
|
|
LocalFree(pwszDisposition);
|
|
}
|
|
pwszDisposition = pwszDisposition2;
|
|
}
|
|
}
|
|
|
|
if (NULL != pResult->pctbFullResponse)
|
|
{
|
|
BYTE const *pbCert = NULL;
|
|
DWORD cbCert = 0;
|
|
|
|
if (NULL != pResult->pctbCert && NULL != pResult->pctbCert->pb)
|
|
{
|
|
pbCert = pResult->pctbCert->pb;
|
|
cbCert = pResult->pctbCert->cb;
|
|
}
|
|
CSASSERT(NULL == pResult->pctbFullResponse->pb);
|
|
hr2 = PKCSEncodeFullResponse(
|
|
prow,
|
|
pResult,
|
|
hr,
|
|
pwszDisposition,
|
|
pCAContext,
|
|
pbCert, // pbCertLeaf
|
|
cbCert, // cbCertLeaf
|
|
0 != (CR_IN_CRLS & dwFlags),
|
|
&pResult->pctbFullResponse->pb, // CoTaskMem*
|
|
&pResult->pctbFullResponse->cb);
|
|
_PrintIfError(hr2, "PKCSEncodeFullResponse");
|
|
if (S_OK == hr &&
|
|
(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr2 || IsWhistler()))
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
|
|
if (!((CRCF_FAILDENIEDREQUEST & pResult->dwResultFlags) &&
|
|
(CRCF_PREVIOUSLYDENIED & pResult->dwResultFlags)))
|
|
{
|
|
hr2 = coreAuditRequestDisposition(
|
|
prow,
|
|
ReqId,
|
|
pwszUserName,
|
|
pwszAttributes,
|
|
*pResult->pdwDisposition);
|
|
_PrintIfError(hr2, "coreAuditRequestDisposition");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
|
|
if (NULL != pwszDisposition && NULL != pResult->pctbDispositionMessage)
|
|
{
|
|
DWORD cbAlloc = (wcslen(pwszDisposition) + 1) * sizeof(WCHAR);
|
|
BYTE *pbAlloc;
|
|
|
|
pbAlloc = (BYTE *) CoTaskMemAlloc(cbAlloc);
|
|
if (NULL != pbAlloc)
|
|
{
|
|
CopyMemory(pbAlloc, pwszDisposition, cbAlloc);
|
|
pResult->pctbDispositionMessage->pb = pbAlloc;
|
|
pResult->pctbDispositionMessage->cb = cbAlloc;
|
|
}
|
|
}
|
|
if (NULL != prow)
|
|
{
|
|
BOOL fSave;
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
hr2 = PropSetRequestTimeProperty(prow, g_wszPropRequestResolvedWhen);
|
|
_PrintIfError(hr2, "PropSetRequestTimeProperty");
|
|
}
|
|
|
|
fSave = FALSE;
|
|
switch (*pResult->pdwDisposition)
|
|
{
|
|
case CR_DISP_ISSUED:
|
|
case CR_DISP_ISSUED_OUT_OF_BAND:
|
|
case CR_DISP_UNDER_SUBMISSION:
|
|
fSave = TRUE;
|
|
break;
|
|
|
|
default:
|
|
if (KRAF_SAVEBADREQUESTKEY & g_KRAFlags)
|
|
{
|
|
fSave = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
if (fSave)
|
|
{
|
|
if (NULL != pResult->pbArchivedKey)
|
|
{
|
|
hr2 = prow->SetProperty(
|
|
g_wszPropRequestRawArchivedKey,
|
|
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
pResult->cbArchivedKey,
|
|
pResult->pbArchivedKey);
|
|
_PrintIfError(hr2, "SetProperty(ArchivedKey)");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
|
|
hr2 = prow->SetProperty(
|
|
g_wszPropRequestKeyRecoveryHashes,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
MAXDWORD,
|
|
(BYTE const *) pResult->pwszKRAHashes);
|
|
_PrintIfError(hr2, "SetProperty(KRAHashes)");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
else if (CR_IN_DENY == OpRequest || CR_IN_RESUBMIT == OpRequest)
|
|
{
|
|
BYTE b = 0;
|
|
|
|
hr2 = prow->SetProperty(
|
|
g_wszPropRequestRawArchivedKey,
|
|
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
0,
|
|
&b); // to avoid E_POINTER errors
|
|
_PrintIfError(hr2, "SetProperty(ArchivedKey)");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
|
|
hr2 = prow->SetProperty(
|
|
g_wszPropRequestKeyRecoveryHashes,
|
|
PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
0,
|
|
NULL);
|
|
_PrintIfError(hr2, "SetProperty(KRAHashes)");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
if (pResult->fRequestSavedWithoutKey &&
|
|
(KRAF_SAVEBADREQUESTKEY & g_KRAFlags))
|
|
{
|
|
fSave = FALSE;
|
|
switch (*pResult->pdwDisposition)
|
|
{
|
|
case CR_DISP_INCOMPLETE:
|
|
case CR_DISP_ERROR:
|
|
case CR_DISP_DENIED:
|
|
fSave = TRUE;
|
|
break;
|
|
|
|
default:
|
|
if (S_OK != hr)
|
|
{
|
|
fSave = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
if (fSave)
|
|
{
|
|
hr2 = prow->SetProperty(
|
|
g_wszPropRequestRawRequest,
|
|
PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
cbRequest,
|
|
pbRequest);
|
|
_PrintIfError(hr2, "SetProperty(request)");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr2 = prow->CommitTransaction(TRUE);
|
|
_PrintIfError(hr2, "CommitTransaction");
|
|
fCommitted = S_OK == hr2;
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
}
|
|
|
|
error:
|
|
// If the request exists, clean up the DB
|
|
|
|
if (NULL != prow)
|
|
{
|
|
if (S_OK != hr && !fCommitted)
|
|
{
|
|
hr2 = prow->CommitTransaction(FALSE);
|
|
_PrintIfError(hr2, "CommitTransaction");
|
|
}
|
|
prow->Release();
|
|
}
|
|
if (EXITEVENT_INVALID != ExitEvent)
|
|
{
|
|
CSASSERT(fCoInitialized);
|
|
ExitNotify(
|
|
ExitEvent,
|
|
ReqId,
|
|
CR_IN_NEW == OpRequest? pResult : NULL,
|
|
dwComContextIndex);
|
|
}
|
|
if (fCoInitialized)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
WCHAR const *pwszMsg;
|
|
|
|
pwszMsg = myGetErrorMessageText(hr, TRUE);
|
|
if (NULL != pwszMsg)
|
|
{
|
|
CONSOLEPRINT1((DBG_SS_CERTSRV, "%ws\n", pwszMsg));
|
|
LocalFree(const_cast<WCHAR *>(pwszMsg));
|
|
}
|
|
}
|
|
if (NULL != pwszDisposition)
|
|
{
|
|
LocalFree(pwszDisposition);
|
|
}
|
|
|
|
// Hide the failed HRESULT in the returned Disposition.
|
|
// This allows the encoded Full response and disposition message to be
|
|
// returned via DCOM or RPC. Returning S_OK != hr defeats this mechanism.
|
|
|
|
if (FAILED(hr) &&
|
|
(CR_DISP_ERROR == *pResult->pdwDisposition ||
|
|
CR_DISP_DENIED == *pResult->pdwDisposition))
|
|
{
|
|
*pResult->pdwDisposition = hr;
|
|
hr = S_OK;
|
|
}
|
|
{
|
|
#define wszFORMATREQUESTID L"RequestId=%u"
|
|
WCHAR wszRequestId[ARRAYSIZE(wszFORMATREQUESTID) + cwcDWORDSPRINTF];
|
|
|
|
hr2 = hr;
|
|
if (S_OK == hr2 && FAILED(*pResult->pdwDisposition))
|
|
{
|
|
hr2 = *pResult->pdwDisposition;
|
|
}
|
|
if (S_OK != hr2)
|
|
{
|
|
wsprintf(wszRequestId, wszFORMATREQUESTID, *pResult->pdwRequestId);
|
|
_PrintErrorStr(hr2, "CoreProcessRequest", wszRequestId);
|
|
}
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CoreValidateRequestId(
|
|
IN ICertDBRow *prow,
|
|
IN DWORD ExpectedDisposition)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cbProp;
|
|
DWORD Disposition;
|
|
|
|
cbProp = sizeof(Disposition);
|
|
hr = prow->GetProperty(
|
|
g_wszPropRequestDisposition,
|
|
PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
|
|
NULL,
|
|
&cbProp,
|
|
(BYTE *) &Disposition);
|
|
_PrintIfError(hr, "GetProperty");
|
|
if (S_OK != hr || sizeof(Disposition) != cbProp)
|
|
{
|
|
hr = CERTSRV_E_NO_REQUEST;
|
|
}
|
|
else if (Disposition != ExpectedDisposition)
|
|
{
|
|
hr = CERTSRV_E_BAD_REQUESTSTATUS;
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SetCAObjectFlags(
|
|
IN DWORD dwFlags)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCAINFO hCAInfo = NULL;
|
|
DWORD dwCAFlags;
|
|
|
|
hr = CAFindByName(
|
|
g_pwszSanitizedDSName,
|
|
NULL,
|
|
CA_FIND_LOCAL_SYSTEM | CA_FIND_INCLUDE_UNTRUSTED,
|
|
&hCAInfo);
|
|
_JumpIfError(hr, error, "CAFindByName");
|
|
|
|
hr = CAGetCAFlags(hCAInfo, &dwCAFlags);
|
|
_JumpIfError(hr, error, "CAGetCAFlags");
|
|
|
|
dwCAFlags |= dwFlags;
|
|
|
|
hr = CASetCAFlags(hCAInfo, dwCAFlags);
|
|
_JumpIfError(hr, error, "CASetCAFlags");
|
|
|
|
hr = CAUpdateCA(hCAInfo);
|
|
_JumpIfError(hr, error, "CAUpdateCA");
|
|
|
|
error:
|
|
if (NULL != hCAInfo)
|
|
{
|
|
CACloseCA(hCAInfo);
|
|
}
|
|
return(hr);
|
|
}
|