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);
|
|
}
|