3691 lines
		
	
	
		
			94 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			3691 lines
		
	
	
		
			94 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //+--------------------------------------------------------------------------
 | |
| //
 | |
| // 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 "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
 | |
| 
 | |
| 
 | |
| 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_wszParentConfig[MAX_PATH];
 | |
| 
 | |
| WCHAR *g_pwszzSubjectTemplate = NULL;
 | |
| WCHAR *g_pwszServerName = NULL;
 | |
| 
 | |
| DWORD g_dwClockSkewMinutes = CCLOCKSKEWMINUTESDEFAULT;
 | |
| DWORD g_dwLogLevel = CERTLOG_WARNING;
 | |
| DWORD g_dwHighSerial = 0;
 | |
| DWORD g_cbMaxIncomingMessageSize = MAXINCOMINGMESSAGESIZEDEFAULT;
 | |
| 
 | |
| 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_wszRegLogLevel[] = wszREGLOGLEVEL;
 | |
| WCHAR const g_wszRegHighSerial[] = wszREGHIGHSERIAL;
 | |
| WCHAR const g_wszRegMaxIncomingMessageSize[] = wszREGMAXINCOMINGMESSAGESIZE;
 | |
| 
 | |
| 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_fcritsecDSCache = FALSE;
 | |
| BOOL g_fServerUpgraded = FALSE;
 | |
| CRITICAL_SECTION g_critsecDSCache;
 | |
| BOOL g_fLockICertRequest = FALSE;
 | |
| 
 | |
| //+--------------------------------------------------------------------------
 | |
| // 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_pwszRequestProcessingError;
 | |
| WCHAR const *g_pwszRequestParsingError;
 | |
| 
 | |
| 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;
 | |
| 
 | |
| 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_REQUESTPROCESSERROR,		&g_pwszRequestProcessingError },
 | |
|     { IDS_REQUESTPARSEERROR,		&g_pwszRequestParsingError },
 | |
|     { 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]},
 | |
| };
 | |
| 
 | |
| 
 | |
| typedef struct _DSCACHE
 | |
| {
 | |
|     _DSCACHE *pdscNext;
 | |
|     WCHAR    *pwszDomain;
 | |
|     LDAP     *pld;
 | |
| } DSCACHE;
 | |
| 
 | |
| DSCACHE *g_DSCache = NULL;
 | |
| HANDLE g_hDS = NULL;
 | |
| 
 | |
| 
 | |
| DWORD
 | |
| coreDSUnbindWorker(
 | |
|     OPTIONAL IN OUT VOID *pvparms)
 | |
| {
 | |
|     HANDLE hDS = (HANDLE) pvparms;
 | |
| 
 | |
|     DsUnBind(&hDS);
 | |
|     return(0);
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| coreDSUnBind(
 | |
|     IN BOOL fSynchronous)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     HANDLE hDS = g_hDS;
 | |
|     HANDLE hThread = NULL;
 | |
|     DWORD ThreadId;
 | |
| 
 | |
|     if (NULL != hDS)
 | |
|     {
 | |
| 	g_hDS = NULL;
 | |
| 	if (fSynchronous)
 | |
| 	{
 | |
| 	    coreDSUnbindWorker(hDS);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    hThread = CreateThread(
 | |
| 			    NULL,	// lpThreadAttributes (Security Attr)
 | |
| 			    0,		// dwStackSize
 | |
| 			    coreDSUnbindWorker,
 | |
| 			    hDS,	// lpParameter
 | |
| 			    0,          // dwCreationFlags
 | |
| 			    &ThreadId);
 | |
| 	    if (NULL == hThread)
 | |
| 	    {
 | |
| 		hr = myHLastError();
 | |
| 		_JumpError(hr, error, "CreateThread");
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     if (NULL != hThread)
 | |
|     {
 | |
|         CloseHandle(hThread);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| 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;
 | |
|     BOOL fRediscover = FALSE;
 | |
|     DS_NAME_RESULTW *pNameResults = NULL;
 | |
| 
 | |
|     CSASSERT(NULL != ppwszDN);
 | |
|     *ppwszDN = NULL;
 | |
| 
 | |
|     while (TRUE)
 | |
|     {
 | |
| 	if (fRediscover)
 | |
| 	{
 | |
| 	    coreDSUnBind(FALSE);
 | |
| 	}
 | |
| 	if (NULL == g_hDS)
 | |
| 	{
 | |
| 	    hr = DsBind(NULL, NULL, &g_hDS);
 | |
| 	    if (S_OK != hr)
 | |
| 	    {
 | |
| 		hr = myHError(hr);
 | |
| 		_JumpError(hr, error, "DsBind");
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	// Got a connection.  Crack the name:
 | |
| 
 | |
| 	hr = DsCrackNames(
 | |
| 		    g_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)
 | |
| 	{
 | |
| 	    hr = myHError(hr);
 | |
| 	    if (!fRediscover)
 | |
| 	    {
 | |
| 		_PrintError(hr, "DsCrackNames");
 | |
| 		fRediscover = TRUE;
 | |
| 		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);
 | |
| 	    if (!fRediscover)
 | |
| 	    {
 | |
| 		_PrintError(hr, "DsCrackNames result");
 | |
| 		fRediscover = TRUE;
 | |
| 		continue;
 | |
| 	    }
 | |
| 	    _JumpError(hr, error, "DsCrackNames result");
 | |
| 	}
 | |
| 	break;
 | |
|     }
 | |
|     hr = myDupString(pNameResults->rItems[0].pName, ppwszDN);
 | |
|     _JumpIfError(hr, error, "myDupString");
 | |
| 
 | |
| error:
 | |
|     if (NULL != pNameResults)
 | |
|     {
 | |
| 	DsFreeNameResult(pNameResults);
 | |
|     }
 | |
|     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);
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| CoreTerminate(VOID)
 | |
| {
 | |
|     VOID coreFreeDSCache();
 | |
| 
 | |
|     coreFreeDSCache();
 | |
|     DBShutDown(FALSE);
 | |
|     ComShutDown();
 | |
|     PKCSTerminate();
 | |
|     CRLTerminate();
 | |
|     if (NULL != g_pwszServerName)
 | |
|     {
 | |
| 	LocalFree(g_pwszServerName);
 | |
| 	g_pwszServerName = NULL;
 | |
|     }
 | |
|     if (NULL != g_pwszzSubjectTemplate)
 | |
|     {
 | |
| 	LocalFree(g_pwszzSubjectTemplate);
 | |
| 	g_pwszzSubjectTemplate = NULL;
 | |
|     }
 | |
|     if (NULL != g_pwszSanitizedDSName)
 | |
|     {
 | |
| 	LocalFree(g_pwszSanitizedDSName);
 | |
| 	g_pwszSanitizedDSName = 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;
 | |
|     }
 | |
|     if (g_fcritsecDSCache)
 | |
|     {
 | |
| 	DeleteCriticalSection(&g_critsecDSCache);
 | |
| 	g_fcritsecDSCache = FALSE;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| 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;
 | |
| 
 | |
|     while (TRUE)
 | |
|     {
 | |
|         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
 | |
| CoreInit(VOID)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     HKEY hkeyConfig = NULL;
 | |
|     HKEY hkeyCN = NULL;
 | |
|     BYTE abbuf[MAX_PATH * sizeof(TCHAR)];
 | |
|     WCHAR awcTemplate[MAX_PATH];
 | |
|     DWORD cbbuf;
 | |
|     DWORD cchbuf;
 | |
|     DWORD dwType;
 | |
|     WCHAR *pwsz;
 | |
|     DWORD dw;
 | |
|     BOOL fLogError = TRUE;
 | |
|     DWORD LogMsg = MSG_BAD_REGISTRY;
 | |
|     WCHAR const *pwszLog = NULL;
 | |
|     int i;
 | |
|     DWORD cbValue;
 | |
|     DWORD dwEnabled;
 | |
|     CAuditEvent AuditSettings;
 | |
|     
 | |
|     __try
 | |
|     {
 | |
| 	InitializeCriticalSection(&g_critsecDSCache);
 | |
| 	g_fcritsecDSCache = TRUE;
 | |
| 	hr = S_OK;
 | |
|     }
 | |
|     __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
 | |
|     {
 | |
|     }
 | |
|     _JumpIfError(hr, error, "InitializeCriticalSection");
 | |
| 
 | |
|     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;
 | |
|     }
 | |
|     
 | |
|     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));
 | |
|     
 | |
|     // 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, &dw);
 | |
|     _JumpIfError(hr, error, "GetSetupStatus");
 | |
|     
 | |
|     if (SETUP_SUSPEND_FLAG & dw)
 | |
|     {
 | |
|         LogMsg = MSG_E_INCOMPLETE_HIERARCHY;
 | |
|         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");
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     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");
 | |
|     
 | |
|     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_wszRegMaxIncomingMessageSize,
 | |
|         NULL,		// lpdwReserved
 | |
|         &dwType,
 | |
|         (BYTE *) &dw,
 | |
|         &cbValue);
 | |
|     if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
 | |
|     {
 | |
|         g_cbMaxIncomingMessageSize = 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 && REG_DWORD == dwType && sizeof(dw) == cbValue)
 | |
|     {
 | |
|         g_dwHighSerial = dw;
 | |
|     }
 | |
| 
 | |
|     cbValue = sizeof(dw);
 | |
|     hr = RegQueryValueEx(
 | |
|         hkeyCN,
 | |
|         wszLOCKICERTREQUEST,
 | |
|         NULL,		// lpdwReserved
 | |
|         &dwType,
 | |
|         (BYTE *) &dw,
 | |
|         &cbValue);
 | |
|     if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
 | |
|     {
 | |
|         g_fLockICertRequest = dw;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     hr = g_CASD.Initialize(g_wszSanitizedName);
 | |
|     _JumpIfError(hr, error, "CProtectedSecurityDescriptor::Initialize");
 | |
| 
 | |
|     g_CASD.ImportResourceStrings(g_pwszAuditResources);
 | |
| 
 | |
|     // Functionality available only on advanced server:
 | |
|     // - auditing
 | |
|     // - 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.LoadFilter(g_wszSanitizedName);
 | |
|         if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
 | |
|         {
 | |
|             _JumpIfError(hr, error, "CAuditEvent::LoadFilter");
 | |
|         }
 | |
| 
 | |
|         hr = AuditSettings.RoleSeparationFlagLoad(g_wszSanitizedName);
 | |
|         if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
 | |
|         {
 | |
|             _JumpIfError(hr, error, "CAuditEvent::RoleSeparationFlagLoad");
 | |
|         }
 | |
| 
 | |
|     }
 | |
|     g_dwAuditFilter = AuditSettings.GetFilter();
 | |
| 
 | |
|     
 | |
|     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");
 | |
|     
 | |
|     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 = 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 != hkeyCN)
 | |
|     {
 | |
|         RegCloseKey(hkeyCN);
 | |
|     }
 | |
|     if (NULL != hkeyConfig)
 | |
|     {
 | |
|         RegCloseKey(hkeyConfig);
 | |
|     }
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
|         CoreTerminate();
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| 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
 | |
| 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;
 | |
|     
 | |
|     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 awcAttributes[CCH_DBMAXTEXT_ATTRSTRING + 1];
 | |
|         
 | |
|         wcsncpy(awcAttributes, pwszAttributes, CCH_DBMAXTEXT_ATTRSTRING);
 | |
|         awcAttributes[CCH_DBMAXTEXT_ATTRSTRING] = L'\0';
 | |
|         if (wcslen(pwszAttributes) > CCH_DBMAXTEXT_ATTRSTRING)
 | |
|         {
 | |
|             DBGPRINT((
 | |
|                 DBG_SS_CERTSRV,
 | |
|                 "coreCreateRequest: truncating Attributes %u -> %u chars\n",
 | |
|                 wcslen(pwszAttributes),
 | |
|                 CCH_DBMAXTEXT_ATTRSTRING));
 | |
|         }
 | |
|         hr = prow->SetProperty(
 | |
|             g_wszPropRequestAttributes,
 | |
|             PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
 | |
|             MAXDWORD,
 | |
|             (BYTE const *) awcAttributes);
 | |
|         _JumpIfError(hr, error, "SetProperty(attrib)");
 | |
|     }
 | |
|     
 | |
|     hr = PropParseRequest(prow, dwFlags, cbRequest, pbRequest, pResult);
 | |
|     _JumpIfError(hr, error, "PropParseRequest");
 | |
| 
 | |
|     hr = PKCSParseAttributes(
 | |
| 			prow,
 | |
| 			pwszAttributes,
 | |
| 			FALSE,
 | |
| 			PROPTABLE_REQUEST,
 | |
| 			NULL);
 | |
|     _JumpIfError(hr, error, "PKCSParseAttributes");
 | |
| 
 | |
|     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,
 | |
| 		    &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:
 | |
|     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,
 | |
|         &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,
 | |
|         &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,
 | |
| 		&cbProp,
 | |
| 		(BYTE *) &Disposition);
 | |
|     _JumpIfError(hr, error, "GetProperty(disposition)");
 | |
| 
 | |
|     cbProp = sizeof(hrRequest);
 | |
|     hr = prow->GetProperty(
 | |
| 		    g_wszPropRequestStatusCode,
 | |
| 		    PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
 | |
| 		    &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,
 | |
| 			&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,
 | |
| 			    &fErrorLogged,
 | |
| 			    ppCAContext,
 | |
| 			    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;
 | |
|     DWORD cbProp;
 | |
|     WCHAR awcSubject[1024];
 | |
|     WCHAR const *pwszSubject;
 | |
|     WCHAR wszRequestId[11 + 1];
 | |
|     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 = SEC_E_CERT_UNKNOWN;	// unknown error
 | |
| 	}
 | |
| 	pwszMessageText = myGetErrorMessageText(ErrCode, TRUE);
 | |
| 	if (NULL == pwszMessageText)
 | |
| 	{
 | |
| 	    pwszMessageText = myHResultToStringRaw(awchr, ErrCode);
 | |
| 	}
 | |
| 	apwsz[cString++] = pwszMessageText;
 | |
|     }
 | |
|     
 | |
|     cbProp = sizeof(awcSubject);
 | |
|     hr = prow->GetProperty(
 | |
| 		    g_wszPropSubjectDistinguishedName,
 | |
| 		    PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
 | |
| 		    &cbProp,
 | |
| 		    (BYTE *) awcSubject);
 | |
|     if (CERTSRV_E_PROPERTY_EMPTY == hr)
 | |
|     {
 | |
|         cbProp = sizeof(awcSubject);
 | |
|         hr = prow->GetProperty(
 | |
| 			g_wszPropSubjectDistinguishedName,
 | |
| 			PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
 | |
| 			&cbProp,
 | |
| 			(BYTE *) awcSubject);
 | |
|     }
 | |
|     if (CERTSRV_E_PROPERTY_EMPTY == hr)
 | |
|     {
 | |
|         cbProp = sizeof(awcSubject);
 | |
|         hr = prow->GetProperty(
 | |
| 			g_wszPropRequesterName,
 | |
| 			PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
 | |
| 			&cbProp,
 | |
| 			(BYTE *) awcSubject);
 | |
|     }
 | |
|     pwszSubject = awcSubject;
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
|         _PrintError(hr, "GetProperty(DN/Requester)");
 | |
| 	pwszSubject = g_pwszUnknownSubject;
 | |
|     }
 | |
|     apwsz[cString++] = pwszSubject;
 | |
|     
 | |
|     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;
 | |
| 	
 | |
| 	while (TRUE)
 | |
| 	{
 | |
| 	    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)
 | |
| 	    {
 | |
| 	    }
 | |
| 	    if (S_OK == hr || fRetried || !IOBUNALIGNED(stdout))
 | |
| 	    {
 | |
| 		break;
 | |
| 	    }
 | |
| 	    ALIGNIOB(stdout);
 | |
| 	    fRetried = TRUE;
 | |
| 	}
 | |
|     }
 | |
|     if (NULL != pwszMessageText && awchr != pwszMessageText)
 | |
|     {
 | |
| 	LocalFree(const_cast<WCHAR *>(pwszMessageText));
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| WCHAR *
 | |
| CoreBuildDispositionString(
 | |
|     OPTIONAL IN WCHAR const *pwszDispositionBase,
 | |
|     OPTIONAL IN WCHAR const *pwszUserName,
 | |
|     OPTIONAL IN WCHAR const *pwszDispositionDetail,
 | |
|     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 != 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 != 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 WCHAR const *pwszSamName,
 | |
|     IN LDAP *pld,
 | |
|     IN WCHAR const *pwszDN,
 | |
|     OPTIONAL IN WCHAR const *pwszError,
 | |
|     IN HRESULT hrPublish)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     WCHAR const *apwsz[6];
 | |
|     WORD cpwsz;
 | |
|     WCHAR wszRequestId[11 + 1];
 | |
|     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 = MSG_E_CERT_PUBLICATION;
 | |
|     if (NULL != pwszHostName)
 | |
|     {
 | |
| 	LogMsg = 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 WCHAR const *pwszSamName,
 | |
|     IN CERT_CONTEXT const *pcc)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     LDAP *pld = NULL;
 | |
|     HCERTSTORE hStore = NULL;
 | |
|     DWORD dwDisposition;
 | |
|     WCHAR *pwszError = NULL;
 | |
| 
 | |
|     hr = myRobustLdapBind(&pld, FALSE);
 | |
|     _JumpIfError(hr, error, "myRobustLdapBind");
 | |
| 
 | |
|     hStore = CertOpenStore(
 | |
| 			CERT_STORE_PROV_SYSTEM_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,
 | |
| 			&dwDisposition,
 | |
| 			&pwszError);
 | |
|     _JumpIfError(hr, error, "myLdapPublishCertToDS");
 | |
| 
 | |
| error:
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	coreLogPublishError(
 | |
| 			RequestId,
 | |
| 			pwszSamName,
 | |
| 			pld,
 | |
| 			g_pwszKRAPublishURL,
 | |
| 			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 WCHAR const *pwszSamName,
 | |
|     IN CERT_CONTEXT const *pcc)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     HRESULT hr2;
 | |
|     LDAP *pld = NULL;
 | |
|     DWORD dwDisposition;
 | |
|     WCHAR *pwszError = NULL;
 | |
|     WCHAR const *pwszDN = g_pwszAIACrossCertPublishURL;
 | |
|     CAutoLPWSTR pwszSubjectHash;
 | |
|     CAutoLPWSTR pwszSubjectDN, pwszSubject;
 | |
|     LPCWSTR pcwszFormatDN = L"LDAP:///CN=%s%s";
 | |
|     DWORD dwFlags = LPC_CAOBJECT;
 | |
|     bool fPublishToSubject = false;
 | |
| 
 | |
|     hr = myRobustLdapBind(&pld, FALSE);
 | |
|     _JumpIfError(hr, error, "myRobustLdapBind");
 | |
| 
 | |
|     // Attempt to build the location based on subject name:
 | |
|     //  
 | |
|     //  LDAP:///CN=<subject DN hasn>,<AIA container DN>
 | |
|     //
 | |
|     // In case of errors, fall back to publishing to CA AIA object
 | |
| 
 | |
|     hr = CertNameToHashString(
 | |
|         &pcc->pCertInfo->Subject,
 | |
|         &pwszSubjectHash);
 | |
| 
 | |
|     if(S_OK==hr)
 | |
|     {
 | |
|         WCHAR *pchRelDN = wcschr(pwszDN, L',');
 | |
|         if(pchRelDN)
 | |
|         {
 | |
|             pwszSubjectDN = (LPWSTR)LocalAlloc(LMEM_FIXED, 
 | |
|                 (wcslen(pwszSubjectHash)+
 | |
|                  wcslen(pchRelDN)+
 | |
|                  wcslen(pcwszFormatDN))*sizeof(WCHAR));
 | |
|             if(pwszSubjectDN)
 | |
|             {
 | |
|                 wsprintf(pwszSubjectDN, pcwszFormatDN, 
 | |
|                     (LPCWSTR)pwszSubjectHash, pchRelDN);
 | |
|                 pwszDN = pwszSubjectDN;
 | |
| 
 | |
|                 // we'll publish to subject's DS object which might not exist
 | |
|                 dwFlags |= LPC_CREATEOBJECT;
 | |
| 
 | |
|                 fPublishToSubject = true;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     hr = myLdapPublishCertToDS(
 | |
| 			pld,
 | |
| 			pcc,
 | |
| 			pwszDN,
 | |
| 			wszDSCROSSCERTPAIRATTRIBUTE,
 | |
| 			dwFlags,
 | |
| 			&dwDisposition,
 | |
| 			&pwszError);
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	    _PrintErrorStr(hr, "myLdapPublishCertToDS", pwszDN);
 | |
| 	    if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr &&
 | |
| 	        IsRootCA(g_CAType))
 | |
| 	    {
 | |
| 	        hr = S_OK;
 | |
| 	    }
 | |
|     }
 | |
| 
 | |
|     _JumpIfErrorStr(hr, error, "myLdapPublishCertToDS", pwszDN);
 | |
| 
 | |
|     if(fPublishToSubject)
 | |
|     {
 | |
|         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);
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	coreLogPublishError(RequestId, pwszSamName, pld, pwszDN, pwszError, hr);
 | |
|     }
 | |
|     if (NULL != pwszError)
 | |
|     {
 | |
| 	LocalFree(pwszError);
 | |
|     }
 | |
|     if (NULL != pld)
 | |
|     {
 | |
| 	ldap_unbind(pld);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| coreFreeDSCacheEntry(
 | |
|     IN OUT DSCACHE *pdsc)
 | |
| {
 | |
|     if (NULL != pdsc->pld)
 | |
|     {
 | |
| 	ldap_unbind(pdsc->pld);
 | |
| 	pdsc->pld = NULL;
 | |
|     }
 | |
|     if (NULL != pdsc->pwszDomain)
 | |
|     {
 | |
| 	LocalFree(pdsc->pwszDomain);
 | |
| 	pdsc->pwszDomain = NULL;
 | |
|     }
 | |
|     LocalFree(pdsc);
 | |
| }
 | |
| 
 | |
| 
 | |
| VOID
 | |
| coreFreeDSCache()
 | |
| {
 | |
|     DSCACHE *pdsc;
 | |
| 
 | |
|     // only called during shutdown
 | |
| 
 | |
|     while (NULL != g_DSCache)
 | |
|     {
 | |
|        // remove from head of list
 | |
| 
 | |
|        pdsc = g_DSCache;
 | |
|        g_DSCache = pdsc->pdscNext;
 | |
| 
 | |
|        coreFreeDSCacheEntry(pdsc);
 | |
|     }
 | |
|     coreDSUnBind(TRUE);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| coreGetCachedDS(
 | |
|     IN WCHAR const *pwszSamName,
 | |
|     IN BOOL fRediscover,
 | |
|     OUT LDAP **ppld)
 | |
| {
 | |
|     HRESULT hr;
 | |
|     ULONG ldaperr;
 | |
|     DS_NAME_RESULTW *pNameResults = NULL;
 | |
|     WCHAR *pwszDomain = NULL;
 | |
|     DSCACHE *pdsc = NULL;
 | |
|     DSCACHE **ppdscPrev;
 | |
|     DSCACHE *pdscFree = NULL;
 | |
|     DWORD cwc;
 | |
|     WCHAR *pwsz;
 | |
| 
 | |
|     CSASSERT(NULL != ppld);
 | |
|     *ppld = NULL;
 | |
| 
 | |
|     // Copy domain out of the SamName
 | |
| 
 | |
|     pwsz = wcschr(pwszSamName, L'\\');
 | |
|     if (NULL != pwsz)
 | |
|     {
 | |
|         cwc = SAFE_SUBTRACT_POINTERS(pwsz, pwszSamName);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         cwc = wcslen(pwszSamName);
 | |
|     }
 | |
|     pwszDomain = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
 | |
|     if (NULL == pwszDomain)
 | |
|     {
 | |
| 	hr = E_OUTOFMEMORY;
 | |
| 	_JumpError(hr, error, "LocalAlloc");
 | |
|     }
 | |
|     CopyMemory(pwszDomain, pwszSamName, sizeof(WCHAR) * cwc);
 | |
|     pwszDomain[cwc] = L'\0';
 | |
| 
 | |
|     ppdscPrev = &g_DSCache;
 | |
|     for (pdsc = g_DSCache; NULL != pdsc; pdsc = pdsc->pdscNext)
 | |
|     {
 | |
| 	if (0 == lstrcmpi(pdsc->pwszDomain, pwszDomain))
 | |
| 	{
 | |
| 	    // should we toss the cached entry?
 | |
| 
 | |
| 	    if (fRediscover)
 | |
| 	    {
 | |
| 		// unhook from cache list & free the entry,
 | |
| 
 | |
| 		*ppdscPrev = pdsc->pdscNext;
 | |
| 		coreFreeDSCacheEntry(pdsc);
 | |
| 		pdsc = NULL;
 | |
| 	    }
 | |
| 	    break;
 | |
| 	}
 | |
| 	ppdscPrev = &pdsc->pdscNext;
 | |
|     }
 | |
| 
 | |
|     if (fRediscover)
 | |
|     {
 | |
| 	coreDSUnBind(FALSE);
 | |
|     }
 | |
|     if (NULL == pdsc)
 | |
|     {
 | |
| 	pdsc = (DSCACHE *) LocalAlloc(
 | |
| 				LMEM_FIXED | LMEM_ZEROINIT,
 | |
| 				sizeof(*pdsc));
 | |
| 	if (NULL == pdsc)
 | |
| 	{
 | |
| 	    hr = E_OUTOFMEMORY;
 | |
| 	    _JumpError(hr, error, "LocalAlloc");
 | |
| 	}
 | |
| 	pdscFree = pdsc;
 | |
| 
 | |
| 	pdsc->pwszDomain = pwszDomain;
 | |
| 	pwszDomain = NULL;
 | |
|     }
 | |
|     CSASSERT(NULL != pdsc->pwszDomain);
 | |
| 
 | |
|     // if we don't have an ldap handle yet, get a good one
 | |
| 
 | |
|     if (NULL == pdsc->pld)
 | |
|     {
 | |
| 	CSASSERT(pdsc == pdscFree);
 | |
| 
 | |
| 	hr = myRobustLdapBindEx(
 | |
|                         FALSE,			// fGC
 | |
|                         FALSE,			// fRediscover
 | |
|                         LDAP_VERSION2,		// uVersion
 | |
| 			pwszDomain,		// pwszDomainName
 | |
|                         &pdsc->pld,		// ppld
 | |
|                         NULL);			// ppwszForestDNSName
 | |
| 	_JumpIfError(hr, error, "Policy:myRobustLdapBindEx");
 | |
| 
 | |
| 	// link into list: we have all data necessary
 | |
| 
 | |
| 	pdsc->pdscNext = g_DSCache;
 | |
| 	g_DSCache = pdsc;
 | |
| 	pdscFree = NULL;
 | |
|     }
 | |
|     *ppld = pdsc->pld;
 | |
| 
 | |
| error:
 | |
|     if (NULL != pwszDomain)
 | |
|     {
 | |
|         LocalFree(pwszDomain);
 | |
|     }
 | |
|     if (NULL != pNameResults)
 | |
|     {
 | |
|         DsFreeNameResult(pNameResults);
 | |
|     }
 | |
|     if (NULL != pdscFree)
 | |
|     {
 | |
|        coreFreeDSCacheEntry(pdscFree);
 | |
|     }
 | |
|     return(hr);
 | |
| }
 | |
| 
 | |
| 
 | |
| HRESULT
 | |
| corePublishIssuedCertificate(
 | |
|     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 const *pwszUserName;
 | |
|     DWORD cbProp;
 | |
|     LDAP *pld = NULL;
 | |
|     WCHAR const *pwszDN;
 | |
|     DWORD dwDisposition;
 | |
|     BOOL fCritSecEntered = FALSE;
 | |
|     WCHAR *pwszError = NULL;
 | |
| 
 | |
|     hr = myAddDomainName(pwszSamName, &pwszSamNamePatched, &pwszUserName);
 | |
|     _JumpIfError(hr, error, "myAddDomainName");
 | |
| 
 | |
|     if (NULL != pwszSamNamePatched)
 | |
|     {
 | |
| 	pwszSamName = pwszSamNamePatched;
 | |
|     }
 | |
| 
 | |
|     EnterCriticalSection(&g_critsecDSCache);
 | |
|     fCritSecEntered = TRUE;
 | |
|     __try
 | |
|     {
 | |
| 	BOOL fRediscover = FALSE;
 | |
| 
 | |
| 	hr = coreGetComContextUserDNFromSamName(
 | |
| 			    FALSE,		// fDeleteUserDNOnly
 | |
| 			    pwszSamName,
 | |
| 			    0,			// Context
 | |
| 			    dwComContextIndex,
 | |
| 			    &pwszDN);
 | |
| 	_JumpIfError(hr, error, "coreGetComContextUserDNFromSamName");
 | |
| 
 | |
| 	while (TRUE)
 | |
| 	{
 | |
| 	    if (NULL != pwszError)
 | |
| 	    {
 | |
| 		LocalFree(pwszError);
 | |
| 		pwszError = NULL;
 | |
| 	    }
 | |
| 	    pld = NULL;
 | |
| 
 | |
| 	    hr = coreGetCachedDS(pwszSamName, fRediscover, &pld); 
 | |
| 	    if (S_OK != hr)
 | |
| 	    {
 | |
| 		_PrintErrorStr(
 | |
| 			    hr,
 | |
| 			    "coreGetCachedDS",
 | |
| 			    fRediscover? L"noncached" : L"cached");
 | |
| 		if (fRediscover)
 | |
| 		{
 | |
| 		    _leave;
 | |
| 		}
 | |
| 	    }
 | |
| 	    else
 | |
| 	    {
 | |
| 		hr = myLdapPublishCertToDS(
 | |
| 				    pld,
 | |
| 				    pcc,
 | |
| 				    pwszDN,
 | |
| 				    wszDSUSERCERTATTRIBUTE,
 | |
| 				    dwObjectType,	// LPC_*
 | |
| 				    &dwDisposition,
 | |
| 				    &pwszError);
 | |
| 		_PrintIfErrorStr(hr, "myLdapPublishCertToDS", pwszDN);
 | |
| 		if (fRediscover || S_OK == hr)
 | |
| 		{
 | |
| 		    break;
 | |
| 		}
 | |
| 		if (!myLdapRebindRequired(dwDisposition, pld))
 | |
| 		{
 | |
| 		    _LeaveError(hr, "myLdapPublishCertToDS");
 | |
| 		}
 | |
| 	    }
 | |
| 	    fRediscover = TRUE;
 | |
| 	}
 | |
|     }
 | |
|     __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
 | |
|     {
 | |
| 	_PrintError(hr, "Exception");
 | |
|     }
 | |
| 
 | |
| error:
 | |
|     if (S_OK != hr)
 | |
|     {
 | |
| 	coreLogPublishError(RequestId, pwszSamName, pld, pwszDN, pwszError, hr);
 | |
|     }
 | |
|     if (NULL != pwszError)
 | |
|     {
 | |
| 	LocalFree(pwszError);
 | |
|     }
 | |
|     if (NULL != pwszSamNamePatched)
 | |
|     {
 | |
| 	LocalFree(pwszSamNamePatched);
 | |
|     }
 | |
|     if (fCritSecEntered)
 | |
|     {
 | |
| 	LeaveCriticalSection(&g_critsecDSCache);
 | |
|     }
 | |
|     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,
 | |
| 		    &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,
 | |
| 		    &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, pwszSamName, pcc);
 | |
| 	    _PrintIfError(hr, "corePublishCrossCertificate");
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    hr = corePublishIssuedCertificate(
 | |
| 				    RequestId,
 | |
| 				    dwComContextIndex,
 | |
| 				    pwszSamName,
 | |
| 				    pcc,
 | |
| 				    (CT_FLAG_MACHINE_TYPE & GeneralFlags)?
 | |
| 					LPC_MACHINEOBJECT : LPC_USEROBJECT);
 | |
| 	    _PrintIfError(hr, "corePublishIssuedCertificate");
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (CT_FLAG_PUBLISH_TO_KRA_CONTAINER & EnrollmentFlags)
 | |
|     {
 | |
| 	HRESULT hr2;
 | |
| 	
 | |
| 	hr2 = corePublishKRACertificate(RequestId, pwszSamName, 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 HRESULT *phrPublish)
 | |
| {
 | |
|     HRESULT hr;
 | |
| 
 | |
|     *ppCAContext = 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,
 | |
| 			pfErrorLogged,
 | |
| 			ppCAContext,
 | |
| 			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 *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 = 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));
 | |
| 		}
 | |
| 	    }
 | |
|             _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,
 | |
| 				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,
 | |
| 			    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,
 | |
| 				&hrPublish);
 | |
| 		if (S_OK != hr)
 | |
| 		{
 | |
| 	            CSASSERT(FAILED(hr));
 | |
| 	            _PrintError(hr, "coreAcceptRequest");
 | |
| 	            pwszDispositionBase = g_pwszRequestProcessingError;
 | |
| 	            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,
 | |
| 				    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);
 | |
|     }
 | |
|     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);
 | |
|     _PrintIfErrorStr(hr, "PKCSGetProperty", pwszPropName);
 | |
|     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);
 | |
| }
 | |
| 
 | |
| #define LOGMSG_ATTACK_DELAY_SECONDS (CVT_MINUTES * 20)
 | |
| static FILETIME g_ftLogNextAttackMsg = {0};
 | |
| 
 | |
| HRESULT ValidateMessageSize(OPTIONAL LPCWSTR pwszUser, DWORD cbRequest)
 | |
| {
 | |
|     HRESULT hr = S_OK;
 | |
| 
 | |
|     if (cbRequest > g_cbMaxIncomingMessageSize)
 | |
|     {
 | |
|         hr = HRESULT_FROM_WIN32(ERROR_MESSAGE_EXCEEDS_MAX_SIZE);
 | |
| 
 | |
|         SYSTEMTIME stNow;
 | |
|         FILETIME ftNow;
 | |
|         GetSystemTime(&stNow);
 | |
| 
 | |
|         // if VERBOSE -or- it's time to log the next msg (Next < Now)
 | |
|         if ( (CERTLOG_VERBOSE <= g_dwLogLevel) ||
 | |
|              ( (SystemTimeToFileTime(&stNow, &ftNow)) && (0 > CompareFileTime(&g_ftLogNextAttackMsg, &ftNow)) )
 | |
|            )
 | |
|         {
 | |
|             // g_ftLogNextAttackMsg = ftNow + DELAY;
 | |
| 
 | |
|             ULARGE_INTEGER ui;
 | |
|             ui.LowPart = ftNow.dwLowDateTime;
 | |
|             ui.HighPart = ftNow.dwHighDateTime;
 | |
|             ui.QuadPart += ((LONGLONG)LOGMSG_ATTACK_DELAY_SECONDS) * CVT_BASE;
 | |
|             g_ftLogNextAttackMsg.dwLowDateTime = ui.LowPart;
 | |
|             g_ftLogNextAttackMsg.dwHighDateTime = ui.HighPart;
 | |
| 
 | |
|             // don't pass NULL
 | |
|             if (NULL == pwszUser)
 | |
|                pwszUser = L"?";
 | |
| 
 | |
|             LogEventStringHResult(EVENTLOG_ERROR_TYPE,
 | |
| 			    MSG_E_POSSIBLE_DENIAL_OF_SERVICE_ATTACK,
 | |
|                             pwszUser,
 | |
| 			    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 = ValidateMessageSize(pwszUserName, cbRequest);
 | |
|     _JumpIfError(hr, error, "ValidateMessageSize");
 | |
| 
 | |
|     // 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;
 | |
| 	WCHAR const *pwszDisp = g_pwszRequestParsingError;
 | |
| 	
 | |
| 	hr2 = myDupString(pwszDisp, ppwszDisposition);
 | |
| 	_PrintIfError(hr2, "myDupString");
 | |
| 
 | |
| 	if (NULL != *pprow)
 | |
| 	{
 | |
| 	    hr2 = CoreSetRequestDispositionFields(
 | |
| 					    *pprow,
 | |
| 					    hr,
 | |
| 					    DB_DISP_ERROR,
 | |
| 					    pwszDisp);
 | |
| 	    _PrintIfError(hr2, "CoreSetRequestDispositionFields");
 | |
| 	    
 | |
| 	    CoreLogRequestStatus(
 | |
| 			    *pprow,
 | |
| 			    MSG_E_PROCESS_REQUEST_FAILED,
 | |
| 			    hr,
 | |
| 			    pwszDisp);
 | |
| 	}
 | |
|     }
 | |
|     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;
 | |
|     
 | |
|     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,
 | |
| 			&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,	// 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;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     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)
 | |
|     {
 | |
| 	if (pResult->fKeyArchived && (KRAF_SAVEBADREQUESTKEY & g_KRAFlags))
 | |
| 	{
 | |
| 	    BOOL 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, 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;
 | |
|     }
 | |
|     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,
 | |
|         &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_wszSanitizedName,
 | |
| 		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);
 | |
| }
 |