Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4850 lines
121 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: core.cpp
  7. //
  8. // Contents: Cert Server Core implementation
  9. //
  10. // History: 25-Jul-96 vich created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include <pch.cpp>
  14. #pragma hdrstop
  15. #include <stdio.h>
  16. #include <winldap.h>
  17. #include <ntdsapi.h>
  18. #include <dsgetdc.h>
  19. #include <lm.h>
  20. #include <esent.h>
  21. #include "cscom.h"
  22. #include "csprop.h"
  23. #include "cspolicy.h"
  24. #include "ciinit.h"
  25. #include "csdisp.h"
  26. #include "csldap.h"
  27. #include "cainfop.h"
  28. #include "elog.h"
  29. #include "certlog.h"
  30. #include "resource.h"
  31. #define __dwFILE__ __dwFILE_CERTSRV_CORE_CPP__
  32. #if DBG_COMTEST
  33. #define DBG_COMTEST_CONST
  34. #else
  35. #define DBG_COMTEST_CONST const
  36. #endif
  37. #define DBSESSIONCOUNTMIN 4
  38. #define DBSESSIONCOUNTMAX 1024
  39. DBG_COMTEST_CONST BOOL fComTest = FALSE;
  40. SERVERCALLBACKS ServerCallBacks = {
  41. PropCIGetProperty,
  42. PropCISetProperty,
  43. PropCIGetExtension,
  44. PropCISetExtension,
  45. PropCIEnumSetup,
  46. PropCIEnumNext,
  47. PropCIEnumClose,
  48. };
  49. HINSTANCE g_hInstance;
  50. WCHAR g_wszSharedFolder[MAX_PATH];
  51. WCHAR g_wszSanitizedName[MAX_PATH];
  52. WCHAR *g_pwszSanitizedDSName;
  53. WCHAR g_wszCommonName[MAX_PATH];
  54. WCHAR g_wszPolicyDCName[MAX_PATH];
  55. DWORD g_cwcPolicyDCName = ARRAYSIZE(g_wszPolicyDCName);
  56. WCHAR g_wszParentConfig[MAX_PATH];
  57. WCHAR *g_pwszzAlternatePublishDomains = NULL;
  58. WCHAR *g_pwszzSubjectTemplate = NULL;
  59. WCHAR *g_pwszServerName = NULL;
  60. DWORD g_dwClockSkewMinutes = CCLOCKSKEWMINUTESDEFAULT;
  61. DWORD g_dwViewAgeMinutes = CVIEWAGEMINUTESDEFAULT;
  62. DWORD g_dwViewIdleMinutes = CVIEWIDLEMINUTESDEFAULT;
  63. DWORD g_dwLogLevel = CERTLOG_WARNING;
  64. DWORD g_dwSessionCount = DBSESSIONCOUNTDEFAULT;
  65. DWORD g_dwHighSerial = 0;
  66. BYTE *g_pbHighSerial = NULL;
  67. DWORD g_cbHighSerial;
  68. DWORD g_cbMaxIncomingMessageSize = MAXINCOMINGMESSAGESIZEDEFAULT;
  69. DWORD g_cbMaxIncomingAllocSize = MAXINCOMINGALLOCSIZEDEFAULT;
  70. WCHAR const g_wszRegValidityPeriodString[] = wszREGVALIDITYPERIODSTRING;
  71. WCHAR const g_wszRegValidityPeriodCount[] = wszREGVALIDITYPERIODCOUNT;
  72. WCHAR const g_wszRegCAXchgValidityPeriodString[] = wszREGCAXCHGVALIDITYPERIODSTRING;
  73. WCHAR const g_wszRegCAXchgValidityPeriodCount[] = wszREGCAXCHGVALIDITYPERIODCOUNT;
  74. WCHAR const g_wszRegCAXchgOverlapPeriodString[] = wszREGCAXCHGOVERLAPPERIODSTRING;
  75. WCHAR const g_wszRegCAXchgOverlapPeriodCount[] = wszREGCAXCHGOVERLAPPERIODCOUNT;
  76. WCHAR const g_wszRegCAXchgCertHash[] = wszREGCAXCHGCERTHASH;
  77. WCHAR const g_wszRegSubjectTemplate[] = wszREGSUBJECTTEMPLATE;
  78. WCHAR const g_wszRegKeyConfigPath[] = wszREGKEYCONFIGPATH;
  79. WCHAR const g_wszRegDirectory[] = wszREGDIRECTORY;
  80. WCHAR const g_wszRegActive[] = wszREGACTIVE;
  81. WCHAR const g_wszRegEnabled[] = wszREGENABLED;
  82. WCHAR const g_wszRegPolicyFlags[] = wszREGPOLICYFLAGS;
  83. WCHAR const g_wszCertSrvServiceName[] = wszSERVICE_NAME;
  84. WCHAR const g_wszRegCertEnrollCompatible[] = wszREGCERTENROLLCOMPATIBLE;
  85. WCHAR const g_wszRegEnforceX500NameLengths[] = wszREGENFORCEX500NAMELENGTHS;
  86. WCHAR const g_wszRegForceTeletex[] = wszREGFORCETELETEX;
  87. WCHAR const g_wszRegClockSkewMinutes[] = wszREGCLOCKSKEWMINUTES;
  88. WCHAR const g_wszRegViewAgeMinutes[] = wszREGVIEWAGEMINUTES;
  89. WCHAR const g_wszRegViewIdleMinutes[] = wszREGVIEWIDLEMINUTES;
  90. WCHAR const g_wszRegLogLevel[] = wszREGLOGLEVEL;
  91. WCHAR const g_wszRegHighSerial[] = wszREGHIGHSERIAL;
  92. WCHAR const g_wszRegMaxIncomingMessageSize[] = wszREGMAXINCOMINGMESSAGESIZE;
  93. WCHAR const g_wszRegMaxIncomingAllocSize[] = wszREGMAXINCOMINGALLOCSIZE;
  94. BOOL g_fCertEnrollCompatible = TRUE;
  95. BOOL g_fEnforceRDNNameLengths = TRUE;
  96. DWORD g_KRAFlags = 0;
  97. DWORD g_CRLEditFlags = EDITF_ENABLEAKIKEYID |
  98. EDITF_ENABLEAKIISSUERNAME |
  99. EDITF_ENABLEAKIISSUERSERIAL |
  100. EDITF_ENABLEAKICRITICAL;
  101. ENUM_FORCETELETEX g_fForceTeletex = ENUM_TELETEX_AUTO;
  102. ENUM_CATYPES g_CAType = ENUM_UNKNOWN_CA;
  103. BOOL g_fUseDS = FALSE;
  104. BOOL g_fServerUpgraded = FALSE;
  105. DWORD g_InterfaceFlags = IF_DEFAULT;
  106. HRESULT g_hrJetVersionStoreOutOfMemory;
  107. //+--------------------------------------------------------------------------
  108. // Name properties:
  109. WCHAR const g_wszPropDistinguishedName[] = wszPROPDISTINGUISHEDNAME;
  110. WCHAR const g_wszPropRawName[] = wszPROPRAWNAME;
  111. WCHAR const g_wszPropCountry[] = wszPROPCOUNTRY;
  112. WCHAR const g_wszPropOrganization[] = wszPROPORGANIZATION;
  113. WCHAR const g_wszPropOrgUnit[] = wszPROPORGUNIT;
  114. WCHAR const g_wszPropCommonName[] = wszPROPCOMMONNAME;
  115. WCHAR const g_wszPropLocality[] = wszPROPLOCALITY;
  116. WCHAR const g_wszPropState[] = wszPROPSTATE;
  117. WCHAR const g_wszPropTitle[] = wszPROPTITLE;
  118. WCHAR const g_wszPropGivenName[] = wszPROPGIVENNAME;
  119. WCHAR const g_wszPropInitials[] = wszPROPINITIALS;
  120. WCHAR const g_wszPropSurName[] = wszPROPSURNAME;
  121. WCHAR const g_wszPropDomainComponent[] = wszPROPDOMAINCOMPONENT;
  122. WCHAR const g_wszPropEMail[] = wszPROPEMAIL;
  123. WCHAR const g_wszPropStreetAddress[] = wszPROPSTREETADDRESS;
  124. WCHAR const g_wszPropUnstructuredAddress[] = wszPROPUNSTRUCTUREDADDRESS;
  125. WCHAR const g_wszPropUnstructuredName[] = wszPROPUNSTRUCTUREDNAME;
  126. WCHAR const g_wszPropDeviceSerialNumber[] = wszPROPDEVICESERIALNUMBER;
  127. //+--------------------------------------------------------------------------
  128. // Subject Name properties:
  129. WCHAR const g_wszPropSubjectDot[] = wszPROPSUBJECTDOT;
  130. WCHAR const g_wszPropSubjectDistinguishedName[] = wszPROPSUBJECTDISTINGUISHEDNAME;
  131. WCHAR const g_wszPropSubjectRawName[] = wszPROPSUBJECTRAWNAME;
  132. WCHAR const g_wszPropSubjectCountry[] = wszPROPSUBJECTCOUNTRY;
  133. WCHAR const g_wszPropSubjectOrganization[] = wszPROPSUBJECTORGANIZATION;
  134. WCHAR const g_wszPropSubjectOrgUnit[] = wszPROPSUBJECTORGUNIT;
  135. WCHAR const g_wszPropSubjectCommonName[] = wszPROPSUBJECTCOMMONNAME;
  136. WCHAR const g_wszPropSubjectLocality[] = wszPROPSUBJECTLOCALITY;
  137. WCHAR const g_wszPropSubjectState[] = wszPROPSUBJECTSTATE;
  138. WCHAR const g_wszPropSubjectTitle[] = wszPROPSUBJECTTITLE;
  139. WCHAR const g_wszPropSubjectGivenName[] = wszPROPSUBJECTGIVENNAME;
  140. WCHAR const g_wszPropSubjectInitials[] = wszPROPSUBJECTINITIALS;
  141. WCHAR const g_wszPropSubjectSurName[] = wszPROPSUBJECTSURNAME;
  142. WCHAR const g_wszPropSubjectDomainComponent[] = wszPROPSUBJECTDOMAINCOMPONENT;
  143. WCHAR const g_wszPropSubjectEMail[] = wszPROPSUBJECTEMAIL;
  144. WCHAR const g_wszPropSubjectStreetAddress[] = wszPROPSUBJECTSTREETADDRESS;
  145. WCHAR const g_wszPropSubjectUnstructuredAddress[] = wszPROPSUBJECTUNSTRUCTUREDADDRESS;
  146. WCHAR const g_wszPropSubjectUnstructuredName[] = wszPROPSUBJECTUNSTRUCTUREDNAME;
  147. WCHAR const g_wszPropSubjectDeviceSerialNumber[] = wszPROPSUBJECTDEVICESERIALNUMBER;
  148. //+--------------------------------------------------------------------------
  149. // Issuer Name properties:
  150. WCHAR const g_wszPropIssuerDot[] = wszPROPISSUERDOT;
  151. WCHAR const g_wszPropIssuerDistinguishedName[] = wszPROPISSUERDISTINGUISHEDNAME;
  152. WCHAR const g_wszPropIssuerRawName[] = wszPROPISSUERRAWNAME;
  153. WCHAR const g_wszPropIssuerCountry[] = wszPROPISSUERCOUNTRY;
  154. WCHAR const g_wszPropIssuerOrganization[] = wszPROPISSUERORGANIZATION;
  155. WCHAR const g_wszPropIssuerOrgUnit[] = wszPROPISSUERORGUNIT;
  156. WCHAR const g_wszPropIssuerCommonName[] = wszPROPISSUERCOMMONNAME;
  157. WCHAR const g_wszPropIssuerLocality[] = wszPROPISSUERLOCALITY;
  158. WCHAR const g_wszPropIssuerState[] = wszPROPISSUERSTATE;
  159. WCHAR const g_wszPropIssuerTitle[] = wszPROPISSUERTITLE;
  160. WCHAR const g_wszPropIssuerGivenName[] = wszPROPISSUERGIVENNAME;
  161. WCHAR const g_wszPropIssuerInitials[] = wszPROPISSUERINITIALS;
  162. WCHAR const g_wszPropIssuerSurName[] = wszPROPISSUERSURNAME;
  163. WCHAR const g_wszPropIssuerDomainComponent[] = wszPROPISSUERDOMAINCOMPONENT;
  164. WCHAR const g_wszPropIssuerEMail[] = wszPROPISSUEREMAIL;
  165. WCHAR const g_wszPropIssuerStreetAddress[] = wszPROPISSUERSTREETADDRESS;
  166. WCHAR const g_wszPropIssuerUnstructuredAddress[] = wszPROPISSUERUNSTRUCTUREDADDRESS;
  167. WCHAR const g_wszPropIssuerUnstructuredName[] = wszPROPISSUERUNSTRUCTUREDNAME;
  168. WCHAR const g_wszPropIssuerDeviceSerialNumber[] = wszPROPISSUERDEVICESERIALNUMBER;
  169. //+--------------------------------------------------------------------------
  170. // Request properties:
  171. WCHAR const g_wszPropRequestRequestID[] = wszPROPREQUESTREQUESTID;
  172. WCHAR const g_wszPropRequestRawRequest[] = wszPROPREQUESTRAWREQUEST;
  173. WCHAR const g_wszPropRequestRawArchivedKey[] = wszPROPREQUESTRAWARCHIVEDKEY;
  174. WCHAR const g_wszPropRequestKeyRecoveryHashes[] = wszPROPREQUESTKEYRECOVERYHASHES;
  175. WCHAR const g_wszPropRequestRawOldCertificate[] = wszPROPREQUESTRAWOLDCERTIFICATE;
  176. WCHAR const g_wszPropRequestAttributes[] = wszPROPREQUESTATTRIBUTES;
  177. WCHAR const g_wszPropRequestType[] = wszPROPREQUESTTYPE;
  178. WCHAR const g_wszPropRequestFlags[] = wszPROPREQUESTFLAGS;
  179. WCHAR const g_wszPropRequestStatusCode[] = wszPROPREQUESTSTATUSCODE;
  180. WCHAR const g_wszPropRequestDisposition[] = wszPROPREQUESTDISPOSITION;
  181. WCHAR const g_wszPropRequestDispositionMessage[] = wszPROPREQUESTDISPOSITIONMESSAGE;
  182. WCHAR const g_wszPropRequestSubmittedWhen[] = wszPROPREQUESTSUBMITTEDWHEN;
  183. WCHAR const g_wszPropRequestResolvedWhen[] = wszPROPREQUESTRESOLVEDWHEN;
  184. WCHAR const g_wszPropRequestRevokedWhen[] = wszPROPREQUESTREVOKEDWHEN;
  185. WCHAR const g_wszPropRequestRevokedEffectiveWhen[] = wszPROPREQUESTREVOKEDEFFECTIVEWHEN;
  186. WCHAR const g_wszPropRequestRevokedReason[] = wszPROPREQUESTREVOKEDREASON;
  187. WCHAR const g_wszPropRequesterName[] = wszPROPREQUESTERNAME;
  188. WCHAR const g_wszPropCallerName[] = wszPROPCALLERNAME;
  189. WCHAR const g_wszPropRequestOSVersion[] = wszPROPREQUESTOSVERSION;
  190. WCHAR const g_wszPropRequestCSPProvider[] = wszPROPREQUESTCSPPROVIDER;
  191. //+--------------------------------------------------------------------------
  192. // Request attribute properties:
  193. WCHAR const g_wszPropChallenge[] = wszPROPCHALLENGE;
  194. WCHAR const g_wszPropExpectedChallenge[] = wszPROPEXPECTEDCHALLENGE;
  195. //+--------------------------------------------------------------------------
  196. // Certificate properties:
  197. WCHAR const g_wszPropCertificateRequestID[] = wszPROPCERTIFICATEREQUESTID;
  198. WCHAR const g_wszPropRawCertificate[] = wszPROPRAWCERTIFICATE;
  199. WCHAR const g_wszPropCertificateHash[] = wszPROPCERTIFICATEHASH;
  200. WCHAR const g_wszPropCertificateSerialNumber[] = wszPROPCERTIFICATESERIALNUMBER;
  201. WCHAR const g_wszPropCertificateIssuerNameID[] = wszPROPCERTIFICATEISSUERNAMEID;
  202. WCHAR const g_wszPropCertificateNotBeforeDate[] = wszPROPCERTIFICATENOTBEFOREDATE;
  203. WCHAR const g_wszPropCertificateNotAfterDate[] = wszPROPCERTIFICATENOTAFTERDATE;
  204. WCHAR const g_wszPropCertificateSubjectKeyIdentifier[] = wszPROPCERTIFICATESUBJECTKEYIDENTIFIER;
  205. WCHAR const g_wszPropCertificateRawPublicKey[] = wszPROPCERTIFICATERAWPUBLICKEY;
  206. WCHAR const g_wszPropCertificatePublicKeyLength[] = wszPROPCERTIFICATEPUBLICKEYLENGTH;
  207. WCHAR const g_wszPropCertificatePublicKeyAlgorithm[] = wszPROPCERTIFICATEPUBLICKEYALGORITHM;
  208. WCHAR const g_wszPropCertificateRawPublicKeyAlgorithmParameters[] = wszPROPCERTIFICATERAWPUBLICKEYALGORITHMPARAMETERS;
  209. // Strings loaded from the resource file:
  210. WCHAR const *g_pwszRequestedBy;
  211. WCHAR const *g_pwszDeniedBy;
  212. WCHAR const *g_pwszPublishedBy;
  213. WCHAR const *g_pwszPolicyDeniedRequest;
  214. WCHAR const *g_pwszIssued;
  215. WCHAR const *g_pwszUnderSubmission;
  216. WCHAR const *g_pwszCertConstructionError;
  217. WCHAR const *g_pwszRequestParsingError;
  218. WCHAR const *g_pwszRequestSigError;
  219. WCHAR const *g_pwszKeyArchivalError;
  220. WCHAR const *g_pwszArchiveSigningKeyError;
  221. WCHAR const *g_pwszRevokedBy;
  222. WCHAR const *g_pwszUnrevokedBy;
  223. WCHAR const *g_pwszResubmittedBy;
  224. WCHAR const *g_pwszPrintfCertRequestDisposition;
  225. WCHAR const *g_pwszUnknownSubject;
  226. WCHAR const *g_pwszIntermediateCAStore;
  227. WCHAR const *g_pwszPublishError;
  228. WCHAR const *g_pwszYes;
  229. WCHAR const *g_pwszNo;
  230. WCHAR const *g_pwszInvalidIssuancePolicies;
  231. WCHAR const *g_pwszInvalidApplicationPolicies;
  232. LPWSTR g_wszzSecuredAttributes = NULL;
  233. LPCWSTR g_wszzSecuredAttributesDefault = wszzDEFAULTSIGNEDATTRIBUTES;
  234. typedef struct _STRINGINITMAP
  235. {
  236. int idResource;
  237. WCHAR const **ppwszResource;
  238. } STRINGINITMAP;
  239. STRINGINITMAP g_aStringInitStrings[] = {
  240. { IDS_REVOKEDBY, &g_pwszRevokedBy },
  241. { IDS_UNREVOKEDBY, &g_pwszUnrevokedBy },
  242. { IDS_RESUBMITTEDBY, &g_pwszResubmittedBy },
  243. { IDS_REQUESTEDBY, &g_pwszRequestedBy },
  244. { IDS_DENIEDBY, &g_pwszDeniedBy },
  245. { IDS_PUBLISHEDBY, &g_pwszPublishedBy },
  246. { IDS_POLICYDENIED, &g_pwszPolicyDeniedRequest },
  247. { IDS_ISSUED, &g_pwszIssued },
  248. { IDS_CERTCONSTRUCTIONERROR, &g_pwszCertConstructionError },
  249. { IDS_REQUESTPARSEERROR, &g_pwszRequestParsingError },
  250. { IDS_REQUESTSIGERROR, &g_pwszRequestSigError },
  251. { IDS_KEYARCHIVALERROR, &g_pwszKeyArchivalError },
  252. { IDS_ARCHIVESIGNINGKEYERROR, &g_pwszArchiveSigningKeyError },
  253. { IDS_UNDERSUBMISSION, &g_pwszUnderSubmission },
  254. { IDS_PRINTFCERTREQUESTDISPOSITION, &g_pwszPrintfCertRequestDisposition },
  255. { IDS_UNKNOWNSUBJECT, &g_pwszUnknownSubject },
  256. { IDS_INTERMEDIATECASTORE, &g_pwszIntermediateCAStore },
  257. { IDS_PUBLISHERROR, &g_pwszPublishError },
  258. { IDS_YES, &g_pwszYes },
  259. { IDS_NO, &g_pwszNo },
  260. { IDS_ALLOW, &g_pwszAuditResources[0] },
  261. { IDS_DENY, &g_pwszAuditResources[1] },
  262. { IDS_CAADMIN, &g_pwszAuditResources[2] },
  263. { IDS_OFFICER, &g_pwszAuditResources[3] },
  264. { IDS_READ, &g_pwszAuditResources[4] },
  265. { IDS_ENROLL, &g_pwszAuditResources[5] },
  266. { IDS_INVALIDISSUANCEPOLICIES, &g_pwszInvalidIssuancePolicies },
  267. { IDS_INVALIDAPPLICATIONPOLICIES, &g_pwszInvalidApplicationPolicies },
  268. };
  269. HANDLE *g_rgDSCache = NULL;
  270. DWORD g_cDSCacheCur;
  271. BOOL g_fcritsecDSCache = FALSE;
  272. CRITICAL_SECTION g_critsecDSCache;
  273. // Check if retriever is requester or subject of the cert being retrieved
  274. HRESULT coreCheckRetrieveAccessRight(
  275. ICertDBRow *prow,
  276. IN WCHAR const *pcwszUserName)
  277. {
  278. HRESULT hr;
  279. WCHAR *pwszRequesterName = NULL;
  280. WCHAR *pwszCallerName = NULL;
  281. hr = PKCSGetProperty(
  282. prow,
  283. g_wszPropRequesterName,
  284. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  285. NULL,
  286. (BYTE **) &pwszRequesterName);
  287. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  288. {
  289. _JumpIfError(hr, error, "PKCSGetProperty RequesterName");
  290. }
  291. if (S_OK != hr ||
  292. NULL == pwszRequesterName ||
  293. 0 != mylstrcmpiL(pcwszUserName, pwszRequesterName))
  294. {
  295. hr = PKCSGetProperty(
  296. prow,
  297. g_wszPropCallerName,
  298. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  299. NULL,
  300. (BYTE **) &pwszCallerName);
  301. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  302. {
  303. _JumpIfError(hr, error, "PKCSGetProperty CallerName");
  304. }
  305. if (S_OK != hr ||
  306. NULL == pwszCallerName ||
  307. 0 != mylstrcmpiL(pcwszUserName, pwszCallerName))
  308. {
  309. CAuditEvent audit(0, g_dwAuditFilter);
  310. hr = audit.AccessCheck(
  311. CA_ACCESS_ALLREADROLES,
  312. audit.m_gcNoAuditSuccess | audit.m_gcNoAuditFailure);
  313. _JumpIfError(hr, error, "CAuditEvent::AccessCheck");
  314. }
  315. }
  316. hr = S_OK;
  317. error:
  318. LOCAL_FREE(pwszRequesterName);
  319. LOCAL_FREE(pwszCallerName);
  320. return hr;
  321. }
  322. HRESULT
  323. coreDSInitCache()
  324. {
  325. HRESULT hr;
  326. hr = S_OK;
  327. __try
  328. {
  329. InitializeCriticalSection(&g_critsecDSCache);
  330. g_fcritsecDSCache = TRUE;
  331. }
  332. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  333. {
  334. }
  335. _JumpIfError(hr, error, "InitializeCriticalSection");
  336. g_rgDSCache = (HANDLE *) LocalAlloc(
  337. LMEM_FIXED | LMEM_ZEROINIT,
  338. g_dwSessionCount * sizeof(g_rgDSCache[0]));
  339. if (NULL == g_rgDSCache)
  340. {
  341. hr = E_OUTOFMEMORY;
  342. _JumpError(hr, error, "LocalAlloc");
  343. }
  344. g_cDSCacheCur = 0;
  345. hr = S_OK;
  346. error:
  347. return(hr);
  348. }
  349. HRESULT
  350. coreDSGetHandle(
  351. OUT HANDLE *phDS,
  352. OUT BOOL *pfCached)
  353. {
  354. HRESULT hr;
  355. HANDLE hDS;
  356. *phDS = NULL;
  357. *pfCached = TRUE;
  358. hDS = NULL;
  359. EnterCriticalSection(&g_critsecDSCache);
  360. if (0 != g_cDSCacheCur)
  361. {
  362. hDS = g_rgDSCache[--g_cDSCacheCur];
  363. }
  364. LeaveCriticalSection(&g_critsecDSCache);
  365. if (NULL == hDS)
  366. {
  367. *pfCached = FALSE;
  368. hr = DsBind(NULL, NULL, &hDS);
  369. if (S_OK != hr)
  370. {
  371. hr = myHError(hr);
  372. _JumpError(hr, error, "DsBind");
  373. }
  374. }
  375. *phDS = hDS;
  376. hr = S_OK;
  377. error:
  378. return(hr);
  379. }
  380. DWORD
  381. coreDSUnbindWorker(
  382. OPTIONAL IN OUT VOID *pvparms)
  383. {
  384. HANDLE hDS = (HANDLE) pvparms;
  385. DsUnBind(&hDS);
  386. return(0);
  387. }
  388. VOID
  389. coreDSUnbind(
  390. IN HANDLE hDS,
  391. IN BOOL fSynchronous)
  392. {
  393. HRESULT hr;
  394. HANDLE hThread = NULL;
  395. DWORD ThreadId;
  396. if (NULL != hDS)
  397. {
  398. if (!fSynchronous)
  399. {
  400. hThread = CreateThread(
  401. NULL, // lpThreadAttributes (Security Attr)
  402. 0, // dwStackSize
  403. coreDSUnbindWorker,
  404. hDS, // lpParameter
  405. 0, // dwCreationFlags
  406. &ThreadId);
  407. if (NULL == hThread)
  408. {
  409. hr = myHLastError();
  410. _PrintError(hr, "CreateThread");
  411. }
  412. }
  413. if (NULL == hThread)
  414. {
  415. coreDSUnbindWorker(hDS);
  416. }
  417. }
  418. //error:
  419. if (NULL != hThread)
  420. {
  421. CloseHandle(hThread);
  422. }
  423. }
  424. VOID
  425. coreDSEmptyCache(
  426. IN BOOL fSynchronous)
  427. {
  428. EnterCriticalSection(&g_critsecDSCache);
  429. while (0 != g_cDSCacheCur)
  430. {
  431. coreDSUnbind(g_rgDSCache[--g_cDSCacheCur], fSynchronous);
  432. }
  433. LeaveCriticalSection(&g_critsecDSCache);
  434. }
  435. VOID
  436. coreDSReleaseHandle(
  437. IN HANDLE hDS)
  438. {
  439. // only cache g_dwSessionCount DS handles. They're all equivalent,
  440. // so if the one being released won't fit in the array, toss it.
  441. EnterCriticalSection(&g_critsecDSCache);
  442. CSASSERT(0 != g_dwSessionCount);
  443. if (g_cDSCacheCur < g_dwSessionCount)
  444. {
  445. g_rgDSCache[g_cDSCacheCur++] = hDS;
  446. hDS = NULL;
  447. }
  448. LeaveCriticalSection(&g_critsecDSCache);
  449. if (NULL != hDS)
  450. {
  451. coreDSUnbind(hDS, TRUE);
  452. }
  453. }
  454. typedef struct _LDAPCACHE
  455. {
  456. _LDAPCACHE *plcNext;
  457. WCHAR *pwszDomainDns;
  458. LDAP *pld;
  459. } LDAPCACHE;
  460. typedef struct _FORESTLDAPCACHE
  461. {
  462. LDAPCACHE *plc;
  463. DWORD clc;
  464. WCHAR *pwszDomainDns;
  465. BOOL fcritsec;
  466. CRITICAL_SECTION critsec;
  467. } FORESTLDAPCACHE;
  468. FORESTLDAPCACHE *g_rgForestLdapCache = NULL;
  469. DWORD g_cForestLdapCache = 0;
  470. HRESULT
  471. coreLdapInitCache()
  472. {
  473. HRESULT hr;
  474. WCHAR *pwsz;
  475. FORESTLDAPCACHE *pflcEnd;
  476. FORESTLDAPCACHE *pflc;
  477. g_cForestLdapCache = 1; // local Forest
  478. if (NULL != g_pwszzAlternatePublishDomains)
  479. {
  480. for (
  481. pwsz = g_pwszzAlternatePublishDomains;
  482. L'\0' != *pwsz;
  483. pwsz += wcslen(pwsz) + 1)
  484. {
  485. g_cForestLdapCache++;
  486. }
  487. }
  488. g_rgForestLdapCache = (FORESTLDAPCACHE *) LocalAlloc(
  489. LMEM_FIXED | LMEM_ZEROINIT,
  490. g_cForestLdapCache * sizeof(g_rgForestLdapCache[0]));
  491. if (NULL == g_rgForestLdapCache)
  492. {
  493. hr = E_OUTOFMEMORY;
  494. _JumpError(hr, error, "LocalAlloc");
  495. }
  496. pwsz = g_pwszzAlternatePublishDomains;
  497. pflcEnd = &g_rgForestLdapCache[g_cForestLdapCache];
  498. for (pflc = g_rgForestLdapCache; pflc < pflcEnd; pflc++)
  499. {
  500. if (pflc > g_rgForestLdapCache)
  501. {
  502. pflc->pwszDomainDns = pwsz;
  503. pwsz += wcslen(pwsz) + 1;
  504. }
  505. hr = S_OK;
  506. __try
  507. {
  508. InitializeCriticalSection(&pflc->critsec);
  509. pflc->fcritsec = TRUE;
  510. }
  511. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  512. {
  513. }
  514. _JumpIfError(hr, error, "InitializeCriticalSection");
  515. }
  516. hr = S_OK;
  517. error:
  518. return(hr);
  519. }
  520. VOID
  521. coreLdapUnbind(
  522. IN OUT LDAPCACHE *plc)
  523. {
  524. if (NULL != plc->pld)
  525. {
  526. ldap_unbind(plc->pld);
  527. plc->pld = NULL;
  528. }
  529. if (NULL != plc->pwszDomainDns)
  530. {
  531. LocalFree(plc->pwszDomainDns);
  532. plc->pwszDomainDns = NULL;
  533. }
  534. LocalFree(plc);
  535. }
  536. VOID
  537. coreLdapFreeCache()
  538. {
  539. if (NULL != g_rgForestLdapCache)
  540. {
  541. FORESTLDAPCACHE *pflcEnd = &g_rgForestLdapCache[g_cForestLdapCache];
  542. FORESTLDAPCACHE *pflc;
  543. for (pflc = g_rgForestLdapCache; pflc < pflcEnd; pflc++)
  544. {
  545. if (pflc->fcritsec)
  546. {
  547. LDAPCACHE *plc;
  548. EnterCriticalSection(&pflc->critsec);
  549. while (NULL != pflc->plc)
  550. {
  551. plc = pflc->plc;
  552. pflc->plc = plc->plcNext;
  553. plc->plcNext = NULL;
  554. coreLdapUnbind(plc);
  555. }
  556. LeaveCriticalSection(&pflc->critsec);
  557. DeleteCriticalSection(&pflc->critsec);
  558. pflc->fcritsec = FALSE;
  559. }
  560. }
  561. LocalFree(g_rgForestLdapCache);
  562. g_rgForestLdapCache = NULL;
  563. }
  564. }
  565. HRESULT
  566. coreLdapGetCachedHandle(
  567. IN DWORD iForest,
  568. OPTIONAL IN WCHAR const *pwszDomainDns,
  569. OUT WCHAR const **ppwszDomainDns,
  570. OUT LDAPCACHE **pplc)
  571. {
  572. HRESULT hr;
  573. FORESTLDAPCACHE *pflc = NULL;
  574. BOOL fCritSecEntered = FALSE;
  575. LDAPCACHE *plc;
  576. LDAPCACHE **pplcPrev;
  577. *ppwszDomainDns = NULL;
  578. *pplc = NULL;
  579. if (NULL == g_rgForestLdapCache || iForest >= g_cForestLdapCache)
  580. {
  581. hr = E_INVALIDARG;
  582. _JumpError(hr, error, "g_rgForestLdapCache");
  583. }
  584. pflc = &g_rgForestLdapCache[iForest];
  585. *ppwszDomainDns = pflc->pwszDomainDns;
  586. EnterCriticalSection(&pflc->critsec);
  587. fCritSecEntered = TRUE;
  588. pplcPrev = &pflc->plc;
  589. for (plc = pflc->plc; ; plc = plc->plcNext)
  590. {
  591. if (NULL == plc)
  592. {
  593. hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  594. _JumpError2(hr, error, "pflc->plc", hr);
  595. }
  596. if (NULL == pwszDomainDns ||
  597. 0 == mylstrcmpiL(plc->pwszDomainDns, pwszDomainDns))
  598. {
  599. break;
  600. }
  601. pplcPrev = &plc->plcNext;
  602. }
  603. *pplcPrev = plc->plcNext;
  604. plc->plcNext = NULL;
  605. *pplc = plc;
  606. CSASSERT(0 < pflc->clc);
  607. pflc->clc--;
  608. hr = S_OK;
  609. error:
  610. if (NULL != pflc && fCritSecEntered)
  611. {
  612. LeaveCriticalSection(&pflc->critsec);
  613. }
  614. return(hr);
  615. }
  616. HRESULT
  617. coreLdapBindHandle(
  618. IN WCHAR const *pwszDomainDns,
  619. OUT LDAPCACHE **pplc)
  620. {
  621. HRESULT hr;
  622. LDAPCACHE *plc = NULL;
  623. plc = (LDAPCACHE *) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(*plc));
  624. if (NULL == plc)
  625. {
  626. hr = E_OUTOFMEMORY;
  627. _JumpError(hr, error, "LocalAlloc");
  628. }
  629. CSASSERT(NULL != pwszDomainDns);
  630. hr = myDupString(pwszDomainDns, &plc->pwszDomainDns);
  631. _JumpIfError(hr, error, "myDupString");
  632. hr = myRobustLdapBindEx(
  633. 0, // dwFlags1
  634. RLBF_REQUIRE_SECURE_LDAP, // dwFlags2
  635. LDAP_VERSION2, // uVersion
  636. pwszDomainDns, // pwszDomainName
  637. &plc->pld, // ppld
  638. NULL); // ppwszForestDNSName
  639. _JumpIfError(hr, error, "myRobustLdapBindEx");
  640. *pplc = plc;
  641. plc = NULL;
  642. hr = S_OK;
  643. error:
  644. if (NULL != plc)
  645. {
  646. coreLdapUnbind(plc);
  647. }
  648. return(hr);
  649. }
  650. HRESULT
  651. coreLdapGetHandle(
  652. IN DWORD iForest,
  653. OPTIONAL IN WCHAR const *pwszDomainDns, // NULL for 0 < iForest
  654. OUT LDAPCACHE **pplc,
  655. OUT BOOL *pfCached)
  656. {
  657. HRESULT hr;
  658. WCHAR const *pwszForestDomainDns;
  659. CSASSERT(NULL != pplc);
  660. *pplc = NULL;
  661. *pfCached = TRUE;
  662. hr = coreLdapGetCachedHandle(
  663. iForest,
  664. pwszDomainDns,
  665. &pwszForestDomainDns,
  666. pplc);
  667. if (S_OK != hr)
  668. {
  669. _PrintError(hr, "coreGetLdapCache");
  670. *pfCached = FALSE;
  671. if (NULL == pwszDomainDns)
  672. {
  673. CSASSERT(0 < iForest);
  674. if (NULL == pwszForestDomainDns)
  675. {
  676. hr = E_UNEXPECTED;
  677. _JumpError(hr, error, "pwszForestDomainDns NULL");
  678. }
  679. pwszDomainDns = pwszForestDomainDns;
  680. }
  681. hr = coreLdapBindHandle(pwszDomainDns, pplc);
  682. _JumpIfError(hr, error, "coreBindLdapHandle");
  683. }
  684. hr = S_OK;
  685. error:
  686. return(hr);
  687. }
  688. VOID
  689. coreLdapReleaseHandle(
  690. IN DWORD iForest,
  691. IN LDAPCACHE *plc)
  692. {
  693. if (NULL != g_rgForestLdapCache && iForest < g_cForestLdapCache)
  694. {
  695. FORESTLDAPCACHE *pflc = &g_rgForestLdapCache[iForest];
  696. if (pflc->fcritsec)
  697. {
  698. EnterCriticalSection(&pflc->critsec);
  699. plc->plcNext = pflc->plc;
  700. pflc->plc = plc;
  701. pflc->clc++;
  702. LeaveCriticalSection(&pflc->critsec);
  703. plc = NULL;
  704. }
  705. }
  706. if (NULL != plc)
  707. {
  708. coreLdapUnbind(plc);
  709. }
  710. }
  711. HRESULT
  712. myAddDomainName(
  713. IN WCHAR const *pwszSamName,
  714. OUT WCHAR **ppwszSamName, // *ppwszSamName is NULL if unchanged
  715. OUT WCHAR const **ppwszUserName)
  716. {
  717. HRESULT hr;
  718. WCHAR const *pwszUserName;
  719. WCHAR wszDomain[MAX_PATH];
  720. *ppwszSamName = NULL;
  721. *ppwszUserName = NULL;
  722. if (L'\0' == *pwszSamName)
  723. {
  724. hr = E_ACCESSDENIED; // can't have a zero length name
  725. _JumpError(hr, error, "zero length name");
  726. }
  727. // See if it includes a domain name.
  728. pwszUserName = wcschr(pwszSamName, L'\\');
  729. if (NULL == pwszUserName)
  730. {
  731. DWORD cwc = ARRAYSIZE(wszDomain);
  732. WCHAR *pwsz;
  733. // There was no domain portion, so assume part of the current domain.
  734. if (GetUserNameEx(NameSamCompatible, wszDomain, &cwc))
  735. {
  736. // Fix NULL termination bug
  737. if (0 != cwc)
  738. {
  739. cwc--;
  740. }
  741. wszDomain[cwc] = L'\0';
  742. pwsz = wcschr(wszDomain, L'\\');
  743. if (NULL != pwsz)
  744. {
  745. pwsz++;
  746. wcsncpy(pwsz, pwszSamName, ARRAYSIZE(wszDomain) - cwc);
  747. hr = myDupString(wszDomain, ppwszSamName);
  748. _JumpIfError(hr, error, "myDupString");
  749. pwszSamName = *ppwszSamName;
  750. }
  751. }
  752. }
  753. pwszUserName = wcschr(pwszSamName, L'\\');
  754. if (NULL == pwszUserName)
  755. {
  756. pwszUserName = pwszSamName;
  757. }
  758. else
  759. {
  760. pwszUserName++;
  761. }
  762. *ppwszUserName = pwszUserName;
  763. hr = S_OK;
  764. error:
  765. return(hr);
  766. }
  767. HRESULT
  768. coreGetDNFromSamName(
  769. IN WCHAR const *pwszSamName,
  770. OUT WCHAR **ppwszDN)
  771. {
  772. HRESULT hr;
  773. HANDLE hDS = NULL;
  774. DS_NAME_RESULT *pNameResults = NULL;
  775. CSASSERT(NULL != ppwszDN);
  776. *ppwszDN = NULL;
  777. for (;;)
  778. {
  779. BOOL fCached;
  780. if (NULL != hDS)
  781. {
  782. coreDSUnbind(hDS, FALSE);
  783. hDS = NULL;
  784. coreDSEmptyCache(FALSE);
  785. }
  786. hr = coreDSGetHandle(&hDS, &fCached);
  787. _JumpIfError(hr, error, "coreGetDSHandle");
  788. // Got a connection. Crack the name:
  789. hr = DsCrackNames(
  790. hDS,
  791. DS_NAME_NO_FLAGS,
  792. DS_NT4_ACCOUNT_NAME,
  793. DS_FQDN_1779_NAME,
  794. 1, // one name
  795. &pwszSamName, // one name (IN)
  796. &pNameResults); // OUT
  797. if (S_OK != hr)
  798. {
  799. // It's probably not worth flushing the DS cache only when certain
  800. // errors are detected.
  801. hr = myHError(hr);
  802. if (fCached)
  803. {
  804. _PrintError(hr, "DsCrackNames");
  805. continue;
  806. }
  807. _JumpError(hr, error, "DsCrackNames");
  808. }
  809. if (1 > pNameResults->cItems ||
  810. DS_NAME_NO_ERROR != pNameResults->rItems[0].status)
  811. {
  812. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  813. _JumpError(hr, error, "DsCrackNames result");
  814. }
  815. break;
  816. }
  817. hr = myDupString(pNameResults->rItems[0].pName, ppwszDN);
  818. _JumpIfError(hr, error, "myDupString");
  819. error:
  820. if (NULL != pNameResults)
  821. {
  822. DsFreeNameResult(pNameResults);
  823. }
  824. if (NULL != hDS)
  825. {
  826. coreDSReleaseHandle(hDS);
  827. }
  828. return(hr);
  829. }
  830. HRESULT
  831. coreGetComContextUserDNFromSamName(
  832. IN BOOL fDeleteUserDNOnly,
  833. OPTIONAL IN WCHAR const *pwszSamName,
  834. IN LONG Context,
  835. IN DWORD dwComContextIndex,
  836. OPTIONAL OUT WCHAR const **ppwszDN) // do NOT free!
  837. {
  838. HRESULT hr;
  839. CERTSRV_COM_CONTEXT *pComContext;
  840. hr = ComGetClientInfo(Context, dwComContextIndex, &pComContext);
  841. _JumpIfError(hr, error, "ComGetClientInfo");
  842. if (fDeleteUserDNOnly)
  843. {
  844. if (NULL != pComContext->pwszUserDN)
  845. {
  846. LocalFree(pComContext->pwszUserDN);
  847. pComContext->pwszUserDN = NULL;
  848. }
  849. }
  850. else
  851. {
  852. if (NULL == pComContext->pwszUserDN)
  853. {
  854. hr = coreGetDNFromSamName(pwszSamName, &pComContext->pwszUserDN);
  855. _JumpIfError(hr, error, "coreGetDNFromSamName");
  856. }
  857. }
  858. if (NULL != ppwszDN)
  859. {
  860. *ppwszDN = pComContext->pwszUserDN;
  861. }
  862. hr = S_OK;
  863. error:
  864. return(hr);
  865. }
  866. HRESULT
  867. CoreSetComContextUserDN(
  868. IN DWORD dwRequestId,
  869. IN LONG Context,
  870. IN DWORD dwComContextIndex,
  871. OPTIONAL OUT WCHAR const **ppwszDN) // do NOT free!
  872. {
  873. HRESULT hr;
  874. ICertDBRow *prow = NULL;
  875. WCHAR *pwszSamName = NULL;
  876. WCHAR *pwszSamNamePatched = NULL;
  877. WCHAR const *pwszUserName;
  878. hr = g_pCertDB->OpenRow(
  879. PROPOPEN_READONLY | PROPTABLE_REQCERT,
  880. dwRequestId,
  881. NULL,
  882. &prow);
  883. _JumpIfError(hr, error, "OpenRow");
  884. hr = PKCSGetProperty(
  885. prow,
  886. g_wszPropRequesterName,
  887. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  888. NULL,
  889. (BYTE **) &pwszSamName);
  890. _JumpIfError(hr, error, "PKCSGetProperty");
  891. hr = myAddDomainName(pwszSamName, &pwszSamNamePatched, &pwszUserName);
  892. _JumpIfError(hr, error, "myAddDomainName");
  893. hr = coreGetComContextUserDNFromSamName(
  894. FALSE, // fDeleteUserDNOnly
  895. NULL != pwszSamNamePatched? pwszSamNamePatched : pwszSamName,
  896. Context,
  897. dwComContextIndex,
  898. ppwszDN);
  899. _JumpIfError(hr, error, "coreGetComContextUserDNFromSamName");
  900. error:
  901. if (NULL != pwszSamName)
  902. {
  903. LocalFree(pwszSamName);
  904. }
  905. if (NULL != pwszSamNamePatched)
  906. {
  907. LocalFree(pwszSamNamePatched);
  908. }
  909. if (NULL != prow)
  910. {
  911. prow->Release();
  912. }
  913. return(hr);
  914. }
  915. HRESULT
  916. CoreSetArchivedKey(
  917. IN OUT CERTSRV_COM_CONTEXT *pComContext)
  918. {
  919. HRESULT hr;
  920. ICertDBRow *prow = NULL;
  921. DWORD cb;
  922. CSASSERT(0 ==
  923. ((CCCF_KEYARCHIVEDSET | CCCF_KEYARCHIVED) & pComContext->dwFlags));
  924. hr = g_pCertDB->OpenRow(
  925. PROPOPEN_READONLY | PROPTABLE_REQCERT,
  926. pComContext->RequestId,
  927. NULL,
  928. &prow);
  929. _JumpIfError(hr, error, "OpenRow");
  930. cb = 0;
  931. hr = prow->GetProperty(
  932. g_wszPropRequestRawArchivedKey,
  933. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  934. NULL,
  935. &cb,
  936. NULL);
  937. if (CERTSRV_E_PROPERTY_EMPTY != hr)
  938. {
  939. _JumpIfError(hr, error, "PKCSGetProperty");
  940. if (0 < cb)
  941. {
  942. pComContext->dwFlags |= CCCF_KEYARCHIVED;
  943. }
  944. }
  945. pComContext->dwFlags |= CCCF_KEYARCHIVEDSET;
  946. hr = S_OK;
  947. error:
  948. if (NULL != prow)
  949. {
  950. prow->Release();
  951. }
  952. return(hr);
  953. }
  954. DWORD g_PolicyFlags;
  955. HRESULT
  956. CoreSetDisposition(
  957. IN ICertDBRow *prow,
  958. IN DWORD Disposition)
  959. {
  960. HRESULT hr;
  961. hr = prow->SetProperty(
  962. g_wszPropRequestDisposition,
  963. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  964. sizeof(Disposition),
  965. (BYTE const *) &Disposition);
  966. _JumpIfError(hr, error, "SetProperty(disposition)");
  967. error:
  968. return(hr);
  969. }
  970. DWORD
  971. coreRegGetTimePeriod(
  972. IN HKEY hkeyCN,
  973. IN WCHAR const *pwszRegPeriodCount,
  974. IN WCHAR const *pwszRegPeriodString,
  975. OUT enum ENUM_PERIOD *penumPeriod,
  976. OUT LONG *plCount)
  977. {
  978. HRESULT hr;
  979. LONG lCount;
  980. DWORD dwType;
  981. DWORD cbValue;
  982. cbValue = sizeof(lCount);
  983. hr = RegQueryValueEx(
  984. hkeyCN,
  985. pwszRegPeriodCount,
  986. NULL, // lpdwReserved
  987. &dwType,
  988. (BYTE *) &lCount,
  989. &cbValue);
  990. if (S_OK == hr && REG_DWORD == dwType && sizeof(lCount) == cbValue)
  991. {
  992. WCHAR awcPeriod[10];
  993. cbValue = sizeof(awcPeriod);
  994. hr = RegQueryValueEx(
  995. hkeyCN,
  996. pwszRegPeriodString,
  997. NULL, // lpdwReserved
  998. &dwType,
  999. (BYTE *) awcPeriod,
  1000. &cbValue);
  1001. if (S_OK != hr)
  1002. {
  1003. hr = myHError(hr);
  1004. if (HRESULT_FROM_WIN32(ERROR_MORE_DATA) == hr)
  1005. {
  1006. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1007. }
  1008. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1009. {
  1010. hr = S_OK;
  1011. }
  1012. _JumpIfError(hr, error, "RegQueryValueEx");
  1013. }
  1014. else
  1015. {
  1016. if (REG_SZ != dwType || sizeof(awcPeriod) <= cbValue)
  1017. {
  1018. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1019. _JumpIfErrorStr(hr, error, "time period string", pwszRegPeriodString);
  1020. }
  1021. hr = myTranslatePeriodUnits(
  1022. awcPeriod,
  1023. lCount,
  1024. penumPeriod,
  1025. plCount);
  1026. _JumpIfError(hr, error, "myTranslatePeriodUnits");
  1027. }
  1028. }
  1029. error:
  1030. return(hr);
  1031. }
  1032. // Converts a REG_SZ Subject template into a double null terminated REG_MULTI_SZ type string
  1033. DWORD
  1034. coreConvertSubjectTemplate(
  1035. OUT WCHAR* pwszz,
  1036. IN WCHAR* pwszTemplate,
  1037. IN DWORD cwc)
  1038. {
  1039. HRESULT hr;
  1040. WCHAR *pwszToken;
  1041. WCHAR *pwszRemain = pwszTemplate;
  1042. WCHAR *pwszzNew = pwszz;
  1043. DWORD cwszzNew = 0;
  1044. BOOL fSplit;
  1045. for (;;)
  1046. {
  1047. pwszToken = PKCSSplitToken(&pwszRemain, wszNAMESEPARATORDEFAULT, &fSplit);
  1048. if (NULL == pwszToken)
  1049. {
  1050. *pwszzNew = L'\0';
  1051. break;
  1052. }
  1053. cwszzNew += (1 + wcslen(pwszToken)) * sizeof(WCHAR);
  1054. if (cwszzNew > cwc)
  1055. {
  1056. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  1057. _JumpError(hr, error, "overflow");
  1058. }
  1059. wcscpy(pwszzNew, pwszToken);
  1060. pwszzNew = wcschr(pwszzNew, L'\0');
  1061. pwszzNew++;
  1062. }
  1063. hr = S_OK;
  1064. error:
  1065. return(hr);
  1066. }
  1067. HRESULT
  1068. coreReadRegStringValue(
  1069. IN HKEY hkey,
  1070. IN WCHAR const *pwszName,
  1071. OUT WCHAR **ppwszzValue)
  1072. {
  1073. HRESULT hr;
  1074. DWORD cb;
  1075. DWORD cwc;
  1076. DWORD dwType;
  1077. WCHAR *pwszzValue = NULL;
  1078. *ppwszzValue = NULL;
  1079. cb = 0;
  1080. cwc = 0;
  1081. for (;;)
  1082. {
  1083. hr = RegQueryValueEx(
  1084. hkey,
  1085. pwszName,
  1086. NULL, // lpdwReserved
  1087. &dwType,
  1088. (BYTE *) pwszzValue,
  1089. &cb);
  1090. if (S_OK != hr)
  1091. {
  1092. hr = myHError(hr);
  1093. _JumpErrorStr(hr, error, "RegQueryValueEx", pwszName);
  1094. }
  1095. if (NULL != pwszzValue)
  1096. {
  1097. pwszzValue[cwc] = L'\0';
  1098. pwszzValue[cwc + 1] = L'\0';
  1099. break;
  1100. }
  1101. if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
  1102. {
  1103. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1104. _JumpError(hr, error, "RegQueryValueEx: value type");
  1105. }
  1106. cwc = (cb + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
  1107. pwszzValue = (WCHAR *) LocalAlloc(
  1108. LMEM_FIXED,
  1109. (cwc + 2) * sizeof(WCHAR));
  1110. if (NULL == pwszzValue)
  1111. {
  1112. hr = E_OUTOFMEMORY;
  1113. _JumpError(hr, error, "LocalAlloc");
  1114. }
  1115. }
  1116. *ppwszzValue = pwszzValue;
  1117. pwszzValue = NULL;
  1118. hr = S_OK;
  1119. error:
  1120. if (NULL != pwszzValue)
  1121. {
  1122. LocalFree(pwszzValue);
  1123. }
  1124. return(hr);
  1125. }
  1126. HRESULT
  1127. CoreInit(
  1128. IN BOOL fAuditEnabled)
  1129. {
  1130. HRESULT hr;
  1131. HKEY hkeyConfig = NULL;
  1132. HKEY hkeyCN = NULL;
  1133. BYTE abbuf[MAX_PATH * sizeof(TCHAR)];
  1134. WCHAR awcTemplate[MAX_PATH];
  1135. DWORD cbbuf;
  1136. DWORD dwType;
  1137. WCHAR *pwsz;
  1138. DWORD dw, dwCASetupStatus;
  1139. BOOL fLogError = TRUE;
  1140. DWORD LogMsg = MSG_BAD_REGISTRY;
  1141. WCHAR const *pwszLog = NULL;
  1142. WCHAR *pwszHighSerial = NULL;
  1143. int i;
  1144. DWORD cbValue;
  1145. DWORD dwEnabled;
  1146. CAuditEvent AuditSettings;
  1147. WCHAR *pwszFullRequestFileName = NULL;
  1148. hr = myGetMachineDnsName(&g_pwszServerName);
  1149. _JumpIfError(hr, error, "myGetMachineDnsName");
  1150. for (i = 0; i < ARRAYSIZE(g_aStringInitStrings); i++)
  1151. {
  1152. WCHAR const *pwszT;
  1153. pwszT = myLoadResourceString(g_aStringInitStrings[i].idResource);
  1154. if (NULL == pwszT)
  1155. {
  1156. hr = myHLastError();
  1157. _JumpError(hr, error, "myLoadResourceString");
  1158. }
  1159. *g_aStringInitStrings[i].ppwszResource = pwszT;
  1160. }
  1161. g_hrJetVersionStoreOutOfMemory = myJetHResult(JET_errVersionStoreOutOfMemory);
  1162. hr = RegOpenKeyEx(
  1163. HKEY_LOCAL_MACHINE,
  1164. g_wszRegKeyConfigPath,
  1165. 0, // dwReserved
  1166. KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_QUERY_VALUE,
  1167. &hkeyConfig);
  1168. _JumpIfError(hr, error, "RegOpenKeyEx(Config)");
  1169. cbbuf = sizeof(abbuf);
  1170. hr = RegQueryValueEx(
  1171. hkeyConfig,
  1172. g_wszRegDirectory,
  1173. NULL, // lpdwReserved
  1174. &dwType,
  1175. abbuf,
  1176. &cbbuf);
  1177. if (S_OK != hr)
  1178. {
  1179. hr = myHError(hr);
  1180. }
  1181. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
  1182. {
  1183. _JumpIfError(hr, error, "RegQueryValueEx(Base)");
  1184. if (REG_SZ != dwType)
  1185. {
  1186. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1187. _JumpError(hr, error, "RegQueryValueEx(Base)");
  1188. }
  1189. if (sizeof(abbuf) < cbbuf)
  1190. {
  1191. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  1192. _JumpError(hr, error, "RegQueryValueEx(Base)");
  1193. }
  1194. CopyMemory(g_wszSharedFolder, abbuf, cbbuf);
  1195. }
  1196. DBGPRINT((DBG_SS_CERTSRVI, "Shared Folder = '%ws'\n", g_wszSharedFolder));
  1197. cbbuf = sizeof(g_dwSessionCount);
  1198. hr = RegQueryValueEx(
  1199. hkeyConfig,
  1200. wszREGDBSESSIONCOUNT,
  1201. NULL,
  1202. NULL,
  1203. (BYTE *) &g_dwSessionCount,
  1204. &cbbuf);
  1205. if (S_OK != hr)
  1206. {
  1207. _PrintErrorStr(hr, "RegQueryValueEx", wszREGDBSESSIONCOUNT);
  1208. g_dwSessionCount = DBSESSIONCOUNTDEFAULT;
  1209. }
  1210. if (DBSESSIONCOUNTMIN > g_dwSessionCount)
  1211. {
  1212. g_dwSessionCount = DBSESSIONCOUNTMIN;
  1213. }
  1214. if (DBSESSIONCOUNTMAX < g_dwSessionCount)
  1215. {
  1216. g_dwSessionCount = DBSESSIONCOUNTMAX;
  1217. }
  1218. // Find out the name of the active CA(s)
  1219. g_wszSanitizedName[0] = L'\0';
  1220. cbbuf = sizeof(g_wszSanitizedName);
  1221. hr = RegQueryValueEx(
  1222. hkeyConfig,
  1223. g_wszRegActive,
  1224. NULL, // lpdwReserved
  1225. &dwType,
  1226. (BYTE *) g_wszSanitizedName,
  1227. &cbbuf);
  1228. if ((HRESULT) ERROR_FILE_NOT_FOUND == hr)
  1229. {
  1230. #define szForgotSetup "\n\nDid you forget to setup the Cert Server?\n\n\n"
  1231. CONSOLEPRINT0((MAXDWORD, szForgotSetup));
  1232. }
  1233. _JumpIfError(hr, error, "RegQueryValueEx(Base)");
  1234. if (REG_SZ != dwType && REG_MULTI_SZ != dwType)
  1235. {
  1236. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1237. _JumpError(hr, error, "RegQueryValueEx: value type");
  1238. }
  1239. g_wszSanitizedName[cbbuf / sizeof(WCHAR)] = L'\0';
  1240. if (REG_MULTI_SZ == dwType)
  1241. {
  1242. i = wcslen(g_wszSanitizedName);
  1243. if (L'\0' != g_wszSanitizedName[i + 1])
  1244. {
  1245. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1246. _JumpError(hr, error, "RegQueryValueEx: multiple Active CAs");
  1247. }
  1248. }
  1249. DBGPRINT((DBG_SS_CERTSRVI, "Active CA (Sanitized Name) = '%ws'\n", g_wszSanitizedName));
  1250. pwszLog = g_wszSanitizedName;
  1251. hr = mySanitizedNameToDSName(g_wszSanitizedName, &g_pwszSanitizedDSName);
  1252. _JumpIfError(hr, error, "mySanitizedNameToDSName");
  1253. hr = RegOpenKeyEx(
  1254. hkeyConfig,
  1255. g_wszSanitizedName,
  1256. 0, // dwReserved
  1257. KEY_ENUMERATE_SUB_KEYS | KEY_EXECUTE | KEY_QUERY_VALUE,
  1258. &hkeyCN);
  1259. if (S_OK != hr)
  1260. {
  1261. hr = myHError(hr);
  1262. _JumpError(hr, error, "RegOpenKeyEx");
  1263. }
  1264. cbValue = sizeof(g_wszCommonName) - 2 * sizeof(WCHAR);
  1265. hr = RegQueryValueEx(
  1266. hkeyCN,
  1267. wszREGCOMMONNAME,
  1268. NULL,
  1269. &dwType,
  1270. (BYTE *)g_wszCommonName,
  1271. &cbValue);
  1272. if (S_OK != hr)
  1273. {
  1274. hr = myHError(hr);
  1275. _JumpError(hr, error, "RegOpenKeyEx");
  1276. }
  1277. if (REG_SZ != dwType)
  1278. {
  1279. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1280. _JumpError(hr, error, "Couldn't find CA common name");
  1281. }
  1282. g_wszCommonName[cbValue / sizeof(WCHAR)] = L'\0';
  1283. pwszLog = g_wszCommonName;
  1284. cbValue = sizeof(dwEnabled);
  1285. hr = RegQueryValueEx(
  1286. hkeyCN,
  1287. g_wszRegEnabled,
  1288. NULL, // lpdwReserved
  1289. &dwType,
  1290. (BYTE *) &dwEnabled,
  1291. &cbValue);
  1292. if (S_OK != hr)
  1293. {
  1294. hr = myHError(hr);
  1295. _JumpError(hr, error, "RegQueryValueEx");
  1296. }
  1297. if (REG_DWORD == dwType &&
  1298. sizeof(dwEnabled) == cbValue &&
  1299. 0 == dwEnabled)
  1300. {
  1301. DBGPRINT((DBG_SS_CERTSRVI, "CN = '%ws' DISABLED!\n", g_wszSanitizedName));
  1302. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1303. _JumpError(hr, error, "RegQueryValueEx: Active CA DISABLED!");
  1304. }
  1305. DBGPRINT((DBG_SS_CERTSRVI, "CN = '%ws': Enabled\n", g_wszSanitizedName));
  1306. // to check machine setup status
  1307. hr = GetSetupStatus(NULL, &dw);
  1308. _JumpIfError(hr, error, "GetSetupStatus");
  1309. if (!(SETUP_SERVER_FLAG & dw))
  1310. {
  1311. hr = HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE);
  1312. _JumpError(hr, error, "Server installation was not complete");
  1313. }
  1314. if (SETUP_SERVER_UPGRADED_FLAG & dw)
  1315. {
  1316. g_fServerUpgraded = TRUE;
  1317. DBGPRINT((
  1318. DBG_SS_CERTSRV,
  1319. "CoreInit: read SETUP_SERVER_UPGRADED_FLAG\n"));
  1320. }
  1321. // check per ca
  1322. hr = GetSetupStatus(g_wszSanitizedName, &dwCASetupStatus);
  1323. _JumpIfError(hr, error, "GetSetupStatus");
  1324. dw = dwCASetupStatus;
  1325. if (SETUP_SUSPEND_FLAG & dw)
  1326. {
  1327. LogMsg = MSG_E_INCOMPLETE_HIERARCHY;
  1328. hr = myGetCARegFileNameTemplate(
  1329. wszREGREQUESTFILENAME,
  1330. g_pwszServerName,
  1331. g_wszSanitizedName,
  1332. 0,
  1333. 0,
  1334. &pwszFullRequestFileName);
  1335. _JumpIfErrorStr(hr, error, "myGetCARegFileNameTemplate wszREGREQUESTFILENAME",
  1336. g_wszSanitizedName);
  1337. pwszLog = pwszFullRequestFileName;
  1338. hr = HRESULT_FROM_WIN32(ERROR_INSTALL_SUSPEND);
  1339. _JumpError(hr, error, "Hierarchy setup incomplete");
  1340. }
  1341. if (!(SETUP_SERVER_FLAG & dw))
  1342. {
  1343. hr = HRESULT_FROM_WIN32(ERROR_CAN_NOT_COMPLETE);
  1344. _JumpError(hr, error, "Server installation was not complete");
  1345. }
  1346. if (SETUP_FORCECRL_FLAG & dw)
  1347. {
  1348. // Don't clear SETUP_FORCECRL_FLAG until CRLs successfully generated
  1349. hr = myDeleteCertRegValue(
  1350. g_wszSanitizedName,
  1351. NULL,
  1352. NULL,
  1353. wszREGCRLNEXTPUBLISH);
  1354. _PrintIfErrorStr2(
  1355. hr,
  1356. "myDeleteCertRegValue",
  1357. wszREGCRLNEXTPUBLISH,
  1358. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  1359. }
  1360. // update the CA DS object with the server type flags
  1361. if (SETUP_UPDATE_CAOBJECT_SVRTYPE & dw)
  1362. {
  1363. hr = SetCAObjectFlags(
  1364. g_fAdvancedServer? CA_FLAG_CA_SERVERTYPE_ADVANCED : 0);
  1365. _PrintIfError(hr, "SetCAObjectFlags");
  1366. if (S_OK == hr)
  1367. {
  1368. hr = SetSetupStatus(
  1369. g_wszSanitizedName,
  1370. SETUP_UPDATE_CAOBJECT_SVRTYPE,
  1371. FALSE);
  1372. _PrintIfError(hr, "SetSetupStatus");
  1373. }
  1374. }
  1375. hr = coreReadRegStringValue(
  1376. hkeyCN,
  1377. wszREGALTERNATEPUBLISHDOMAINS,
  1378. &g_pwszzAlternatePublishDomains);
  1379. _PrintIfError2(
  1380. hr,
  1381. "coreReadRegStringValue",
  1382. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  1383. coreDSInitCache();
  1384. coreLdapInitCache();
  1385. cbValue = sizeof(g_PolicyFlags);
  1386. hr = RegQueryValueEx(
  1387. hkeyCN,
  1388. g_wszRegPolicyFlags,
  1389. NULL, // lpdwReserved
  1390. &dwType,
  1391. (BYTE *) &g_PolicyFlags,
  1392. &cbValue);
  1393. if (S_OK != hr ||
  1394. REG_DWORD != dwType ||
  1395. sizeof(g_PolicyFlags) != cbValue)
  1396. {
  1397. g_PolicyFlags = 0;
  1398. }
  1399. cbValue = sizeof(awcTemplate);
  1400. hr = RegQueryValueEx(
  1401. hkeyCN,
  1402. g_wszRegSubjectTemplate,
  1403. NULL, // lpdwReserved
  1404. &dwType,
  1405. (BYTE *) awcTemplate,
  1406. &cbValue);
  1407. if (S_OK == hr &&
  1408. (REG_SZ == dwType || REG_MULTI_SZ == dwType) &&
  1409. sizeof(WCHAR) < cbValue &&
  1410. L'\0' != awcTemplate[0])
  1411. {
  1412. if (L'\0' != awcTemplate[cbValue/sizeof(WCHAR) - 1] ||
  1413. (REG_MULTI_SZ == dwType &&
  1414. L'\0' != awcTemplate[cbValue/sizeof(WCHAR) - 2]) ||
  1415. sizeof(awcTemplate) < cbValue)
  1416. {
  1417. LogMsg = MSG_E_REG_BAD_SUBJECT_TEMPLATE;
  1418. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1419. _JumpError(hr, error, "Bad Subject Template length/termination");
  1420. }
  1421. pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cbValue + sizeof(WCHAR));
  1422. if (NULL != pwsz)
  1423. {
  1424. if (dwType == REG_MULTI_SZ)
  1425. {
  1426. CopyMemory(pwsz, awcTemplate, cbValue);
  1427. }
  1428. else
  1429. {
  1430. hr = coreConvertSubjectTemplate(pwsz, awcTemplate, cbValue);
  1431. if (S_OK != hr)
  1432. {
  1433. LocalFree(pwsz);
  1434. }
  1435. _JumpIfError(hr, error, "coreConvertSubjectTemplate");
  1436. }
  1437. g_pwszzSubjectTemplate = pwsz;
  1438. }
  1439. }
  1440. cbValue = sizeof(dw);
  1441. hr = RegQueryValueEx(
  1442. hkeyCN,
  1443. g_wszRegCertEnrollCompatible,
  1444. NULL, // lpdwReserved
  1445. &dwType,
  1446. (BYTE *) &dw,
  1447. &cbValue);
  1448. if (S_OK == hr &&
  1449. REG_DWORD == dwType &&
  1450. sizeof(dw) == cbValue)
  1451. {
  1452. g_fCertEnrollCompatible = dw? TRUE : FALSE;
  1453. }
  1454. cbValue = sizeof(dw);
  1455. hr = RegQueryValueEx(
  1456. hkeyCN,
  1457. g_wszRegEnforceX500NameLengths,
  1458. NULL, // lpdwReserved
  1459. &dwType,
  1460. (BYTE *) &dw,
  1461. &cbValue);
  1462. if (S_OK == hr &&
  1463. REG_DWORD == dwType &&
  1464. sizeof(dw) == cbValue)
  1465. {
  1466. g_fEnforceRDNNameLengths = dw? TRUE : FALSE;
  1467. }
  1468. cbValue = sizeof(dw);
  1469. hr = RegQueryValueEx(
  1470. hkeyCN,
  1471. wszREGCRLEDITFLAGS,
  1472. NULL, // lpdwReserved
  1473. &dwType,
  1474. (BYTE *) &dw,
  1475. &cbValue);
  1476. if (S_OK == hr &&
  1477. REG_DWORD == dwType &&
  1478. sizeof(dw) == cbValue)
  1479. {
  1480. g_CRLEditFlags = dw;
  1481. }
  1482. cbValue = sizeof(dw);
  1483. hr = RegQueryValueEx(
  1484. hkeyCN,
  1485. wszREGKRAFLAGS,
  1486. NULL, // lpdwReserved
  1487. &dwType,
  1488. (BYTE *) &dw,
  1489. &cbValue);
  1490. if (S_OK == hr &&
  1491. REG_DWORD == dwType &&
  1492. sizeof(dw) == cbValue)
  1493. {
  1494. g_KRAFlags = dw;
  1495. }
  1496. cbValue = sizeof(dw);
  1497. hr = RegQueryValueEx(
  1498. hkeyCN,
  1499. wszREGKRACERTCOUNT,
  1500. NULL, // lpdwReserved
  1501. &dwType,
  1502. (BYTE *) &dw,
  1503. &cbValue);
  1504. if (S_OK == hr &&
  1505. REG_DWORD == dwType &&
  1506. sizeof(dw) == cbValue)
  1507. {
  1508. g_cKRACertsRoundRobin = dw;
  1509. }
  1510. hr = coreRegGetTimePeriod(
  1511. hkeyCN,
  1512. g_wszRegValidityPeriodCount,
  1513. g_wszRegValidityPeriodString,
  1514. &g_enumValidityPeriod,
  1515. &g_lValidityPeriodCount);
  1516. if (S_OK != hr)
  1517. {
  1518. LogMsg = MSG_E_REG_BAD_CERT_PERIOD;
  1519. _JumpError(hr, error, "Bad Registry ValidityPeriod");
  1520. }
  1521. hr = coreRegGetTimePeriod(
  1522. hkeyCN,
  1523. g_wszRegCAXchgValidityPeriodCount,
  1524. g_wszRegCAXchgValidityPeriodString,
  1525. &g_enumCAXchgValidityPeriod,
  1526. &g_lCAXchgValidityPeriodCount);
  1527. _PrintIfError(hr, "Bad Registry CA Xchg Validity Period");
  1528. hr = coreRegGetTimePeriod(
  1529. hkeyCN,
  1530. g_wszRegCAXchgOverlapPeriodCount,
  1531. g_wszRegCAXchgOverlapPeriodString,
  1532. &g_enumCAXchgOverlapPeriod,
  1533. &g_lCAXchgOverlapPeriodCount);
  1534. _PrintIfError(hr, "Bad Registry CA Xchg Overlap Period");
  1535. hr = PKCSUpdateXchgValidityPeriods(NULL);
  1536. _PrintIfError(hr, "PKCSUpdateXchgValidityPeriods");
  1537. cbValue = sizeof(dw);
  1538. hr = RegQueryValueEx(
  1539. hkeyCN,
  1540. g_wszRegForceTeletex,
  1541. NULL, // lpdwReserved
  1542. &dwType,
  1543. (BYTE *) &dw,
  1544. &cbValue);
  1545. if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
  1546. {
  1547. switch (ENUM_TELETEX_MASK & dw)
  1548. {
  1549. case ENUM_TELETEX_OFF:
  1550. case ENUM_TELETEX_ON:
  1551. g_fForceTeletex =
  1552. (enum ENUM_FORCETELETEX) (ENUM_TELETEX_MASK & dw);
  1553. break;
  1554. default:
  1555. g_fForceTeletex = ENUM_TELETEX_AUTO;
  1556. break;
  1557. }
  1558. if (ENUM_TELETEX_UTF8 & dw)
  1559. {
  1560. *(DWORD *) &g_fForceTeletex |= ENUM_TELETEX_UTF8;
  1561. }
  1562. }
  1563. cbValue = sizeof(g_CAType);
  1564. hr = RegQueryValueEx(
  1565. hkeyCN,
  1566. wszREGCATYPE,
  1567. NULL,
  1568. &dwType,
  1569. (BYTE *) &g_CAType,
  1570. &cbValue);
  1571. _JumpIfError(hr, error, "RegQueryValueEx");
  1572. cbValue = sizeof(g_fUseDS);
  1573. hr = RegQueryValueEx(
  1574. hkeyCN,
  1575. wszREGCAUSEDS,
  1576. NULL,
  1577. &dwType,
  1578. (BYTE *) &g_fUseDS,
  1579. &cbValue);
  1580. _JumpIfError(hr, error, "RegQueryValueEx");
  1581. cbValue = sizeof(g_wszParentConfig) - 2 * sizeof(WCHAR);
  1582. hr = RegQueryValueEx(
  1583. hkeyCN,
  1584. wszREGPARENTCAMACHINE,
  1585. NULL,
  1586. &dwType,
  1587. (BYTE *) g_wszParentConfig,
  1588. &cbValue);
  1589. if (S_OK == hr && REG_SZ == dwType)
  1590. {
  1591. g_wszParentConfig[cbValue / sizeof(WCHAR)] = L'\0';
  1592. pwsz = &g_wszParentConfig[wcslen(g_wszParentConfig)];
  1593. *pwsz++ = L'\\';
  1594. *pwsz = L'\0';
  1595. cbValue =
  1596. sizeof(g_wszParentConfig) -
  1597. (SAFE_SUBTRACT_POINTERS(pwsz, g_wszParentConfig) + 1) *
  1598. sizeof(WCHAR);
  1599. hr = RegQueryValueEx(
  1600. hkeyCN,
  1601. wszREGPARENTCANAME,
  1602. NULL,
  1603. &dwType,
  1604. (BYTE *) pwsz,
  1605. &cbValue);
  1606. if (S_OK == hr && REG_SZ == dwType)
  1607. {
  1608. pwsz[cbValue / sizeof(WCHAR)] = L'\0';
  1609. }
  1610. else
  1611. {
  1612. g_wszParentConfig[0] = L'\0';
  1613. }
  1614. }
  1615. else
  1616. {
  1617. g_wszParentConfig[0] = L'\0';
  1618. }
  1619. cbValue = sizeof(dw);
  1620. hr = RegQueryValueEx(
  1621. hkeyCN,
  1622. g_wszRegClockSkewMinutes,
  1623. NULL, // lpdwReserved
  1624. &dwType,
  1625. (BYTE *) &dw,
  1626. &cbValue);
  1627. if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
  1628. {
  1629. g_dwClockSkewMinutes = dw;
  1630. }
  1631. cbValue = sizeof(dw);
  1632. hr = RegQueryValueEx(
  1633. hkeyCN,
  1634. g_wszRegViewAgeMinutes,
  1635. NULL, // lpdwReserved
  1636. &dwType,
  1637. (BYTE *) &dw,
  1638. &cbValue);
  1639. if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
  1640. {
  1641. g_dwViewAgeMinutes = dw;
  1642. }
  1643. cbValue = sizeof(dw);
  1644. hr = RegQueryValueEx(
  1645. hkeyCN,
  1646. g_wszRegViewIdleMinutes,
  1647. NULL, // lpdwReserved
  1648. &dwType,
  1649. (BYTE *) &dw,
  1650. &cbValue);
  1651. if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
  1652. {
  1653. g_dwViewIdleMinutes = dw;
  1654. }
  1655. cbValue = sizeof(dw);
  1656. hr = RegQueryValueEx(
  1657. hkeyCN,
  1658. g_wszRegMaxIncomingMessageSize,
  1659. NULL, // lpdwReserved
  1660. &dwType,
  1661. (BYTE *) &dw,
  1662. &cbValue);
  1663. if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
  1664. {
  1665. g_cbMaxIncomingMessageSize = dw;
  1666. }
  1667. cbValue = sizeof(dw);
  1668. hr = RegQueryValueEx(
  1669. hkeyCN,
  1670. g_wszRegMaxIncomingAllocSize,
  1671. NULL, // lpdwReserved
  1672. &dwType,
  1673. (BYTE *) &dw,
  1674. &cbValue);
  1675. if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
  1676. {
  1677. g_cbMaxIncomingAllocSize = dw;
  1678. }
  1679. // load CRL globals
  1680. hr = CRLInit(g_wszSanitizedName);
  1681. _JumpIfError(hr, error, "CRLInitializeGlobals");
  1682. cbValue = sizeof(dw);
  1683. hr = RegQueryValueEx(
  1684. hkeyCN,
  1685. g_wszRegLogLevel,
  1686. NULL, // lpdwReserved
  1687. &dwType,
  1688. (BYTE *) &dw,
  1689. &cbValue);
  1690. if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
  1691. {
  1692. g_dwLogLevel = dw;
  1693. }
  1694. cbValue = sizeof(dw);
  1695. hr = RegQueryValueEx(
  1696. hkeyCN,
  1697. g_wszRegHighSerial,
  1698. NULL, // lpdwReserved
  1699. &dwType,
  1700. (BYTE *) &dw,
  1701. &cbValue);
  1702. if (S_OK == hr)
  1703. {
  1704. if (REG_DWORD == dwType)
  1705. {
  1706. if (sizeof(dw) == cbValue)
  1707. {
  1708. g_dwHighSerial = dw;
  1709. }
  1710. }
  1711. else if (REG_SZ == dwType)
  1712. {
  1713. hr = coreReadRegStringValue(
  1714. hkeyCN,
  1715. g_wszRegHighSerial,
  1716. &pwszHighSerial);
  1717. _JumpIfError(hr, error, "coreReadRegStringValue");
  1718. hr = WszToMultiByteInteger(
  1719. FALSE,
  1720. pwszHighSerial,
  1721. &g_cbHighSerial,
  1722. &g_pbHighSerial);
  1723. _JumpIfError(hr, error, "WszToMultiByteInteger");
  1724. }
  1725. }
  1726. cbValue = sizeof(dw);
  1727. hr = RegQueryValueEx(
  1728. hkeyCN,
  1729. wszREGINTERFACEFLAGS,
  1730. NULL, // lpdwReserved
  1731. &dwType,
  1732. (BYTE *) &dw,
  1733. &cbValue);
  1734. if (S_OK == hr && REG_DWORD == dwType && sizeof(dw) == cbValue)
  1735. {
  1736. g_InterfaceFlags = dw;
  1737. }
  1738. hr = g_CASD.Initialize(g_wszSanitizedName);
  1739. if(S_OK!=hr)
  1740. {
  1741. LogMsg = MSG_BAD_PERMISSIONS;
  1742. _JumpError(hr, error, "CProtectedSecurityDescriptor::Initialize");
  1743. }
  1744. // Security has changed while certsrv was stopped. We need to update security on
  1745. // DS & service to make sure they are in sync with the CA permissions
  1746. if(dwCASetupStatus & SETUP_SECURITY_CHANGED)
  1747. {
  1748. hr = g_CASD.MapAndSetDaclOnObjects(g_fUseDS?true:false);
  1749. _PrintIfError(hr, "CProtectedSecurityDescriptor::MapAndSetDaclOnObjects");
  1750. // clear the flag only if successful
  1751. if(S_OK==hr)
  1752. {
  1753. hr = SetSetupStatus(g_wszSanitizedName, SETUP_SECURITY_CHANGED, FALSE);
  1754. _PrintIfError(hr, "SetSetupStatus SETUP_SECURITY_CHANGED FALSE");
  1755. }
  1756. }
  1757. g_CASD.ImportResourceStrings(g_pwszAuditResources);
  1758. // Functionality available only on advanced server:
  1759. // - restricted officers
  1760. // - enforce role separation
  1761. if (g_fAdvancedServer)
  1762. {
  1763. hr = g_OfficerRightsSD.Initialize(g_wszSanitizedName);
  1764. _JumpIfError(hr, error, "CProtectedSecurityDescriptor::Initialize");
  1765. g_OfficerRightsSD.ImportResourceStrings(g_pwszAuditResources);
  1766. hr = AuditSettings.RoleSeparationFlagLoad(g_wszSanitizedName);
  1767. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
  1768. {
  1769. _JumpIfError(hr, error, "CAuditEvent::RoleSeparationFlagLoad");
  1770. }
  1771. }
  1772. hr = AuditSettings.LoadFilter(g_wszSanitizedName);
  1773. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr)
  1774. {
  1775. _JumpIfError(hr, error, "CAuditEvent::LoadFilter");
  1776. }
  1777. if (fAuditEnabled)
  1778. {
  1779. g_dwAuditFilter = AuditSettings.GetFilter();
  1780. }
  1781. if (NULL != g_pwszzSubjectTemplate)
  1782. {
  1783. hr = PKCSSetSubjectTemplate(g_pwszzSubjectTemplate);
  1784. if (S_OK != hr)
  1785. {
  1786. LogMsg = MSG_E_REG_BAD_SUBJECT_TEMPLATE;
  1787. pwszLog = g_wszSanitizedName;
  1788. _JumpError(hr, error, "PKCSSetSubjectTemplate");
  1789. }
  1790. }
  1791. hr = PKCSSetup(g_wszCommonName, g_wszSanitizedName);
  1792. if (S_OK != hr)
  1793. {
  1794. fLogError = FALSE; // PKCSSetup logs a specific error
  1795. _JumpError(hr, error, "PKCSSetup");
  1796. }
  1797. hr = CertificateInterfaceInit(
  1798. &ServerCallBacks,
  1799. sizeof(ServerCallBacks));
  1800. if (S_OK != hr)
  1801. {
  1802. LogMsg = MSG_CERTIF_MISMATCH;
  1803. _JumpError(hr, error, "CertificateInterfaceInit");
  1804. }
  1805. hr = ComInit();
  1806. _JumpIfError(hr, error, "ComInit");
  1807. hr = RequestInitCAPropertyInfo();
  1808. _JumpIfError(hr, error, "RequestInitCAPropertyInfo");
  1809. // We must have a policy module to continue.
  1810. hr = PolicyInit(g_wszCommonName, g_wszSanitizedName);
  1811. if (S_OK != hr)
  1812. {
  1813. LogMsg = MSG_NO_POLICY;
  1814. _JumpError(hr, error, "PolicyInit");
  1815. }
  1816. CSASSERT(g_fEnablePolicy);
  1817. // On error, silently leave exit module(s) disabled.
  1818. hr = ExitInit(g_wszCommonName, g_wszSanitizedName);
  1819. _PrintIfError(hr, "ExitInit");
  1820. hr = myGetCertRegMultiStrValue(
  1821. g_wszSanitizedName,
  1822. NULL,
  1823. NULL,
  1824. wszSECUREDATTRIBUTES,
  1825. &g_wszzSecuredAttributes);
  1826. if (S_OK != hr)
  1827. {
  1828. // Force defaults
  1829. g_wszzSecuredAttributes = (LPWSTR)g_wszzSecuredAttributesDefault;
  1830. }
  1831. if (g_fServerUpgraded)
  1832. {
  1833. DBGPRINT((
  1834. DBG_SS_CERTSRV,
  1835. "CoreInit: clearing SETUP_SERVER_UPGRADED_FLAG\n"));
  1836. hr = SetSetupStatus(NULL, SETUP_SERVER_UPGRADED_FLAG, FALSE);
  1837. _PrintIfError(hr, "SetSetupStatus");
  1838. }
  1839. fLogError = FALSE;
  1840. error:
  1841. if (fLogError)
  1842. {
  1843. LogEventString(EVENTLOG_ERROR_TYPE, LogMsg, pwszLog);
  1844. }
  1845. if (NULL != pwszFullRequestFileName)
  1846. {
  1847. LocalFree(pwszFullRequestFileName);
  1848. }
  1849. if (NULL != pwszHighSerial)
  1850. {
  1851. LocalFree(pwszHighSerial);
  1852. }
  1853. if (NULL != hkeyCN)
  1854. {
  1855. RegCloseKey(hkeyCN);
  1856. }
  1857. if (NULL != hkeyConfig)
  1858. {
  1859. RegCloseKey(hkeyConfig);
  1860. }
  1861. if (S_OK != hr)
  1862. {
  1863. CoreTerminate();
  1864. g_CASD.Uninitialize();
  1865. g_OfficerRightsSD.Uninitialize();
  1866. }
  1867. return(hr);
  1868. }
  1869. VOID
  1870. CoreTerminate(VOID)
  1871. {
  1872. if (g_fcritsecDSCache)
  1873. {
  1874. coreDSEmptyCache(TRUE);
  1875. DeleteCriticalSection(&g_critsecDSCache);
  1876. g_fcritsecDSCache = FALSE;
  1877. }
  1878. if (NULL != g_rgDSCache)
  1879. {
  1880. LocalFree(g_rgDSCache);
  1881. g_rgDSCache = NULL;
  1882. }
  1883. coreLdapFreeCache();
  1884. DBShutDown(FALSE);
  1885. ComShutDown();
  1886. PKCSTerminate();
  1887. CRLTerminate();
  1888. if (NULL != g_pwszServerName)
  1889. {
  1890. LocalFree(g_pwszServerName);
  1891. g_pwszServerName = NULL;
  1892. }
  1893. if (NULL != g_pwszzAlternatePublishDomains)
  1894. {
  1895. LocalFree(g_pwszzAlternatePublishDomains);
  1896. g_pwszzAlternatePublishDomains = NULL;
  1897. }
  1898. if (NULL != g_pwszzSubjectTemplate)
  1899. {
  1900. LocalFree(g_pwszzSubjectTemplate);
  1901. g_pwszzSubjectTemplate = NULL;
  1902. }
  1903. if (NULL != g_pwszSanitizedDSName)
  1904. {
  1905. LocalFree(g_pwszSanitizedDSName);
  1906. g_pwszSanitizedDSName = NULL;
  1907. }
  1908. if (NULL != g_pbHighSerial)
  1909. {
  1910. LocalFree(g_pbHighSerial);
  1911. g_pbHighSerial = NULL;
  1912. }
  1913. // free only if it points to memory that isn't the default static buffer
  1914. if (NULL != g_wszzSecuredAttributes &&
  1915. g_wszzSecuredAttributes != g_wszzSecuredAttributesDefault)
  1916. {
  1917. LocalFree(g_wszzSecuredAttributes);
  1918. g_wszzSecuredAttributes = NULL;
  1919. }
  1920. }
  1921. HRESULT
  1922. CoreSetRequestDispositionFields(
  1923. IN ICertDBRow *prow,
  1924. IN DWORD ErrCode,
  1925. IN DWORD Disposition,
  1926. IN WCHAR const *pwszDisposition)
  1927. {
  1928. HRESULT hr;
  1929. hr = CoreSetDisposition(prow, Disposition);
  1930. _JumpIfError(hr, error, "CoreSetDisposition");
  1931. hr = prow->SetProperty(
  1932. g_wszPropRequestStatusCode,
  1933. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1934. sizeof(ErrCode),
  1935. (BYTE const *) &ErrCode);
  1936. _JumpIfError(hr, error, "SetProperty(status code)");
  1937. if (NULL != pwszDisposition)
  1938. {
  1939. hr = prow->SetProperty(
  1940. g_wszPropRequestDispositionMessage,
  1941. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1942. MAXDWORD,
  1943. (BYTE const *) pwszDisposition);
  1944. _JumpIfError(hr, error, "SetProperty(disposition message)");
  1945. }
  1946. error:
  1947. return(hr);
  1948. }
  1949. HRESULT
  1950. coreFindOldArchivedKey(
  1951. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  1952. {
  1953. HRESULT hr;
  1954. ICertDBRow *prow = NULL;
  1955. if (NULL != pResult->strRenewalCertHash &&
  1956. NULL == pResult->pbArchivedKey &&
  1957. NULL == pResult->pwszKRAHashes)
  1958. {
  1959. hr = g_pCertDB->OpenRow(
  1960. PROPOPEN_READONLY | PROPTABLE_REQCERT | PROPOPEN_CERTHASH,
  1961. 0, // RequestId
  1962. pResult->strRenewalCertHash,
  1963. &prow);
  1964. _JumpIfErrorStr(hr, error, "OpenRow", pResult->strRenewalCertHash);
  1965. hr = PKCSGetProperty(
  1966. prow,
  1967. g_wszPropRequestRawArchivedKey,
  1968. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1969. &pResult->cbArchivedKey,
  1970. (BYTE **) &pResult->pbArchivedKey);
  1971. _JumpIfError(hr, error, "PKCSGetProperty");
  1972. hr = PKCSGetProperty(
  1973. prow,
  1974. g_wszPropRequestKeyRecoveryHashes,
  1975. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  1976. NULL,
  1977. (BYTE **) &pResult->pwszKRAHashes);
  1978. _JumpIfError(hr, error, "PKCSGetProperty");
  1979. }
  1980. hr = S_OK;
  1981. error:
  1982. if (NULL != prow)
  1983. {
  1984. prow->Release();
  1985. }
  1986. return(hr);
  1987. }
  1988. HRESULT
  1989. coreCreateRequest(
  1990. IN DWORD dwFlags,
  1991. IN WCHAR const *pwszUserName,
  1992. IN DWORD cbRequest,
  1993. IN BYTE const *pbRequest,
  1994. IN WCHAR const *pwszAttributes,
  1995. IN DWORD dwComContextIndex,
  1996. OUT ICertDBRow **pprow, // may return non-NULL on error
  1997. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  1998. {
  1999. HRESULT hr;
  2000. DWORD dwRequestFlags;
  2001. DWORD cb;
  2002. WCHAR *pwszAttrAlloc = NULL;
  2003. ICertDBRow *prow = NULL;
  2004. hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, 0, NULL, pprow);
  2005. _JumpIfError(hr, error, "OpenRow");
  2006. prow = *pprow;
  2007. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestSubmittedWhen);
  2008. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  2009. hr = CoreSetDisposition(prow, DB_DISP_ACTIVE);
  2010. _JumpIfError(hr, error, "CoreSetDisposition");
  2011. hr = prow->SetProperty(
  2012. g_wszPropRequestType,
  2013. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2014. sizeof(dwFlags),
  2015. (BYTE const *) &dwFlags);
  2016. _JumpIfError(hr, error, "SetProperty(type)");
  2017. if (L'\0' != *pwszUserName)
  2018. {
  2019. hr = prow->SetProperty(
  2020. g_wszPropRequesterName,
  2021. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2022. MAXDWORD,
  2023. (BYTE const *) pwszUserName);
  2024. _JumpIfError(hr, error, "SetProperty(requester)");
  2025. hr = prow->SetProperty(
  2026. g_wszPropCallerName,
  2027. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2028. MAXDWORD,
  2029. (BYTE const *) pwszUserName);
  2030. _JumpIfError(hr, error, "SetProperty(caller)");
  2031. }
  2032. if (NULL != pwszAttributes && L'\0' != *pwszAttributes)
  2033. {
  2034. WCHAR const *pwszAttrSave = pwszAttributes;
  2035. if (wcslen(pwszAttrSave) > CCH_DBMAXTEXT_ATTRSTRING)
  2036. {
  2037. DBGPRINT((
  2038. DBG_SS_CERTSRV,
  2039. "coreCreateRequest: truncating Attributes %u -> %u chars\n",
  2040. wcslen(pwszAttrSave),
  2041. CCH_DBMAXTEXT_ATTRSTRING));
  2042. hr = myDupString(pwszAttrSave, &pwszAttrAlloc);
  2043. _JumpIfError(hr, error, "myDupString");
  2044. pwszAttrAlloc[CCH_DBMAXTEXT_ATTRSTRING] = L'\0';
  2045. pwszAttrSave = pwszAttrAlloc;
  2046. }
  2047. hr = prow->SetProperty(
  2048. g_wszPropRequestAttributes,
  2049. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2050. MAXDWORD,
  2051. (BYTE const *) pwszAttrSave);
  2052. _JumpIfError(hr, error, "SetProperty(attrib)");
  2053. }
  2054. hr = PropParseRequest(prow, dwFlags, cbRequest, pbRequest, pResult);
  2055. _JumpIfError(hr, error, "PropParseRequest");
  2056. hr = PKCSParseAttributes(
  2057. prow,
  2058. pwszAttributes,
  2059. FALSE,
  2060. FALSE,
  2061. PROPTABLE_REQUEST,
  2062. NULL);
  2063. _JumpIfError(hr, error, "PKCSParseAttributes");
  2064. hr = coreFindOldArchivedKey(pResult);
  2065. _PrintIfError(hr, "coreFindOldArchivedKey");
  2066. hr = prow->CopyRequestNames(); // after parsing request attributes!
  2067. _JumpIfError(hr, error, "CopyRequestNames");
  2068. hr = PKCSVerifyChallengeString(prow);
  2069. _JumpIfError(hr, error, "PKCSVerifyChallengeString");
  2070. cb = sizeof(dwRequestFlags);
  2071. hr = prow->GetProperty(
  2072. g_wszPropRequestFlags,
  2073. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2074. NULL,
  2075. &cb,
  2076. (BYTE *) &dwRequestFlags);
  2077. _JumpIfError(hr, error, "GetProperty");
  2078. if (CR_FLG_ENROLLONBEHALFOF & dwRequestFlags)
  2079. {
  2080. hr = coreGetComContextUserDNFromSamName(
  2081. TRUE, // fDeleteUserDNOnly
  2082. NULL, // pwszSamName
  2083. 0, // Context
  2084. dwComContextIndex,
  2085. NULL); // pwszDN
  2086. _JumpIfError(hr, error, "coreGetComContextUserDNFromSamName");
  2087. }
  2088. hr = S_OK;
  2089. error:
  2090. if (NULL != pwszAttrAlloc)
  2091. {
  2092. LocalFree(pwszAttrAlloc);
  2093. }
  2094. return(hr);
  2095. }
  2096. HRESULT
  2097. coreFetchCertificate(
  2098. IN ICertDBRow *prow,
  2099. OUT CERTTRANSBLOB *pctbCert) // CoTaskMem*
  2100. {
  2101. HRESULT hr;
  2102. DWORD cbProp;
  2103. pctbCert->pb = NULL;
  2104. cbProp = 0;
  2105. hr = prow->GetProperty(
  2106. g_wszPropRawCertificate,
  2107. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2108. NULL,
  2109. &cbProp,
  2110. NULL);
  2111. _JumpIfError(hr, error, "GetProperty(raw cert size)");
  2112. pctbCert->pb = (BYTE *) CoTaskMemAlloc(cbProp);
  2113. if (NULL == pctbCert->pb)
  2114. {
  2115. hr = E_OUTOFMEMORY;
  2116. _JumpError(hr, error, "CoTaskMemAlloc(raw cert)");
  2117. }
  2118. hr = prow->GetProperty(
  2119. g_wszPropRawCertificate,
  2120. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2121. NULL,
  2122. &cbProp,
  2123. pctbCert->pb);
  2124. _JumpIfError(hr, error, "GetProperty(raw cert)");
  2125. error:
  2126. if (S_OK != hr && NULL != pctbCert->pb)
  2127. {
  2128. CoTaskMemFree(pctbCert->pb);
  2129. pctbCert->pb = NULL;
  2130. }
  2131. pctbCert->cb = cbProp;
  2132. return(hr);
  2133. }
  2134. HRESULT
  2135. coreRetrievePending(
  2136. IN ICertDBRow *prow,
  2137. IN BOOL fIncludeCRLs,
  2138. OUT WCHAR **ppwszDisposition, // LocalAlloc
  2139. OUT CACTX **ppCAContext,
  2140. IN OUT CERTSRV_RESULT_CONTEXT *pResult) // CoTaskMem*
  2141. {
  2142. HRESULT hr;
  2143. DWORD cbProp;
  2144. WCHAR *pwszDisposition = NULL;
  2145. DWORD Disposition;
  2146. HRESULT hrRequest;
  2147. BOOL fIssued;
  2148. *ppwszDisposition = NULL;
  2149. *ppCAContext = NULL;
  2150. cbProp = sizeof(Disposition);
  2151. hr = prow->GetProperty(
  2152. g_wszPropRequestDisposition,
  2153. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2154. NULL,
  2155. &cbProp,
  2156. (BYTE *) &Disposition);
  2157. _JumpIfError(hr, error, "GetProperty(disposition)");
  2158. cbProp = sizeof(hrRequest);
  2159. hr = prow->GetProperty(
  2160. g_wszPropRequestStatusCode,
  2161. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2162. NULL,
  2163. &cbProp,
  2164. (BYTE *) &hrRequest);
  2165. _JumpIfError(hr, error, "GetProperty(status code)");
  2166. hr = PKCSGetProperty(
  2167. prow,
  2168. g_wszPropRequestDispositionMessage,
  2169. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2170. NULL,
  2171. (BYTE **) &pwszDisposition);
  2172. _PrintIfError2(hr, "PKCSGetProperty", CERTSRV_E_PROPERTY_EMPTY);
  2173. fIssued = FALSE;
  2174. switch (Disposition)
  2175. {
  2176. FILETIME FileTime;
  2177. case DB_DISP_ACTIVE:
  2178. case DB_DISP_PENDING:
  2179. *pResult->pdwDisposition = CR_DISP_UNDER_SUBMISSION;
  2180. break;
  2181. case DB_DISP_ISSUED:
  2182. case DB_DISP_CA_CERT:
  2183. case DB_DISP_CA_CERT_CHAIN:
  2184. hr = CERTSRV_E_PROPERTY_EMPTY;
  2185. if (DB_DISP_CA_CERT == Disposition && IsRootCA(g_CAType))
  2186. {
  2187. cbProp = sizeof(FileTime);
  2188. hr = prow->GetProperty(
  2189. g_wszPropRequestRevokedEffectiveWhen,
  2190. PROPTYPE_DATE | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2191. NULL,
  2192. &cbProp,
  2193. (BYTE *) &FileTime);
  2194. }
  2195. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  2196. {
  2197. *pResult->pdwDisposition = CR_DISP_ISSUED;
  2198. fIssued = TRUE;
  2199. break;
  2200. }
  2201. // FALLTHROUGH
  2202. case DB_DISP_REVOKED:
  2203. *pResult->pdwDisposition = CR_DISP_REVOKED;
  2204. fIssued = TRUE;
  2205. break;
  2206. case DB_DISP_ERROR:
  2207. *pResult->pdwDisposition = CR_DISP_ERROR;
  2208. break;
  2209. case DB_DISP_DENIED:
  2210. *pResult->pdwDisposition = CR_DISP_DENIED;
  2211. if (FAILED(hrRequest))
  2212. {
  2213. *pResult->pdwDisposition = hrRequest;
  2214. }
  2215. break;
  2216. default:
  2217. *pResult->pdwDisposition = CR_DISP_INCOMPLETE;
  2218. break;
  2219. }
  2220. if (fIssued)
  2221. {
  2222. BOOL fErrorLogged = FALSE;
  2223. hr = coreFetchCertificate(prow, pResult->pctbCert);
  2224. _JumpIfError(hr, error, "coreFetchCertificate");
  2225. CSASSERT(NULL != pResult->pctbCert && NULL != pResult->pctbCert->pb);
  2226. hr = PKCSCreateCertificate(
  2227. prow,
  2228. Disposition,
  2229. fIncludeCRLs,
  2230. FALSE, // fCrossCert
  2231. NULL, // use default signing CACTX
  2232. &fErrorLogged,
  2233. ppCAContext,
  2234. NULL, // ppwszDispositionCreateCert
  2235. pResult);
  2236. CSASSERT(!fErrorLogged);
  2237. if (S_OK != hr)
  2238. {
  2239. if (CERTLOG_ERROR <= g_dwLogLevel)
  2240. {
  2241. LogEventHResult(
  2242. EVENTLOG_ERROR_TYPE,
  2243. MSG_E_CANNOT_BUILD_CERT_OR_CHAIN,
  2244. hr);
  2245. }
  2246. _JumpError(hr, error, "PKCSCreateCertificate");
  2247. }
  2248. }
  2249. *ppwszDisposition = pwszDisposition;
  2250. pwszDisposition = NULL;
  2251. hr = S_OK;
  2252. error:
  2253. if (S_OK != hr && NULL != pResult->pctbCert->pb)
  2254. {
  2255. CoTaskMemFree(pResult->pctbCert->pb);
  2256. pResult->pctbCert->pb = NULL;
  2257. }
  2258. if (NULL != pwszDisposition)
  2259. {
  2260. LocalFree(pwszDisposition);
  2261. }
  2262. return(hr);
  2263. }
  2264. VOID
  2265. CoreLogRequestStatus(
  2266. IN ICertDBRow *prow,
  2267. IN DWORD LogMsg,
  2268. IN DWORD ErrCode,
  2269. OPTIONAL IN WCHAR const *pwszDisposition)
  2270. {
  2271. HRESULT hr;
  2272. WCHAR *pwszSubject = NULL;
  2273. WCHAR const *pwszSubject2;
  2274. WCHAR wszRequestId[cwcDWORDSPRINTF];
  2275. WCHAR awchr[cwcHRESULTSTRING];
  2276. WORD cString = 0;
  2277. WCHAR const *apwsz[4];
  2278. DWORD ReqId;
  2279. DWORD infotype = EVENTLOG_INFORMATION_TYPE;
  2280. WCHAR const *pwszMessageText = NULL;
  2281. DWORD LogMsg2;
  2282. prow->GetRowId(&ReqId);
  2283. wsprintf(wszRequestId, L"%u", ReqId);
  2284. apwsz[cString++] = wszRequestId;
  2285. LogMsg2 = LogMsg;
  2286. switch (LogMsg)
  2287. {
  2288. case MSG_DN_CERT_ISSUED:
  2289. LogMsg2 = MSG_DN_CERT_ISSUED_WITH_INFO;
  2290. break;
  2291. case MSG_DN_CERT_PENDING:
  2292. LogMsg2 = MSG_DN_CERT_PENDING_WITH_INFO;
  2293. break;
  2294. case MSG_DN_CERT_ADMIN_DENIED:
  2295. LogMsg2 = MSG_DN_CERT_ADMIN_DENIED_WITH_INFO;
  2296. break;
  2297. case MSG_DN_CERT_DENIED:
  2298. LogMsg2 = MSG_DN_CERT_DENIED_WITH_INFO;
  2299. infotype = EVENTLOG_WARNING_TYPE;
  2300. break;
  2301. case MSG_E_PROCESS_REQUEST_FAILED:
  2302. LogMsg2 = MSG_E_PROCESS_REQUEST_FAILED_WITH_INFO;
  2303. infotype = EVENTLOG_ERROR_TYPE;
  2304. break;
  2305. }
  2306. if (EVENTLOG_INFORMATION_TYPE != infotype)
  2307. {
  2308. if (S_OK == ErrCode)
  2309. {
  2310. ErrCode = (DWORD) SEC_E_CERT_UNKNOWN; // unknown error
  2311. }
  2312. pwszMessageText = myGetErrorMessageText(ErrCode, TRUE);
  2313. if (NULL == pwszMessageText)
  2314. {
  2315. pwszMessageText = myHResultToStringRaw(awchr, ErrCode);
  2316. }
  2317. apwsz[cString++] = pwszMessageText;
  2318. }
  2319. hr = PKCSGetProperty(
  2320. prow,
  2321. g_wszPropSubjectDistinguishedName,
  2322. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  2323. NULL,
  2324. (BYTE **) &pwszSubject);
  2325. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  2326. {
  2327. hr = PKCSGetProperty(
  2328. prow,
  2329. g_wszPropSubjectDistinguishedName,
  2330. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2331. NULL,
  2332. (BYTE **) &pwszSubject);
  2333. }
  2334. if (CERTSRV_E_PROPERTY_EMPTY == hr)
  2335. {
  2336. hr = PKCSGetProperty(
  2337. prow,
  2338. g_wszPropRequesterName,
  2339. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  2340. NULL,
  2341. (BYTE **) &pwszSubject);
  2342. }
  2343. pwszSubject2 = pwszSubject;
  2344. if (S_OK != hr)
  2345. {
  2346. _PrintError(hr, "GetProperty(DN/Requester)");
  2347. pwszSubject2 = g_pwszUnknownSubject;
  2348. }
  2349. apwsz[cString++] = pwszSubject2;
  2350. if (NULL != pwszDisposition)
  2351. {
  2352. LogMsg = LogMsg2;
  2353. apwsz[cString++] = pwszDisposition;
  2354. }
  2355. if (CERTLOG_VERBOSE <= g_dwLogLevel ||
  2356. (EVENTLOG_WARNING_TYPE == infotype && CERTLOG_WARNING <= g_dwLogLevel) ||
  2357. (EVENTLOG_ERROR_TYPE == infotype && CERTLOG_ERROR <= g_dwLogLevel))
  2358. {
  2359. LogEvent(infotype, LogMsg, cString, apwsz);
  2360. }
  2361. #if 0 == i386
  2362. # define IOBUNALIGNED(pf) ((sizeof(WCHAR) - 1) & (DWORD) (ULONG_PTR) (pf)->_ptr)
  2363. # define ALIGNIOB(pf) \
  2364. { \
  2365. if (IOBUNALIGNED(pf)) \
  2366. { \
  2367. fflush(pf); /* fails when running as a service */ \
  2368. } \
  2369. if (IOBUNALIGNED(pf)) \
  2370. { \
  2371. fprintf(pf, " "); \
  2372. fflush(pf); \
  2373. } \
  2374. }
  2375. #else
  2376. # define IOBUNALIGNED(pf) FALSE
  2377. # define ALIGNIOB(pf)
  2378. #endif
  2379. {
  2380. BOOL fRetried = FALSE;
  2381. for (;;)
  2382. {
  2383. ALIGNIOB(stdout);
  2384. __try
  2385. {
  2386. wprintf(
  2387. // L"\nCertSrv Request %u: rc=%x: %ws: %ws '%ws'\n"
  2388. g_pwszPrintfCertRequestDisposition,
  2389. ReqId,
  2390. ErrCode,
  2391. NULL != pwszMessageText? pwszMessageText : L"",
  2392. NULL != pwszDisposition? pwszDisposition : L"",
  2393. pwszSubject);
  2394. hr = S_OK;
  2395. }
  2396. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  2397. {
  2398. }
  2399. #pragma warning(push)
  2400. #pragma warning(disable: 4127) // conditional expression is constant
  2401. if (S_OK == hr || fRetried || !IOBUNALIGNED(stdout))
  2402. #pragma warning(pop)
  2403. {
  2404. break;
  2405. }
  2406. ALIGNIOB(stdout);
  2407. fRetried = TRUE;
  2408. }
  2409. }
  2410. if (NULL != pwszMessageText && awchr != pwszMessageText)
  2411. {
  2412. LocalFree(const_cast<WCHAR *>(pwszMessageText));
  2413. }
  2414. if (NULL != pwszSubject)
  2415. {
  2416. LocalFree(pwszSubject);
  2417. }
  2418. }
  2419. WCHAR *
  2420. CoreBuildDispositionString(
  2421. OPTIONAL IN WCHAR const *pwszDispositionBase,
  2422. OPTIONAL IN WCHAR const *pwszUserName,
  2423. OPTIONAL IN WCHAR const *pwszDispositionDetail,
  2424. OPTIONAL IN WCHAR const *pwszDispositionDetail2,
  2425. OPTIONAL IN WCHAR const *pwszBy,
  2426. IN HRESULT hrFail,
  2427. IN BOOL fPublishError)
  2428. {
  2429. DWORD cwc = 0;
  2430. WCHAR *pwsz = NULL;
  2431. WCHAR const *pwszMessageText = NULL;
  2432. WCHAR awchr[cwcHRESULTSTRING];
  2433. if (NULL == pwszUserName)
  2434. {
  2435. pwszUserName = L"";
  2436. }
  2437. if (NULL != pwszDispositionBase)
  2438. {
  2439. cwc += wcslen(pwszDispositionBase) + wcslen(pwszUserName);
  2440. }
  2441. if (NULL != pwszDispositionDetail)
  2442. {
  2443. if (0 != cwc)
  2444. {
  2445. cwc += 2; // spaces
  2446. }
  2447. cwc += wcslen(pwszDispositionDetail);
  2448. }
  2449. if (NULL != pwszDispositionDetail2)
  2450. {
  2451. if (0 != cwc)
  2452. {
  2453. cwc += 2; // spaces
  2454. }
  2455. cwc += wcslen(pwszDispositionDetail2);
  2456. }
  2457. if (NULL != pwszBy)
  2458. {
  2459. if (0 != cwc)
  2460. {
  2461. cwc += 2; // spaces
  2462. }
  2463. cwc += wcslen(pwszBy) + wcslen(pwszUserName);
  2464. }
  2465. if (S_OK != hrFail)
  2466. {
  2467. pwszMessageText = myGetErrorMessageText(hrFail, TRUE);
  2468. if (NULL == pwszMessageText)
  2469. {
  2470. pwszMessageText = myHResultToStringRaw(awchr, hrFail);
  2471. }
  2472. if (0 != cwc)
  2473. {
  2474. cwc += 2; // spaces
  2475. }
  2476. if (fPublishError)
  2477. {
  2478. cwc += wcslen(g_pwszPublishError);
  2479. cwc += 2; // spaces
  2480. }
  2481. cwc += wcslen(pwszMessageText);
  2482. }
  2483. if (0 != cwc)
  2484. {
  2485. pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (cwc + 1) * sizeof(WCHAR));
  2486. if (NULL != pwsz)
  2487. {
  2488. pwsz[0] = L'\0';
  2489. if (NULL != pwszDispositionBase)
  2490. {
  2491. wsprintf(pwsz, pwszDispositionBase, pwszUserName);
  2492. }
  2493. if (NULL != pwszDispositionDetail)
  2494. {
  2495. if (L'\0' != pwsz[0])
  2496. {
  2497. wcscat(pwsz, L" ");
  2498. }
  2499. wcscat(pwsz, pwszDispositionDetail);
  2500. }
  2501. if (NULL != pwszDispositionDetail2)
  2502. {
  2503. if (L'\0' != pwsz[0])
  2504. {
  2505. wcscat(pwsz, L" ");
  2506. }
  2507. wcscat(pwsz, pwszDispositionDetail2);
  2508. }
  2509. if (NULL != pwszBy)
  2510. {
  2511. if (L'\0' != pwsz[0])
  2512. {
  2513. wcscat(pwsz, L" ");
  2514. }
  2515. wsprintf(&pwsz[wcslen(pwsz)], pwszBy, pwszUserName);
  2516. }
  2517. if (S_OK != hrFail)
  2518. {
  2519. if (L'\0' != pwsz[0] && L'\n' != pwsz[wcslen(pwsz) - 1])
  2520. {
  2521. wcscat(pwsz, L" ");
  2522. }
  2523. if (fPublishError)
  2524. {
  2525. wcscat(pwsz, g_pwszPublishError);
  2526. wcscat(pwsz, L" ");
  2527. }
  2528. wcscat(pwsz, pwszMessageText);
  2529. }
  2530. }
  2531. CSASSERT(wcslen(pwsz) <= cwc);
  2532. }
  2533. //error:
  2534. if (NULL != pwszMessageText && awchr != pwszMessageText)
  2535. {
  2536. LocalFree(const_cast<WCHAR *>(pwszMessageText));
  2537. }
  2538. return(pwsz);
  2539. }
  2540. VOID
  2541. coreLogPublishError(
  2542. IN DWORD RequestId,
  2543. IN LDAP *pld,
  2544. IN WCHAR const *pwszDN,
  2545. IN BOOL fDelete,
  2546. OPTIONAL IN WCHAR const *pwszError,
  2547. IN HRESULT hrPublish)
  2548. {
  2549. HRESULT hr;
  2550. WCHAR const *apwsz[6];
  2551. WORD cpwsz;
  2552. WCHAR wszRequestId[cwcDWORDSPRINTF];
  2553. WCHAR awchr[cwcHRESULTSTRING];
  2554. WCHAR const *pwszMessageText = NULL;
  2555. WCHAR *pwszHostName = NULL;
  2556. DWORD LogMsg;
  2557. wsprintf(wszRequestId, L"%u", RequestId);
  2558. if (NULL != pld)
  2559. {
  2560. myLdapGetDSHostName(pld, &pwszHostName);
  2561. }
  2562. pwszMessageText = myGetErrorMessageText(hrPublish, TRUE);
  2563. if (NULL == pwszMessageText)
  2564. {
  2565. pwszMessageText = myHResultToStringRaw(awchr, hrPublish);
  2566. }
  2567. cpwsz = 0;
  2568. apwsz[cpwsz++] = wszRequestId;
  2569. apwsz[cpwsz++] = pwszDN;
  2570. apwsz[cpwsz++] = pwszMessageText;
  2571. LogMsg = fDelete? MSG_E_CERT_DELETION : MSG_E_CERT_PUBLICATION;
  2572. if (NULL != pwszHostName)
  2573. {
  2574. LogMsg = fDelete?
  2575. MSG_E_CERT_DELETION_HOST_NAME : MSG_E_CERT_PUBLICATION_HOST_NAME;
  2576. }
  2577. else
  2578. {
  2579. pwszHostName = L"";
  2580. }
  2581. apwsz[cpwsz++] = pwszHostName;
  2582. apwsz[cpwsz++] = NULL != pwszError? L"\n" : L"";
  2583. apwsz[cpwsz++] = NULL != pwszError? pwszError : L"";
  2584. CSASSERT(ARRAYSIZE(apwsz) >= cpwsz);
  2585. if (CERTLOG_WARNING <= g_dwLogLevel)
  2586. {
  2587. hr = LogEvent(EVENTLOG_WARNING_TYPE, LogMsg, cpwsz, apwsz);
  2588. _PrintIfError(hr, "LogEvent");
  2589. }
  2590. //error:
  2591. if (NULL != pwszMessageText && awchr != pwszMessageText)
  2592. {
  2593. LocalFree(const_cast<WCHAR *>(pwszMessageText));
  2594. }
  2595. }
  2596. HRESULT
  2597. corePublishKRACertificate(
  2598. IN DWORD RequestId,
  2599. IN CERT_CONTEXT const *pcc)
  2600. {
  2601. HRESULT hr;
  2602. LDAP *pld = NULL;
  2603. HCERTSTORE hStore = NULL;
  2604. DWORD dwDisposition;
  2605. WCHAR *pwszError = NULL;
  2606. hr = myRobustLdapBindEx(
  2607. 0, // dwFlags1
  2608. RLBF_REQUIRE_SECURE_LDAP, // dwFlags2
  2609. LDAP_VERSION2, // uVersion
  2610. NULL, // pwszDomainName
  2611. &pld,
  2612. NULL); // ppwszForestDNSName
  2613. _JumpIfError(hr, error, "myRobustLdapBindEx");
  2614. hStore = CertOpenStore(
  2615. CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  2616. X509_ASN_ENCODING,
  2617. NULL, // hProv
  2618. CERT_SYSTEM_STORE_LOCAL_MACHINE,
  2619. wszKRA_CERTSTORE);
  2620. if (NULL == hStore)
  2621. {
  2622. hr = myHLastError();
  2623. _JumpErrorStr(hr, error, "CertOpenStore", wszKRA_CERTSTORE);
  2624. }
  2625. // It's a new cert. CERT_STORE_ADD_ALWAYS is faster.
  2626. if (!CertAddCertificateContextToStore(
  2627. hStore,
  2628. pcc,
  2629. CERT_STORE_ADD_ALWAYS,
  2630. NULL))
  2631. {
  2632. hr = myHLastError();
  2633. _JumpError(hr, error, "CertAddCertificateContextToStore");
  2634. }
  2635. hr = myLdapPublishCertToDS(
  2636. pld,
  2637. pcc,
  2638. g_pwszKRAPublishURL,
  2639. wszDSKRACERTATTRIBUTE,
  2640. LPC_KRAOBJECT,
  2641. FALSE, // fDelete
  2642. &dwDisposition,
  2643. &pwszError);
  2644. _JumpIfError(hr, error, "myLdapPublishCertToDS");
  2645. error:
  2646. if (S_OK != hr)
  2647. {
  2648. coreLogPublishError(
  2649. RequestId,
  2650. pld,
  2651. g_pwszKRAPublishURL,
  2652. FALSE, // fDelete
  2653. pwszError,
  2654. hr);
  2655. }
  2656. if (NULL != pwszError)
  2657. {
  2658. LocalFree(pwszError);
  2659. }
  2660. if (NULL != hStore)
  2661. {
  2662. CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
  2663. }
  2664. if (NULL != pld)
  2665. {
  2666. ldap_unbind(pld);
  2667. }
  2668. return(hr);
  2669. }
  2670. HRESULT
  2671. CorePublishCrossCertificate(
  2672. IN DWORD RequestId,
  2673. IN CERT_CONTEXT const *pcc,
  2674. IN BOOL fCreateDSObject,
  2675. IN BOOL fDelete)
  2676. {
  2677. HRESULT hr;
  2678. LDAP *pld = NULL;
  2679. DWORD dwDisposition;
  2680. WCHAR *pwszError = NULL;
  2681. CAutoLPWSTR pwszCN;
  2682. CAutoLPWSTR pwszSanitizedCN;
  2683. CAutoLPWSTR pwszDSSanitizedCN;
  2684. CAutoLPWSTR pwszDN;
  2685. CAutoLPWSTR pwszSubject;
  2686. WCHAR const *pwszFormatDN = L"ldap:///CN=%ws%ws";
  2687. WCHAR *pwcRelDN;
  2688. hr = myGetCommonName(&pcc->pCertInfo->Subject, TRUE, &pwszCN);
  2689. _JumpIfError(hr, error, "myGetCommonName");
  2690. hr = mySanitizeName(pwszCN, &pwszSanitizedCN);
  2691. _JumpIfError(hr, error, "mySanitizeName");
  2692. hr = mySanitizedNameToDSName(pwszSanitizedCN, &pwszDSSanitizedCN);
  2693. _JumpIfError(hr, error, "mySanitizedNameToDSName");
  2694. if (NULL == g_pwszAIACrossCertPublishURL)
  2695. {
  2696. // Actually, something went wrong with pkcsExpandURL!
  2697. hr = ERROR_DS_INVALID_DN_SYNTAX;
  2698. _JumpError(hr, error, "g_pwszAIACrossCertPublishURL");
  2699. }
  2700. pwcRelDN = wcschr(g_pwszAIACrossCertPublishURL, L',');
  2701. if (NULL == pwcRelDN)
  2702. {
  2703. // Actually, something went wrong with pkcsExpandURL!
  2704. hr = ERROR_DS_INVALID_DN_SYNTAX;
  2705. _JumpError(hr, error, "g_pwszAIACrossCertPublishURL");
  2706. }
  2707. pwszDN = (WCHAR *) LocalAlloc(
  2708. LMEM_FIXED,
  2709. (wcslen(pwszFormatDN) +
  2710. wcslen(pwszDSSanitizedCN) +
  2711. wcslen(pwcRelDN)) * sizeof(WCHAR));
  2712. if (pwszDN == NULL)
  2713. {
  2714. hr = E_OUTOFMEMORY;
  2715. _JumpError(hr, error, "LocalAlloc");
  2716. }
  2717. wsprintf(pwszDN, pwszFormatDN, pwszDSSanitizedCN, pwcRelDN);
  2718. hr = myRobustLdapBindEx(
  2719. 0, // dwFlags1
  2720. RLBF_REQUIRE_SECURE_LDAP, // dwFlags2
  2721. LDAP_VERSION2, // uVersion
  2722. NULL, // pwszDomainName
  2723. &pld,
  2724. NULL); // ppwszForestDNSName
  2725. _JumpIfError(hr, error, "myRobustLdapBindEx");
  2726. hr = myLdapPublishCertToDS(
  2727. pld,
  2728. pcc,
  2729. pwszDN,
  2730. wszDSCROSSCERTPAIRATTRIBUTE,
  2731. LPC_CAOBJECT | (fCreateDSObject? LPC_CREATEOBJECT : 0),
  2732. fDelete,
  2733. &dwDisposition,
  2734. &pwszError);
  2735. if (S_OK != hr)
  2736. {
  2737. _PrintErrorStr(hr, "myLdapPublishCertToDS", pwszDN);
  2738. if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr &&
  2739. IsRootCA(g_CAType))
  2740. {
  2741. if (NULL != pwszError)
  2742. {
  2743. LocalFree(pwszError);
  2744. pwszError = NULL;
  2745. }
  2746. hr = S_OK;
  2747. }
  2748. }
  2749. _JumpIfErrorStr(hr, error, "myLdapPublishCertToDS", pwszDN);
  2750. if (!fDelete)
  2751. {
  2752. hr = myCertNameToStr(
  2753. X509_ASN_ENCODING,
  2754. &pcc->pCertInfo->Subject,
  2755. CERT_X500_NAME_STR, //| CERT_NAME_STR_REVERSE_FLAG,
  2756. &pwszSubject);
  2757. _JumpIfError(hr, error, "myCertNameToStr");
  2758. hr = myLDAPSetStringAttribute(
  2759. pld,
  2760. pwszDN,
  2761. CA_PROP_CERT_DN,
  2762. pwszSubject,
  2763. &dwDisposition,
  2764. &pwszError);
  2765. _JumpIfErrorStr(hr, error, "myLDAPSetStringAttribute", pwszDN);
  2766. }
  2767. hr = S_OK;
  2768. error:
  2769. if (S_OK != hr)
  2770. {
  2771. coreLogPublishError(RequestId, pld, pwszDN, fDelete, pwszError, hr);
  2772. }
  2773. if (NULL != pwszError)
  2774. {
  2775. LocalFree(pwszError);
  2776. }
  2777. if (NULL != pld)
  2778. {
  2779. ldap_unbind(pld);
  2780. }
  2781. return(hr);
  2782. }
  2783. #define wszCONTACTFILTER L"(&(&(objectCategory=contact)(objectClass=contact))(mail=%s))"
  2784. HRESULT
  2785. coreGetDNFromEMailName(
  2786. IN LDAP *pld,
  2787. IN WCHAR const *pwszEMailName,
  2788. OUT WCHAR **ppwszDN,
  2789. OUT DWORD *pdwDisposition,
  2790. OPTIONAL OUT WCHAR **ppwszError)
  2791. {
  2792. HRESULT hr;
  2793. DWORD cres;
  2794. LDAP_TIMEVAL timeval;
  2795. LDAPMessage *pmsg = NULL;
  2796. LDAPMessage *pres;
  2797. WCHAR *apwszAttrs[2];
  2798. WCHAR **ppwszValues = NULL;
  2799. CAutoLPWSTR pwszFilter;
  2800. CAutoBSTR strDomainDN;
  2801. pwszFilter = (LPWSTR) LocalAlloc(LMEM_FIXED,
  2802. sizeof(WCHAR)*(wcslen(wszCONTACTFILTER)+wcslen(pwszEMailName)));
  2803. _JumpIfAllocFailed(pwszFilter, error);
  2804. wsprintf(pwszFilter, wszCONTACTFILTER, pwszEMailName);
  2805. hr = myGetAuthoritativeDomainDn(pld, &strDomainDN, NULL);
  2806. _JumpIfError(hr, error, "myGetAuthoritativeDomainDn");
  2807. *ppwszDN = NULL;
  2808. *pdwDisposition = LDAP_OTHER;
  2809. if (NULL != ppwszError)
  2810. {
  2811. *ppwszError = NULL;
  2812. }
  2813. apwszAttrs[0] = wszDSDNATTRIBUTE;
  2814. apwszAttrs[1] = NULL;
  2815. timeval.tv_sec = csecLDAPTIMEOUT;
  2816. timeval.tv_usec = 0;
  2817. hr = ldap_search_st(
  2818. pld, // ld
  2819. strDomainDN, // base
  2820. LDAP_SCOPE_SUBTREE, // scope
  2821. pwszFilter, // filter
  2822. apwszAttrs, // attrs
  2823. FALSE, // attrsonly
  2824. &timeval, // timeout
  2825. &pmsg); // res
  2826. if (S_OK != hr)
  2827. {
  2828. *pdwDisposition = hr;
  2829. hr = myHLdapError(pld, hr, ppwszError);
  2830. _JumpErrorStr(hr, error, "ldap_search_st", pwszFilter);
  2831. }
  2832. hr = HRESULT_FROM_WIN32(ERROR_DS_OBJ_NOT_FOUND);
  2833. cres = ldap_count_entries(pld, pmsg);
  2834. if (0 == cres)
  2835. {
  2836. _JumpError(hr, error, "ldap_count_entries");
  2837. }
  2838. pres = ldap_first_entry(pld, pmsg);
  2839. if (NULL == pres)
  2840. {
  2841. _JumpError(hr, error, "ldap_first_entry");
  2842. }
  2843. ppwszValues = ldap_get_values(pld, pres, wszDSDNATTRIBUTE);
  2844. if (NULL == ppwszValues || NULL == ppwszValues[0])
  2845. {
  2846. _JumpError(hr, error, "ldap_get_values");
  2847. }
  2848. hr = myDupString(ppwszValues[0], ppwszDN);
  2849. _JumpIfError(hr, error, "myDupString");
  2850. *pdwDisposition = LDAP_SUCCESS;
  2851. error:
  2852. if (NULL != ppwszValues)
  2853. {
  2854. ldap_value_free(ppwszValues);
  2855. }
  2856. if (NULL != pmsg)
  2857. {
  2858. ldap_msgfree(pmsg);
  2859. }
  2860. return(hr);
  2861. }
  2862. HRESULT
  2863. coreGetEMailNameFromDN(
  2864. IN LDAP *pld,
  2865. IN WCHAR const *pwszDN,
  2866. OUT WCHAR **ppwszEMailName,
  2867. OUT DWORD *pdwDisposition,
  2868. OPTIONAL OUT WCHAR **ppwszError)
  2869. {
  2870. HRESULT hr;
  2871. DWORD cres;
  2872. LDAP_TIMEVAL timeval;
  2873. LDAPMessage *pmsg = NULL;
  2874. LDAPMessage *pres;
  2875. WCHAR *apwszAttrs[2];
  2876. WCHAR **ppwszValues = NULL;
  2877. *pdwDisposition = LDAP_OTHER;
  2878. if (NULL != ppwszError)
  2879. {
  2880. *ppwszError = NULL;
  2881. }
  2882. apwszAttrs[0] = wszDSMAILATTRIBUTE;
  2883. apwszAttrs[1] = NULL;
  2884. timeval.tv_sec = csecLDAPTIMEOUT;
  2885. timeval.tv_usec = 0;
  2886. hr = ldap_search_st(
  2887. pld, // ld
  2888. const_cast<WCHAR *>(pwszDN), // base
  2889. LDAP_SCOPE_BASE, // scope
  2890. NULL, // filter
  2891. apwszAttrs, // attrs
  2892. FALSE, // attrsonly
  2893. &timeval, // timeout
  2894. &pmsg); // res
  2895. if (S_OK != hr)
  2896. {
  2897. *pdwDisposition = hr;
  2898. hr = myHLdapError(pld, hr, ppwszError);
  2899. _JumpErrorStr(hr, error, "ldap_search_st", pwszDN);
  2900. }
  2901. hr = CERTSRV_E_PROPERTY_EMPTY;
  2902. cres = ldap_count_entries(pld, pmsg);
  2903. if (0 == cres)
  2904. {
  2905. _JumpError(hr, error, "ldap_count_entries");
  2906. }
  2907. pres = ldap_first_entry(pld, pmsg);
  2908. if (NULL == pres)
  2909. {
  2910. _JumpError(hr, error, "ldap_first_entry");
  2911. }
  2912. ppwszValues = ldap_get_values(pld, pres, wszDSMAILATTRIBUTE);
  2913. if (NULL == ppwszValues || NULL == ppwszValues[0])
  2914. {
  2915. _JumpError(hr, error, "ldap_get_values");
  2916. }
  2917. hr = myDupString(ppwszValues[0], ppwszEMailName);
  2918. _JumpIfError(hr, error, "myDupString");
  2919. *pdwDisposition = LDAP_SUCCESS;
  2920. error:
  2921. if (NULL != ppwszValues)
  2922. {
  2923. ldap_value_free(ppwszValues);
  2924. }
  2925. if (NULL != pmsg)
  2926. {
  2927. ldap_msgfree(pmsg);
  2928. }
  2929. return(hr);
  2930. }
  2931. HRESULT
  2932. corePublishCertToForest(
  2933. IN DWORD iForest,
  2934. IN DWORD RequestId,
  2935. OPTIONAL IN WCHAR const *pwszDomainDns, // NULL for 0 < iForest
  2936. OPTIONAL IN WCHAR const *pwszDN, // NULL for 0 < iForest
  2937. OPTIONAL IN WCHAR const *pwszEMailName, // NULL for 0 == iForest
  2938. IN CERT_CONTEXT const *pcc,
  2939. IN DWORD dwObjectType, // LPC_*
  2940. OPTIONAL OUT WCHAR **ppwszEMailName) // NULL for 0 < iForest
  2941. {
  2942. HRESULT hr;
  2943. LDAPCACHE *plc = NULL;
  2944. DWORD dwDisposition;
  2945. WCHAR *pwszContactDN = NULL;
  2946. WCHAR *pwszError = NULL;
  2947. if (NULL != ppwszEMailName)
  2948. {
  2949. *ppwszEMailName = NULL;
  2950. }
  2951. hr = S_OK;
  2952. __try
  2953. {
  2954. for (;;)
  2955. {
  2956. BOOL fCached;
  2957. if (NULL != pwszError)
  2958. {
  2959. LocalFree(pwszError);
  2960. pwszError = NULL;
  2961. }
  2962. if (NULL != plc)
  2963. {
  2964. coreLdapUnbind(plc);
  2965. plc = NULL;
  2966. //coreLdapEmptyCache(iForest);
  2967. }
  2968. hr = coreLdapGetHandle(iForest, pwszDomainDns, &plc, &fCached);
  2969. _LeaveIfError(hr, "coreLdapGetHandle");
  2970. if (NULL != pwszEMailName)
  2971. {
  2972. CSASSERT(NULL == pwszDN);
  2973. hr = coreGetDNFromEMailName(
  2974. plc->pld,
  2975. pwszEMailName,
  2976. &pwszContactDN,
  2977. &dwDisposition,
  2978. &pwszError);
  2979. _PrintIfErrorStr(
  2980. hr,
  2981. fCached?
  2982. "coreGetDNFromEMailName(cached)" :
  2983. "coreGetDNFromEMailName(noncached)",
  2984. pwszDN);
  2985. if (!fCached ||
  2986. !myLdapRebindRequired(dwDisposition, plc->pld))
  2987. {
  2988. _LeaveIfError(hr, "myLdapPublishCertToDS");
  2989. }
  2990. if (S_OK == hr)
  2991. {
  2992. pwszDN = pwszContactDN;
  2993. }
  2994. }
  2995. hr = myLdapPublishCertToDS(
  2996. plc->pld,
  2997. pcc,
  2998. pwszDN,
  2999. wszDSUSERCERTATTRIBUTE,
  3000. dwObjectType, // LPC_*
  3001. FALSE, // fDelete
  3002. &dwDisposition,
  3003. &pwszError);
  3004. if (S_OK == hr)
  3005. {
  3006. break;
  3007. }
  3008. _PrintErrorStr(
  3009. hr,
  3010. fCached?
  3011. "myLdapPublishCertToDS(cached)" :
  3012. "myLdapPublishCertToDS(noncached)",
  3013. pwszDN);
  3014. if (!fCached ||
  3015. !myLdapRebindRequired(dwDisposition, plc->pld))
  3016. {
  3017. _LeaveError(hr, "myLdapPublishCertToDS");
  3018. }
  3019. }
  3020. if (NULL != ppwszEMailName)
  3021. {
  3022. hr = coreGetEMailNameFromDN(
  3023. plc->pld,
  3024. pwszDN,
  3025. ppwszEMailName,
  3026. &dwDisposition,
  3027. &pwszError);
  3028. _PrintIfErrorStr(hr, "coreGetEMailNameFromDN", pwszDN);
  3029. }
  3030. }
  3031. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  3032. {
  3033. _PrintError(hr, "Exception");
  3034. }
  3035. //error:
  3036. if (S_OK != hr)
  3037. {
  3038. coreLogPublishError(
  3039. RequestId,
  3040. NULL != plc? plc->pld : NULL,
  3041. pwszDN,
  3042. FALSE, // fDelete
  3043. pwszError,
  3044. hr);
  3045. }
  3046. if (NULL != plc)
  3047. {
  3048. coreLdapReleaseHandle(iForest, plc);
  3049. }
  3050. if (NULL != pwszContactDN)
  3051. {
  3052. LocalFree(pwszContactDN);
  3053. }
  3054. if (NULL != pwszError)
  3055. {
  3056. LocalFree(pwszError);
  3057. }
  3058. return(hr);
  3059. }
  3060. HRESULT
  3061. coreGetDomainDnsNameFromDN(
  3062. IN WCHAR const *pwszDN,
  3063. OUT WCHAR **ppwszDomainDns)
  3064. {
  3065. HRESULT hr;
  3066. DS_NAME_RESULT *pNameResults = NULL;
  3067. WCHAR const *pwc;
  3068. DWORD cwc;
  3069. CSASSERT(NULL != ppwszDomainDns);
  3070. *ppwszDomainDns = NULL;
  3071. hr = DsCrackNames(
  3072. NULL, // hDS
  3073. DS_NAME_FLAG_SYNTACTICAL_ONLY,
  3074. DS_FQDN_1779_NAME,
  3075. DS_CANONICAL_NAME,
  3076. 1, // one name
  3077. &pwszDN, // one name (IN)
  3078. &pNameResults); // OUT
  3079. if (S_OK != hr)
  3080. {
  3081. hr = myHError(hr);
  3082. _JumpError(hr, error, "DsCrackNames");
  3083. }
  3084. if (1 > pNameResults->cItems ||
  3085. DS_NAME_NO_ERROR != pNameResults->rItems[0].status)
  3086. {
  3087. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  3088. _JumpError(hr, error, "DsCrackNames result");
  3089. }
  3090. pwc = wcschr(pNameResults->rItems[0].pName, L'/');
  3091. if (NULL == pwc)
  3092. {
  3093. cwc = wcslen(pNameResults->rItems[0].pName);
  3094. }
  3095. else
  3096. {
  3097. cwc = SAFE_SUBTRACT_POINTERS(pwc, pNameResults->rItems[0].pName);
  3098. }
  3099. *ppwszDomainDns = (WCHAR *) LocalAlloc(
  3100. LMEM_FIXED,
  3101. (cwc + 1) * sizeof(WCHAR));
  3102. if (NULL == *ppwszDomainDns)
  3103. {
  3104. hr = E_OUTOFMEMORY;
  3105. _JumpError(hr, error, "LocalAlloc");
  3106. }
  3107. CopyMemory(
  3108. *ppwszDomainDns,
  3109. pNameResults->rItems[0].pName,
  3110. cwc * sizeof(WCHAR));
  3111. (*ppwszDomainDns)[cwc] = L'\0';
  3112. error:
  3113. if (NULL != pNameResults)
  3114. {
  3115. DsFreeNameResult(pNameResults);
  3116. }
  3117. return(hr);
  3118. }
  3119. HRESULT
  3120. corePublishUserCertificate(
  3121. IN DWORD RequestId,
  3122. IN DWORD dwComContextIndex,
  3123. IN WCHAR const *pwszSamName,
  3124. IN CERT_CONTEXT const *pcc,
  3125. IN DWORD dwObjectType) // LPC_*
  3126. {
  3127. HRESULT hr;
  3128. WCHAR *pwszSamNamePatched = NULL;
  3129. WCHAR *pwszDomainDns = NULL;
  3130. WCHAR const *pwszUserName;
  3131. WCHAR const *pwszDN;
  3132. WCHAR *pwszEMailName = NULL;
  3133. DWORD i;
  3134. hr = myAddDomainName(pwszSamName, &pwszSamNamePatched, &pwszUserName);
  3135. _JumpIfError(hr, error, "myAddDomainName");
  3136. if (NULL != pwszSamNamePatched)
  3137. {
  3138. pwszSamName = pwszSamNamePatched;
  3139. }
  3140. hr = coreGetComContextUserDNFromSamName(
  3141. FALSE, // fDeleteUserDNOnly
  3142. pwszSamName,
  3143. 0, // Context
  3144. dwComContextIndex,
  3145. &pwszDN);
  3146. _JumpIfError(hr, error, "coreGetComContextUserDNFromSamName");
  3147. hr = coreGetDomainDnsNameFromDN(pwszDN, &pwszDomainDns);
  3148. _JumpIfError(hr, error, "coreGetDomainDnsNameFromDN");
  3149. // For the domestic forest, pass the User object's native domain and DN,
  3150. // and collect the EMail name (if any alternate forests were specified).
  3151. hr = corePublishCertToForest(
  3152. 0, // iForest
  3153. RequestId,
  3154. pwszDomainDns,
  3155. pwszDN,
  3156. NULL, // pwszEMailName
  3157. pcc,
  3158. dwObjectType, // LPC_*
  3159. 1 < g_cForestLdapCache? &pwszEMailName : NULL);
  3160. _PrintIfError(hr, "corePublishCertToForest");
  3161. // For alternate forests, pass a NULL domain, the Contact object's EMail
  3162. // name, and do not collect the EMail name.
  3163. for (i = 1; i < g_cForestLdapCache; i++)
  3164. {
  3165. if (NULL == pwszEMailName)
  3166. {
  3167. break; // EMail name needed to publish to alternate Forests
  3168. }
  3169. hr = corePublishCertToForest(
  3170. i, // iForest
  3171. RequestId,
  3172. NULL, // pwszDomainDns
  3173. NULL, // pwszDN
  3174. pwszEMailName,
  3175. pcc,
  3176. dwObjectType, // LPC_*
  3177. NULL); // ppwszEMailName
  3178. _PrintIfError(hr, "corePublishCertToForest");
  3179. }
  3180. error:
  3181. if (NULL != pwszEMailName)
  3182. {
  3183. LocalFree(pwszEMailName);
  3184. }
  3185. if (NULL != pwszDomainDns)
  3186. {
  3187. LocalFree(pwszDomainDns);
  3188. }
  3189. if (NULL != pwszSamNamePatched)
  3190. {
  3191. LocalFree(pwszSamNamePatched);
  3192. }
  3193. return(hr);
  3194. }
  3195. HRESULT
  3196. CorePublishCertificate(
  3197. IN ICertDBRow *prow,
  3198. IN DWORD dwComContextIndex)
  3199. {
  3200. HRESULT hr;
  3201. DWORD cbProp;
  3202. DWORD RequestId;
  3203. DWORD GeneralFlags;
  3204. DWORD EnrollmentFlags;
  3205. DWORD cbCert;
  3206. BYTE *pbCert = NULL;
  3207. CERT_CONTEXT const *pcc = NULL;
  3208. WCHAR *pwszSamName = NULL;
  3209. prow->GetRowId(&RequestId);
  3210. cbProp = sizeof(EnrollmentFlags);
  3211. hr = prow->GetProperty(
  3212. wszPROPCERTIFICATEENROLLMENTFLAGS,
  3213. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3214. NULL,
  3215. &cbProp,
  3216. (BYTE *) &EnrollmentFlags);
  3217. _PrintIfError2(hr, "GetProperty", CERTSRV_E_PROPERTY_EMPTY);
  3218. if (S_OK != hr)
  3219. {
  3220. EnrollmentFlags = 0;
  3221. }
  3222. if (0 == ((CT_FLAG_PUBLISH_TO_DS | CT_FLAG_PUBLISH_TO_KRA_CONTAINER) &
  3223. EnrollmentFlags))
  3224. {
  3225. hr = S_OK;
  3226. goto error;
  3227. }
  3228. cbProp = sizeof(GeneralFlags);
  3229. hr = prow->GetProperty(
  3230. wszPROPCERTIFICATEGENERALFLAGS,
  3231. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3232. NULL,
  3233. &cbProp,
  3234. (BYTE *) &GeneralFlags);
  3235. _PrintIfError2(hr, "GetProperty", CERTSRV_E_PROPERTY_EMPTY);
  3236. if (S_OK != hr)
  3237. {
  3238. GeneralFlags = 0;
  3239. }
  3240. // Get the name of the user or machine
  3241. hr = PKCSGetProperty(
  3242. prow,
  3243. g_wszPropRequesterName,
  3244. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3245. NULL,
  3246. (BYTE **) &pwszSamName);
  3247. _JumpIfError(hr, error, "PKCSGetProperty");
  3248. hr = PKCSGetProperty(
  3249. prow,
  3250. g_wszPropRawCertificate,
  3251. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3252. &cbCert,
  3253. &pbCert);
  3254. _JumpIfError(hr, error, "PKCSGetProperty(raw cert)");
  3255. pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
  3256. if (NULL == pcc)
  3257. {
  3258. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3259. _JumpError(hr, error, "CertCreateCertificateContext");
  3260. }
  3261. hr = S_OK;
  3262. if (CT_FLAG_PUBLISH_TO_DS & EnrollmentFlags)
  3263. {
  3264. if (CT_FLAG_IS_CROSS_CA & GeneralFlags)
  3265. {
  3266. hr = CorePublishCrossCertificate(
  3267. RequestId,
  3268. pcc,
  3269. TRUE, // fCreateDSObject
  3270. FALSE); // fDelete
  3271. _PrintIfError(hr, "CorePublishCrossCertificate"); // DS object if necessary
  3272. }
  3273. else
  3274. {
  3275. hr = corePublishUserCertificate(
  3276. RequestId,
  3277. dwComContextIndex,
  3278. pwszSamName,
  3279. pcc,
  3280. (CT_FLAG_MACHINE_TYPE & GeneralFlags)?
  3281. LPC_MACHINEOBJECT : LPC_USEROBJECT);
  3282. _PrintIfError(hr, "corePublishUserCertificate");
  3283. }
  3284. }
  3285. if (CT_FLAG_PUBLISH_TO_KRA_CONTAINER & EnrollmentFlags)
  3286. {
  3287. HRESULT hr2;
  3288. hr2 = corePublishKRACertificate(RequestId, pcc);
  3289. _PrintIfError(hr2, "corePublishKRACertificate");
  3290. if (S_OK == hr)
  3291. {
  3292. hr = hr2;
  3293. }
  3294. }
  3295. _JumpIfError(hr, error, "CorePublishCertificate");
  3296. error:
  3297. if (NULL != pwszSamName)
  3298. {
  3299. LocalFree(pwszSamName);
  3300. }
  3301. if (NULL != pcc)
  3302. {
  3303. CertFreeCertificateContext(pcc);
  3304. }
  3305. if (NULL != pbCert)
  3306. {
  3307. LocalFree(pbCert);
  3308. }
  3309. return(hr);
  3310. }
  3311. HRESULT
  3312. coreAcceptRequest(
  3313. IN ICertDBRow *prow,
  3314. IN BOOL fIncludeCRLs,
  3315. IN DWORD dwComContextIndex,
  3316. OUT BOOL *pfErrorLogged,
  3317. OUT CACTX **ppCAContext,
  3318. IN OUT CERTSRV_RESULT_CONTEXT *pResult, // CoTaskMem*
  3319. OUT WCHAR **ppwszDispositionCreateCert,
  3320. OUT HRESULT *phrPublish)
  3321. {
  3322. HRESULT hr;
  3323. *ppCAContext = NULL;
  3324. *ppwszDispositionCreateCert = NULL;
  3325. *phrPublish = S_OK;
  3326. // Force Cert creation:
  3327. CSASSERT(NULL == pResult->pctbCert || NULL == pResult->pctbCert->pb);
  3328. hr = CoreValidateRequestId(prow, DB_DISP_ACTIVE);
  3329. _JumpIfError(hr, error, "CoreValidateRequestId");
  3330. hr = PKCSCreateCertificate(
  3331. prow,
  3332. DB_DISP_ACTIVE,
  3333. fIncludeCRLs,
  3334. FALSE, // fAllowCASubject
  3335. NULL, // use default signing CACTX
  3336. pfErrorLogged,
  3337. ppCAContext,
  3338. ppwszDispositionCreateCert,
  3339. pResult);
  3340. _JumpIfError(hr, error, "PKCSCreateCertificate");
  3341. *phrPublish = CorePublishCertificate(prow, dwComContextIndex);
  3342. _PrintIfError(*phrPublish, "CorePublishCertificate");
  3343. if (S_OK != *phrPublish)
  3344. {
  3345. hr = PKCSSetRequestFlags(prow, TRUE, CR_FLG_PUBLISHERROR);
  3346. _JumpIfError(hr, error, "PKCSSetRequestFlags");
  3347. }
  3348. CSASSERT(S_OK == hr);
  3349. error:
  3350. return(hr);
  3351. }
  3352. HRESULT
  3353. coreVerifyRequest(
  3354. IN OUT ICertDBRow **pprow,
  3355. IN DWORD OpRequest,
  3356. IN BOOL fIncludeCRLs,
  3357. OPTIONAL IN WCHAR const *pwszUserName,
  3358. IN DWORD dwComContextIndex,
  3359. OUT DWORD *pReqId,
  3360. OUT LONG *pExitEvent,
  3361. OUT WCHAR **ppwszDisposition, // LocalAlloc
  3362. OUT CACTX **ppCAContext,
  3363. IN OUT CERTSRV_RESULT_CONTEXT *pResult) // CoTaskMem*
  3364. {
  3365. HRESULT hr;
  3366. HRESULT hr2;
  3367. HRESULT hrRequest = S_OK;
  3368. HRESULT hrPublish = S_OK;
  3369. DWORD VerifyStatus;
  3370. DWORD DBDisposition;
  3371. BOOL fResolved;
  3372. LONG ExitEvent;
  3373. BOOL fPending;
  3374. BOOL fSubmit;
  3375. BOOL fRetrieve;
  3376. BOOL fDenied;
  3377. BOOL fUpdateDisposition = FALSE;
  3378. WCHAR *pwszDispositionCreateCert = NULL;
  3379. WCHAR *pwszDispositionRetrieved = NULL;
  3380. WCHAR const *pwszDispositionBase = NULL;
  3381. WCHAR *pwszDispositionDetail = NULL;
  3382. WCHAR *pwszDisposition = NULL;
  3383. WCHAR const *pwszBy = NULL;
  3384. DWORD LogMsg = MSG_E_PROCESS_REQUEST_FAILED;
  3385. BOOL fErrorLogged = FALSE;
  3386. DWORD ReqId;
  3387. ICertDBRow *prow = *pprow;
  3388. prow->GetRowId(&ReqId);
  3389. *ppCAContext = NULL;
  3390. *pResult->pdwDisposition = CR_DISP_ERROR;
  3391. DBDisposition = DB_DISP_ERROR;
  3392. *ppwszDisposition = NULL;
  3393. ExitEvent = EXITEVENT_INVALID;
  3394. fSubmit = CR_IN_NEW == OpRequest || CR_IN_RESUBMIT == OpRequest;
  3395. fPending = CR_IN_DENY == OpRequest || CR_IN_RESUBMIT == OpRequest;
  3396. fRetrieve = CR_IN_RETRIEVE == OpRequest;
  3397. #if DBG_COMTEST
  3398. if (fSubmit && fComTest && !ComTest((LONG) ReqId))
  3399. {
  3400. _PrintError(0, "ComTest");
  3401. }
  3402. #endif
  3403. if (fRetrieve)
  3404. {
  3405. hr = coreCheckRetrieveAccessRight(
  3406. prow,
  3407. pwszUserName);
  3408. _JumpIfError(hr, error, "coreCheckRetrieveAccessRight");
  3409. hr = coreRetrievePending(
  3410. prow,
  3411. fIncludeCRLs,
  3412. &pwszDispositionRetrieved,
  3413. ppCAContext,
  3414. pResult); // CoTaskMem*
  3415. _JumpIfError(hr, error, "coreRetrievePending");
  3416. pwszDispositionBase = pwszDispositionRetrieved;
  3417. ExitEvent = EXITEVENT_CERTRETRIEVEPENDING;
  3418. }
  3419. else
  3420. {
  3421. // If the current status is expected to be pending, verify that now,
  3422. // and make the request active.
  3423. //
  3424. // If it was already marked active, then something went wrong last time
  3425. // we processed the request (out of disk space?), and we can try to
  3426. // pick up where we left off, by resubmitting or denying the request.
  3427. if (fPending)
  3428. {
  3429. hr = CoreValidateRequestId(prow, DB_DISP_PENDING);
  3430. if (CERTSRV_E_BAD_REQUESTSTATUS == hr)
  3431. {
  3432. hr = CoreValidateRequestId(prow, DB_DISP_ACTIVE);
  3433. }
  3434. if (CERTSRV_E_BAD_REQUESTSTATUS == hr && fSubmit)
  3435. {
  3436. hr = CoreValidateRequestId(prow, DB_DISP_DENIED);
  3437. if (S_OK == hr)
  3438. {
  3439. DBGPRINT((
  3440. DBG_SS_CERTSRV,
  3441. "Resubmit failed request %u\n",
  3442. ReqId));
  3443. pResult->dwResultFlags |= CRCF_PREVIOUSLYDENIED;
  3444. if (CRCF_FAILDENIEDREQUEST & pResult->dwResultFlags)
  3445. {
  3446. hr = CERTSRV_E_BAD_REQUESTSTATUS;
  3447. }
  3448. }
  3449. }
  3450. _JumpIfError(hr, error, "CoreValidateRequestId");
  3451. hr = CoreSetDisposition(prow, DB_DISP_ACTIVE);
  3452. _JumpIfError(hr, error, "CoreSetDisposition");
  3453. }
  3454. fUpdateDisposition = TRUE;
  3455. if (fSubmit)
  3456. {
  3457. if (fPending)
  3458. {
  3459. pwszBy = g_pwszResubmittedBy;
  3460. hr = PKCSSetServerProperties(
  3461. prow,
  3462. NULL, // use default signing CACTX
  3463. NULL, // pftNotBefore
  3464. NULL, // pftNotAfter
  3465. g_lValidityPeriodCount,
  3466. g_enumValidityPeriod);
  3467. _JumpIfError(hr, error, "PKCSSetServerProperties");
  3468. }
  3469. hr = prow->CommitTransaction(TRUE);
  3470. _JumpIfError(hr, error, "CommitTransaction");
  3471. prow->Release();
  3472. prow = NULL;
  3473. *pprow = NULL;
  3474. hr = PolicyVerifyRequest(
  3475. g_wszCommonName,
  3476. ReqId,
  3477. g_PolicyFlags,
  3478. CR_IN_NEW == OpRequest,
  3479. CR_IN_NEW == OpRequest? pResult : NULL,
  3480. dwComContextIndex,
  3481. &pwszDispositionDetail,
  3482. &VerifyStatus);
  3483. if (S_OK != hr)
  3484. {
  3485. _PrintError(hr, "PolicyVerifyRequest");
  3486. if (SUCCEEDED(hr))
  3487. {
  3488. if (S_FALSE == hr)
  3489. {
  3490. hr = E_UNEXPECTED;
  3491. }
  3492. else
  3493. {
  3494. hr = myHError(hr);
  3495. }
  3496. }
  3497. VerifyStatus = hr;
  3498. }
  3499. hr = g_pCertDB->OpenRow(PROPTABLE_REQCERT, ReqId, NULL, &prow);
  3500. _JumpIfError(hr, error, "OpenRow");
  3501. CSASSERT(NULL != prow);
  3502. *pprow = prow;
  3503. }
  3504. else // else we're denying the request!
  3505. {
  3506. VerifyStatus = VR_INSTANT_BAD;
  3507. }
  3508. fResolved = FALSE;
  3509. fDenied = FALSE;
  3510. switch (VerifyStatus)
  3511. {
  3512. case VR_PENDING:
  3513. hr = S_OK;
  3514. DBDisposition = DB_DISP_PENDING;
  3515. ExitEvent = EXITEVENT_CERTPENDING;
  3516. LogMsg = MSG_DN_CERT_PENDING;
  3517. *pResult->pdwDisposition = CR_DISP_UNDER_SUBMISSION;
  3518. pwszDispositionBase = g_pwszUnderSubmission;
  3519. break;
  3520. case VR_INSTANT_OK:
  3521. hr = coreAcceptRequest(
  3522. prow,
  3523. fIncludeCRLs,
  3524. dwComContextIndex,
  3525. &fErrorLogged,
  3526. ppCAContext,
  3527. pResult,
  3528. &pwszDispositionCreateCert,
  3529. &hrPublish);
  3530. if (S_OK != hr)
  3531. {
  3532. CSASSERT(FAILED(hr));
  3533. _PrintError(hr, "coreAcceptRequest");
  3534. pwszDispositionBase = g_pwszCertConstructionError;
  3535. VerifyStatus = hr;
  3536. hr = S_OK;
  3537. fDenied = TRUE;
  3538. }
  3539. else
  3540. {
  3541. fResolved = TRUE;
  3542. DBDisposition = DB_DISP_ISSUED;
  3543. ExitEvent = EXITEVENT_CERTISSUED;
  3544. LogMsg = MSG_DN_CERT_ISSUED;
  3545. *pResult->pdwDisposition = CR_DISP_ISSUED;
  3546. pwszDispositionBase = g_pwszIssued;
  3547. }
  3548. break;
  3549. default:
  3550. if (SUCCEEDED(VerifyStatus))
  3551. {
  3552. CSASSERT(
  3553. VerifyStatus == VR_PENDING ||
  3554. VerifyStatus == VR_INSTANT_OK ||
  3555. VerifyStatus == VR_INSTANT_BAD);
  3556. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  3557. _JumpError(hr, error, "VerifyStatus");
  3558. }
  3559. // FALLTHROUGH
  3560. case VR_INSTANT_BAD:
  3561. hr = CoreValidateRequestId(prow, DB_DISP_ACTIVE);
  3562. _JumpIfError(hr, error, "CoreValidateRequestId");
  3563. fDenied = TRUE;
  3564. break;
  3565. }
  3566. if (fDenied)
  3567. {
  3568. fResolved = TRUE;
  3569. DBDisposition = DB_DISP_DENIED;
  3570. ExitEvent = EXITEVENT_CERTDENIED;
  3571. *pResult->pdwDisposition = CR_DISP_DENIED;
  3572. if (FAILED(VerifyStatus))
  3573. {
  3574. *pResult->pdwDisposition = VerifyStatus;
  3575. hrRequest = VerifyStatus;
  3576. }
  3577. if (fSubmit)
  3578. {
  3579. if (NULL == pwszDispositionBase)
  3580. {
  3581. pwszDispositionBase = g_pwszPolicyDeniedRequest;
  3582. }
  3583. LogMsg = MSG_DN_CERT_DENIED;
  3584. }
  3585. else
  3586. {
  3587. pwszDispositionBase = g_pwszDeniedBy;
  3588. LogMsg = MSG_DN_CERT_ADMIN_DENIED;
  3589. }
  3590. }
  3591. if (fResolved)
  3592. {
  3593. hr = PropSetRequestTimeProperty(prow, g_wszPropRequestResolvedWhen);
  3594. _JumpIfError(hr, error, "PropSetRequestTimeProperty");
  3595. }
  3596. }
  3597. error:
  3598. *pReqId = ReqId;
  3599. *pExitEvent = ExitEvent;
  3600. // If we verified or denied the request, set the status & disposition
  3601. // Build the full disposition string
  3602. pwszDisposition = CoreBuildDispositionString(
  3603. pwszDispositionBase,
  3604. pwszUserName,
  3605. pwszDispositionDetail,
  3606. pwszDispositionCreateCert,
  3607. pwszBy,
  3608. hrPublish,
  3609. TRUE);
  3610. if (NULL != pwszDispositionDetail)
  3611. {
  3612. LocalFree(pwszDispositionDetail);
  3613. }
  3614. if (S_OK == hrRequest && S_OK != hr)
  3615. {
  3616. hrRequest = hr;
  3617. }
  3618. if (fUpdateDisposition && NULL != prow)
  3619. {
  3620. hr2 = CoreSetRequestDispositionFields(
  3621. prow,
  3622. hrRequest,
  3623. DBDisposition,
  3624. pwszDisposition);
  3625. if (S_OK == hr)
  3626. {
  3627. hr = hr2;
  3628. }
  3629. }
  3630. if (!fErrorLogged &&
  3631. NULL != prow &&
  3632. (fUpdateDisposition || S_OK != hr))
  3633. {
  3634. CoreLogRequestStatus(prow, LogMsg, hrRequest, pwszDisposition);
  3635. }
  3636. if (NULL != ppwszDisposition)
  3637. {
  3638. *ppwszDisposition = pwszDisposition;
  3639. }
  3640. else if (NULL != pwszDisposition)
  3641. {
  3642. LocalFree(pwszDisposition);
  3643. }
  3644. if (NULL != pwszDispositionRetrieved)
  3645. {
  3646. LocalFree(pwszDispositionRetrieved);
  3647. }
  3648. if (NULL != pwszDispositionCreateCert)
  3649. {
  3650. LocalFree(pwszDispositionCreateCert);
  3651. }
  3652. return(hr);
  3653. }
  3654. HRESULT
  3655. coreAuditAddStringProperty(
  3656. IN ICertDBRow *prow,
  3657. IN WCHAR const *pwszPropName,
  3658. IN CertSrv::CAuditEvent *pevent)
  3659. {
  3660. HRESULT hr;
  3661. WCHAR const *pwszLogValue = L"";
  3662. WCHAR *pwszPropValue = NULL;
  3663. hr = PKCSGetProperty(
  3664. prow,
  3665. pwszPropName,
  3666. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_CERTIFICATE,
  3667. NULL,
  3668. (BYTE **) &pwszPropValue);
  3669. _PrintIfErrorStr2(hr, "PKCSGetProperty", pwszPropName, CERTSRV_E_PROPERTY_EMPTY);
  3670. if (S_OK == hr)
  3671. {
  3672. pwszLogValue = pwszPropValue;
  3673. }
  3674. hr = pevent->AddData(pwszLogValue);
  3675. _JumpIfError(hr, error, "CAuditEvent::AddData");
  3676. error:
  3677. if (NULL != pwszPropValue)
  3678. {
  3679. LocalFree(pwszPropValue);
  3680. }
  3681. return(hr);
  3682. }
  3683. HRESULT
  3684. coreAuditRequestDisposition(
  3685. OPTIONAL IN ICertDBRow *prow,
  3686. IN DWORD ReqId,
  3687. IN WCHAR const *pwszUserName,
  3688. IN WCHAR const *pwszAttributes,
  3689. IN DWORD dwDisposition)
  3690. {
  3691. HRESULT hr;
  3692. CertSrv::CAuditEvent
  3693. audit(0, g_dwAuditFilter);
  3694. hr = audit.AddData(ReqId); // %1 request ID
  3695. _JumpIfError(hr, error, "CAuditEvent::AddData");
  3696. hr = audit.AddData(pwszUserName); // %2 requester
  3697. _JumpIfError(hr, error, "CAuditEvent::AddData");
  3698. hr = audit.AddData(pwszAttributes); // %3 attributes
  3699. _JumpIfError(hr, error, "CAuditEvent::AddData");
  3700. hr = audit.AddData(dwDisposition); // %4 disposition
  3701. _JumpIfError(hr, error, "CAuditEvent::AddData");
  3702. if (NULL != prow)
  3703. {
  3704. hr = coreAuditAddStringProperty(
  3705. prow,
  3706. g_wszPropCertificateSubjectKeyIdentifier,
  3707. &audit); // %5 SKI
  3708. _JumpIfError(hr, error, "coreAuditAddStringProperty");
  3709. hr = coreAuditAddStringProperty(
  3710. prow,
  3711. g_wszPropSubjectDistinguishedName,
  3712. &audit); // %6 Subject
  3713. _JumpIfError(hr, error, "coreAuditAddStringProperty");
  3714. }
  3715. else // we need to guarantee the same number of audit params
  3716. {
  3717. hr = audit.AddData(L""); // %5 SKI
  3718. _JumpIfError(hr, error, "");
  3719. hr = audit.AddData(L""); // %6 Subject
  3720. _JumpIfError(hr, error, "");
  3721. }
  3722. switch (dwDisposition)
  3723. {
  3724. case CR_DISP_ISSUED:
  3725. audit.SetEventID(SE_AUDITID_CERTSRV_REQUESTAPPROVED);
  3726. hr = audit.Report();
  3727. _JumpIfError(hr, error, "CAuditEvent::Report");
  3728. break;
  3729. case CR_DISP_UNDER_SUBMISSION:
  3730. audit.SetEventID(SE_AUDITID_CERTSRV_REQUESTPENDING);
  3731. hr = audit.Report();
  3732. _JumpIfError(hr, error, "CAuditEvent::Report");
  3733. break;
  3734. case CR_DISP_DENIED: // fail over
  3735. default:
  3736. audit.SetEventID(SE_AUDITID_CERTSRV_REQUESTDENIED);
  3737. hr = audit.Report(false);
  3738. _JumpIfError(hr, error, "CAuditEvent::Report");
  3739. break;
  3740. }
  3741. CSASSERT(S_OK == hr);
  3742. error:
  3743. return(hr);
  3744. }
  3745. HRESULT
  3746. coreValidateMessageSize(
  3747. IN OPTIONAL LPCWSTR pwszUser,
  3748. IN DWORD cbRequest)
  3749. {
  3750. HRESULT hr = S_OK;
  3751. if (cbRequest > g_cbMaxIncomingMessageSize)
  3752. {
  3753. hr = HRESULT_FROM_WIN32(ERROR_MESSAGE_EXCEEDS_MAX_SIZE);
  3754. if (CERTLOG_VERBOSE <= g_dwLogLevel)
  3755. {
  3756. LogEventStringHResult(
  3757. EVENTLOG_ERROR_TYPE,
  3758. MSG_E_POSSIBLE_DENIAL_OF_SERVICE_ATTACK,
  3759. NULL != pwszUser? pwszUser : g_pwszUnknownSubject,
  3760. hr);
  3761. }
  3762. }
  3763. return(hr);
  3764. }
  3765. HRESULT
  3766. coreInitRequest(
  3767. IN DWORD dwFlags,
  3768. OPTIONAL IN WCHAR const *pwszUserName,
  3769. IN DWORD cbRequest,
  3770. OPTIONAL IN BYTE const *pbRequest,
  3771. OPTIONAL IN WCHAR const *pwszAttributes,
  3772. OPTIONAL IN WCHAR const *pwszSerialNumber,
  3773. IN DWORD dwComContextIndex,
  3774. OUT DWORD *pOpRequest,
  3775. OUT ICertDBRow **pprow, // may return non-NULL on error
  3776. OUT WCHAR **ppwszDisposition,
  3777. IN OUT CERTSRV_RESULT_CONTEXT *pResult)
  3778. {
  3779. HRESULT hr;
  3780. *pprow = NULL;
  3781. *ppwszDisposition = NULL;
  3782. // for Denial-of-Service reasons, don't do anything with a too-long message
  3783. hr = coreValidateMessageSize(pwszUserName, cbRequest);
  3784. _JumpIfError(hr, error, "coreValidateMessageSize");
  3785. // Called in several cases:
  3786. //
  3787. // - CR_IN_NEW: Create a new request and return error/pending/etc &
  3788. // possibly the cert:
  3789. // NULL != pbRequest && NULL != pResult->pctbCert, etc.
  3790. //
  3791. // - CR_IN_DENY: Deny a pending request:
  3792. // NULL == pbRequest && NULL == pResult->pctbCert, etc.
  3793. //
  3794. // - CR_IN_RESUBMIT: Resubmit a pending request and return hr/pending/etc.
  3795. // NULL == pbRequest && NULL == pResult->pctbCert, etc.
  3796. //
  3797. // - CR_IN_RETRIEVE: Retrieve a cert for a processed request and return
  3798. // error/pending/etc & possibly the cert:
  3799. // NULL == pbRequest && NULL != pResult->pctbCert, etc.
  3800. *pOpRequest = (CR_IN_COREMASK & dwFlags);
  3801. switch (*pOpRequest)
  3802. {
  3803. // Process a new request:
  3804. case CR_IN_NEW:
  3805. CSASSERT(NULL != pwszUserName);
  3806. CSASSERT(0 != cbRequest);
  3807. CSASSERT(NULL != pbRequest);
  3808. CSASSERT(0 == *pResult->pdwRequestId);
  3809. *pResult->pdwRequestId = 0;
  3810. hr = coreCreateRequest(
  3811. ~CR_IN_COREMASK & dwFlags,
  3812. pwszUserName,
  3813. cbRequest,
  3814. pbRequest,
  3815. pwszAttributes,
  3816. dwComContextIndex,
  3817. pprow,
  3818. pResult);
  3819. _JumpIfError(hr, error, "coreCreateRequest");
  3820. (*pprow)->GetRowId(pResult->pdwRequestId);
  3821. {
  3822. CertSrv::CAuditEvent
  3823. audit(SE_AUDITID_CERTSRV_NEWREQUEST, g_dwAuditFilter);
  3824. hr = audit.AddData(*pResult->pdwRequestId); // %1 request ID
  3825. _JumpIfError(hr, error, "CAuditEvent::AddData");
  3826. hr = audit.AddData(pwszUserName); // %2 requester
  3827. _JumpIfError(hr, error, "CAuditEvent::AddData");
  3828. hr = audit.AddData(pwszAttributes); // %3 attributes
  3829. _JumpIfError(hr, error, "CAuditEvent::AddData");
  3830. hr = audit.Report();
  3831. _JumpIfError(hr, error, "CAuditEvent::Report");
  3832. }
  3833. break;
  3834. // Deny a request:
  3835. // Resubmit a request:
  3836. case CR_IN_DENY:
  3837. case CR_IN_RESUBMIT:
  3838. break;
  3839. // Retrieve a cert:
  3840. case CR_IN_RETRIEVE:
  3841. break;
  3842. default:
  3843. CSASSERT(*pOpRequest != *pOpRequest);
  3844. break;
  3845. }
  3846. if (CR_IN_NEW != *pOpRequest)
  3847. {
  3848. hr = E_INVALIDARG;
  3849. if (0 != cbRequest || NULL != pbRequest)
  3850. {
  3851. _JumpError(hr, error, "unexpected request");
  3852. }
  3853. if ((0 != *pResult->pdwRequestId) ^ (NULL == pwszSerialNumber))
  3854. {
  3855. _JumpError(hr, error, "expected RequestId or SerialNumber");
  3856. }
  3857. // RetrievePending by RequestId OR SerialNumber in pwszSerialNumber
  3858. hr = g_pCertDB->OpenRow(
  3859. PROPTABLE_REQCERT,
  3860. *pResult->pdwRequestId,
  3861. pwszSerialNumber,
  3862. pprow);
  3863. _JumpIfError(hr, error, "OpenRow");
  3864. }
  3865. hr = S_OK;
  3866. error:
  3867. if (S_OK != hr)
  3868. {
  3869. HRESULT hr2;
  3870. hr2 = myDupString(
  3871. (CRCF_SIGNATUREERROR & pResult->dwResultFlags)?
  3872. g_pwszRequestSigError :
  3873. ((CRCF_ARCHIVESIGNINGKEYERROR & pResult->dwResultFlags)?
  3874. g_pwszArchiveSigningKeyError :
  3875. ((CRCF_KEYARCHIVALERROR & pResult->dwResultFlags)?
  3876. g_pwszKeyArchivalError :
  3877. g_pwszRequestParsingError)),
  3878. ppwszDisposition);
  3879. _PrintIfError(hr2, "myDupString");
  3880. if (NULL != pResult->pwszExtendedErrorInfo)
  3881. {
  3882. hr2 = myAppendString(
  3883. pResult->pwszExtendedErrorInfo,
  3884. L" ",
  3885. ppwszDisposition);
  3886. _PrintIfError(hr2, "myAppendString");
  3887. }
  3888. if (NULL != *pprow)
  3889. {
  3890. hr2 = CoreSetRequestDispositionFields(
  3891. *pprow,
  3892. hr,
  3893. DB_DISP_ERROR,
  3894. *ppwszDisposition);
  3895. _PrintIfError(hr2, "CoreSetRequestDispositionFields");
  3896. CoreLogRequestStatus(
  3897. *pprow,
  3898. MSG_E_PROCESS_REQUEST_FAILED,
  3899. hr,
  3900. *ppwszDisposition);
  3901. }
  3902. }
  3903. return(hr);
  3904. }
  3905. HRESULT
  3906. CoreProcessRequest(
  3907. IN DWORD dwFlags,
  3908. OPTIONAL IN WCHAR const *pwszUserName,
  3909. IN DWORD cbRequest,
  3910. OPTIONAL IN BYTE const *pbRequest,
  3911. OPTIONAL IN WCHAR const *pwszAttributes,
  3912. OPTIONAL IN WCHAR const *pwszSerialNumber,
  3913. IN DWORD dwComContextIndex,
  3914. IN DWORD dwRequestId,
  3915. OUT CERTSRV_RESULT_CONTEXT *pResult)
  3916. {
  3917. HRESULT hr;
  3918. HRESULT hr2;
  3919. WCHAR *pwszDisposition = NULL;
  3920. DWORD OpRequest;
  3921. ICertDBRow *prow = NULL;
  3922. DWORD ReqId;
  3923. LONG ExitEvent = EXITEVENT_INVALID;
  3924. BOOL fCoInitialized = FALSE;
  3925. CACTX *pCAContext;
  3926. BOOL fCommitted = FALSE;
  3927. CSASSERT(NULL != pResult->pdwRequestId);
  3928. CSASSERT(NULL != pResult->pdwDisposition);
  3929. if (MAXDWORD == dwRequestId)
  3930. {
  3931. dwRequestId = 0;
  3932. }
  3933. *pResult->pdwRequestId = dwRequestId;
  3934. *pResult->pdwDisposition = CR_DISP_ERROR;
  3935. OpRequest = CR_IN_RETRIEVE;
  3936. ReqId = 0;
  3937. hr = CoInitializeEx(NULL, GetCertsrvComThreadingModel());
  3938. if (S_OK != hr && S_FALSE != hr)
  3939. {
  3940. _JumpError(hr, error, "CoInitializeEx");
  3941. }
  3942. fCoInitialized = TRUE;
  3943. hr = coreInitRequest(
  3944. dwFlags,
  3945. pwszUserName,
  3946. cbRequest,
  3947. pbRequest,
  3948. pwszAttributes,
  3949. pwszSerialNumber,
  3950. dwComContextIndex,
  3951. &OpRequest,
  3952. &prow,
  3953. &pwszDisposition,
  3954. pResult);
  3955. _PrintIfError(hr, "coreInitRequest");
  3956. pCAContext = NULL;
  3957. if (S_OK == hr)
  3958. {
  3959. CSASSERT(NULL == pwszDisposition); // error string only
  3960. if (CR_IN_NEW != OpRequest)
  3961. {
  3962. DWORD cb;
  3963. DWORD dw;
  3964. cb = sizeof(dw);
  3965. hr = prow->GetProperty(
  3966. g_wszPropRequestType,
  3967. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  3968. NULL,
  3969. &cb,
  3970. (BYTE *) &dw);
  3971. if (S_OK == hr)
  3972. {
  3973. dwFlags |= (CR_IN_CRLS & dw);
  3974. }
  3975. }
  3976. hr = coreVerifyRequest(
  3977. &prow,
  3978. OpRequest,
  3979. 0 != (CR_IN_CRLS & dwFlags),
  3980. pwszUserName,
  3981. dwComContextIndex,
  3982. &ReqId,
  3983. &ExitEvent,
  3984. &pwszDisposition,
  3985. &pCAContext,
  3986. pResult); // CoTaskMem
  3987. _PrintIfError(hr, "coreVerifyRequest");
  3988. }
  3989. else
  3990. {
  3991. WCHAR *pwszDisposition2 = CoreBuildDispositionString(
  3992. pwszDisposition,
  3993. NULL, // pwszUserName
  3994. NULL, // pwszDispositionDetail
  3995. NULL, // pwszDispositionDetail2
  3996. NULL, // pwszBy
  3997. hr,
  3998. FALSE);
  3999. if (NULL != pwszDisposition2)
  4000. {
  4001. if (NULL != pwszDisposition)
  4002. {
  4003. LocalFree(pwszDisposition);
  4004. }
  4005. pwszDisposition = pwszDisposition2;
  4006. }
  4007. }
  4008. if (NULL != pResult->pctbFullResponse)
  4009. {
  4010. BYTE const *pbCert = NULL;
  4011. DWORD cbCert = 0;
  4012. if (NULL != pResult->pctbCert && NULL != pResult->pctbCert->pb)
  4013. {
  4014. pbCert = pResult->pctbCert->pb;
  4015. cbCert = pResult->pctbCert->cb;
  4016. }
  4017. CSASSERT(NULL == pResult->pctbFullResponse->pb);
  4018. hr2 = PKCSEncodeFullResponse(
  4019. prow,
  4020. pResult,
  4021. hr,
  4022. pwszDisposition,
  4023. pCAContext,
  4024. pbCert, // pbCertLeaf
  4025. cbCert, // cbCertLeaf
  4026. 0 != (CR_IN_CRLS & dwFlags),
  4027. &pResult->pctbFullResponse->pb, // CoTaskMem*
  4028. &pResult->pctbFullResponse->cb);
  4029. _PrintIfError(hr2, "PKCSEncodeFullResponse");
  4030. if (S_OK == hr &&
  4031. (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) != hr2 || IsWhistler()))
  4032. {
  4033. hr = hr2;
  4034. }
  4035. }
  4036. if (!((CRCF_FAILDENIEDREQUEST & pResult->dwResultFlags) &&
  4037. (CRCF_PREVIOUSLYDENIED & pResult->dwResultFlags)))
  4038. {
  4039. hr2 = coreAuditRequestDisposition(
  4040. prow,
  4041. ReqId,
  4042. pwszUserName,
  4043. pwszAttributes,
  4044. *pResult->pdwDisposition);
  4045. _PrintIfError(hr2, "coreAuditRequestDisposition");
  4046. if (S_OK == hr)
  4047. {
  4048. hr = hr2;
  4049. }
  4050. }
  4051. if (NULL != pwszDisposition && NULL != pResult->pctbDispositionMessage)
  4052. {
  4053. DWORD cbAlloc = (wcslen(pwszDisposition) + 1) * sizeof(WCHAR);
  4054. BYTE *pbAlloc;
  4055. pbAlloc = (BYTE *) CoTaskMemAlloc(cbAlloc);
  4056. if (NULL != pbAlloc)
  4057. {
  4058. CopyMemory(pbAlloc, pwszDisposition, cbAlloc);
  4059. pResult->pctbDispositionMessage->pb = pbAlloc;
  4060. pResult->pctbDispositionMessage->cb = cbAlloc;
  4061. }
  4062. }
  4063. if (NULL != prow)
  4064. {
  4065. BOOL fSave;
  4066. if (S_OK != hr)
  4067. {
  4068. hr2 = PropSetRequestTimeProperty(prow, g_wszPropRequestResolvedWhen);
  4069. _PrintIfError(hr2, "PropSetRequestTimeProperty");
  4070. }
  4071. fSave = FALSE;
  4072. switch (*pResult->pdwDisposition)
  4073. {
  4074. case CR_DISP_ISSUED:
  4075. case CR_DISP_ISSUED_OUT_OF_BAND:
  4076. case CR_DISP_UNDER_SUBMISSION:
  4077. fSave = TRUE;
  4078. break;
  4079. default:
  4080. if (KRAF_SAVEBADREQUESTKEY & g_KRAFlags)
  4081. {
  4082. fSave = TRUE;
  4083. }
  4084. break;
  4085. }
  4086. if (fSave)
  4087. {
  4088. if (NULL != pResult->pbArchivedKey)
  4089. {
  4090. hr2 = prow->SetProperty(
  4091. g_wszPropRequestRawArchivedKey,
  4092. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4093. pResult->cbArchivedKey,
  4094. pResult->pbArchivedKey);
  4095. _PrintIfError(hr2, "SetProperty(ArchivedKey)");
  4096. if (S_OK == hr)
  4097. {
  4098. hr = hr2;
  4099. }
  4100. hr2 = prow->SetProperty(
  4101. g_wszPropRequestKeyRecoveryHashes,
  4102. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4103. MAXDWORD,
  4104. (BYTE const *) pResult->pwszKRAHashes);
  4105. _PrintIfError(hr2, "SetProperty(KRAHashes)");
  4106. if (S_OK == hr)
  4107. {
  4108. hr = hr2;
  4109. }
  4110. }
  4111. }
  4112. else if (CR_IN_DENY == OpRequest || CR_IN_RESUBMIT == OpRequest)
  4113. {
  4114. BYTE b = 0;
  4115. hr2 = prow->SetProperty(
  4116. g_wszPropRequestRawArchivedKey,
  4117. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4118. 0,
  4119. &b); // to avoid E_POINTER errors
  4120. _PrintIfError(hr2, "SetProperty(ArchivedKey)");
  4121. if (S_OK == hr)
  4122. {
  4123. hr = hr2;
  4124. }
  4125. hr2 = prow->SetProperty(
  4126. g_wszPropRequestKeyRecoveryHashes,
  4127. PROPTYPE_STRING | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4128. 0,
  4129. NULL);
  4130. _PrintIfError(hr2, "SetProperty(KRAHashes)");
  4131. if (S_OK == hr)
  4132. {
  4133. hr = hr2;
  4134. }
  4135. }
  4136. if (pResult->fRequestSavedWithoutKey &&
  4137. (KRAF_SAVEBADREQUESTKEY & g_KRAFlags))
  4138. {
  4139. fSave = FALSE;
  4140. switch (*pResult->pdwDisposition)
  4141. {
  4142. case CR_DISP_INCOMPLETE:
  4143. case CR_DISP_ERROR:
  4144. case CR_DISP_DENIED:
  4145. fSave = TRUE;
  4146. break;
  4147. default:
  4148. if (S_OK != hr)
  4149. {
  4150. fSave = TRUE;
  4151. }
  4152. break;
  4153. }
  4154. if (fSave)
  4155. {
  4156. hr2 = prow->SetProperty(
  4157. g_wszPropRequestRawRequest,
  4158. PROPTYPE_BINARY | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4159. cbRequest,
  4160. pbRequest);
  4161. _PrintIfError(hr2, "SetProperty(request)");
  4162. if (S_OK == hr)
  4163. {
  4164. hr = hr2;
  4165. }
  4166. }
  4167. }
  4168. hr2 = prow->CommitTransaction(TRUE);
  4169. _PrintIfError(hr2, "CommitTransaction");
  4170. fCommitted = S_OK == hr2;
  4171. if (S_OK == hr)
  4172. {
  4173. hr = hr2;
  4174. }
  4175. }
  4176. error:
  4177. // If the request exists, clean up the DB
  4178. if (NULL != prow)
  4179. {
  4180. if (S_OK != hr && !fCommitted)
  4181. {
  4182. hr2 = prow->CommitTransaction(FALSE);
  4183. _PrintIfError(hr2, "CommitTransaction");
  4184. }
  4185. prow->Release();
  4186. }
  4187. if (EXITEVENT_INVALID != ExitEvent)
  4188. {
  4189. CSASSERT(fCoInitialized);
  4190. ExitNotify(
  4191. ExitEvent,
  4192. ReqId,
  4193. CR_IN_NEW == OpRequest? pResult : NULL,
  4194. dwComContextIndex);
  4195. }
  4196. if (fCoInitialized)
  4197. {
  4198. CoUninitialize();
  4199. }
  4200. if (S_OK != hr)
  4201. {
  4202. WCHAR const *pwszMsg;
  4203. pwszMsg = myGetErrorMessageText(hr, TRUE);
  4204. if (NULL != pwszMsg)
  4205. {
  4206. CONSOLEPRINT1((DBG_SS_CERTSRV, "%ws\n", pwszMsg));
  4207. LocalFree(const_cast<WCHAR *>(pwszMsg));
  4208. }
  4209. }
  4210. if (NULL != pwszDisposition)
  4211. {
  4212. LocalFree(pwszDisposition);
  4213. }
  4214. // Hide the failed HRESULT in the returned Disposition.
  4215. // This allows the encoded Full response and disposition message to be
  4216. // returned via DCOM or RPC. Returning S_OK != hr defeats this mechanism.
  4217. if (FAILED(hr) &&
  4218. (CR_DISP_ERROR == *pResult->pdwDisposition ||
  4219. CR_DISP_DENIED == *pResult->pdwDisposition))
  4220. {
  4221. *pResult->pdwDisposition = hr;
  4222. hr = S_OK;
  4223. }
  4224. {
  4225. #define wszFORMATREQUESTID L"RequestId=%u"
  4226. WCHAR wszRequestId[ARRAYSIZE(wszFORMATREQUESTID) + cwcDWORDSPRINTF];
  4227. hr2 = hr;
  4228. if (S_OK == hr2 && FAILED(*pResult->pdwDisposition))
  4229. {
  4230. hr2 = *pResult->pdwDisposition;
  4231. }
  4232. if (S_OK != hr2)
  4233. {
  4234. wsprintf(wszRequestId, wszFORMATREQUESTID, *pResult->pdwRequestId);
  4235. _PrintErrorStr(hr2, "CoreProcessRequest", wszRequestId);
  4236. }
  4237. }
  4238. return(hr);
  4239. }
  4240. HRESULT
  4241. CoreValidateRequestId(
  4242. IN ICertDBRow *prow,
  4243. IN DWORD ExpectedDisposition)
  4244. {
  4245. HRESULT hr;
  4246. DWORD cbProp;
  4247. DWORD Disposition;
  4248. cbProp = sizeof(Disposition);
  4249. hr = prow->GetProperty(
  4250. g_wszPropRequestDisposition,
  4251. PROPTYPE_LONG | PROPCALLER_SERVER | PROPTABLE_REQUEST,
  4252. NULL,
  4253. &cbProp,
  4254. (BYTE *) &Disposition);
  4255. _PrintIfError(hr, "GetProperty");
  4256. if (S_OK != hr || sizeof(Disposition) != cbProp)
  4257. {
  4258. hr = CERTSRV_E_NO_REQUEST;
  4259. }
  4260. else if (Disposition != ExpectedDisposition)
  4261. {
  4262. hr = CERTSRV_E_BAD_REQUESTSTATUS;
  4263. }
  4264. return(hr);
  4265. }
  4266. HRESULT
  4267. SetCAObjectFlags(
  4268. IN DWORD dwFlags)
  4269. {
  4270. HRESULT hr = S_OK;
  4271. HCAINFO hCAInfo = NULL;
  4272. DWORD dwCAFlags;
  4273. hr = CAFindByName(
  4274. g_pwszSanitizedDSName,
  4275. NULL,
  4276. CA_FIND_LOCAL_SYSTEM | CA_FIND_INCLUDE_UNTRUSTED,
  4277. &hCAInfo);
  4278. _JumpIfError(hr, error, "CAFindByName");
  4279. hr = CAGetCAFlags(hCAInfo, &dwCAFlags);
  4280. _JumpIfError(hr, error, "CAGetCAFlags");
  4281. dwCAFlags |= dwFlags;
  4282. hr = CASetCAFlags(hCAInfo, dwCAFlags);
  4283. _JumpIfError(hr, error, "CASetCAFlags");
  4284. hr = CAUpdateCA(hCAInfo);
  4285. _JumpIfError(hr, error, "CAUpdateCA");
  4286. error:
  4287. if (NULL != hCAInfo)
  4288. {
  4289. CACloseCA(hCAInfo);
  4290. }
  4291. return(hr);
  4292. }