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.

2462 lines
59 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: certsrv.cpp
  7. //
  8. // Contents: Cert Server main & debug support
  9. //
  10. // History: 25-Jul-96 vich created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include <pch.cpp>
  14. #pragma hdrstop
  15. #include <locale.h>
  16. #include <io.h>
  17. #include <fcntl.h>
  18. #include <safeboot.h>
  19. #include <authzi.h>
  20. #include <common.ver>
  21. #include "elog.h"
  22. #include "certlog.h"
  23. #include "certsrvd.h"
  24. #include "resource.h"
  25. #include "csresstr.h"
  26. #define __dwFILE__ __dwFILE_CERTSRV_CERTSRV_CPP__
  27. HKEY g_hkeyCABase = 0;
  28. BOOL g_fCreateDB = FALSE;
  29. BOOL g_fStartAsService = TRUE;
  30. BOOL g_fStarted;
  31. BOOL g_fStartInProgress;
  32. DWORD g_ServiceThreadId;
  33. HWND g_hwndMain;
  34. WCHAR g_wszAppName[] = L"CertSrv";
  35. HINSTANCE g_hInstApp;
  36. DWORD g_dwDelay0;
  37. DWORD g_dwDelay1;
  38. DWORD g_dwDelay2;
  39. DWORD g_CryptSilent = 0;
  40. HANDLE g_hServiceThread = NULL;
  41. HANDLE g_hShutdownEvent = NULL;
  42. CRITICAL_SECTION g_ShutdownCriticalSection;
  43. BOOL g_fShutdownCritSec = FALSE;
  44. BOOL g_fRefuseIncoming = FALSE;
  45. LONG g_cCalls = 0;
  46. LONG g_cCallsActive = 0;
  47. LONG g_cCallsActiveMax = 0;
  48. BOOL g_fAdvancedServer = FALSE;
  49. CAVIEW *g_pCAViewList = NULL;
  50. DWORD g_cCAView = 0;
  51. BOOL g_fCAViewForceCleanup = FALSE;
  52. CAutoLPWSTR g_pwszDBFileHash;
  53. SERVICE_TABLE_ENTRY steDispatchTable[] =
  54. {
  55. { const_cast<WCHAR *>(g_wszCertSrvServiceName), ServiceMain },
  56. { NULL, NULL }
  57. };
  58. WCHAR const g_wszRegKeyClassesCLSID[] = L"SOFTWARE\\Classes\\CLSID";
  59. WCHAR const g_wszRegKeyInprocServer32[] = L"InprocServer32";
  60. WCHAR const g_wszRegValueThreadingModel[] = L"ThreadingModel";
  61. WCHAR const g_wszRegKeyAppId[] = L"SOFTWARE\\Classes\\AppId";
  62. WCHAR const g_wszRegRunAs[] = L"RunAs";
  63. WCHAR const g_wszRegValueInteractiveUser[] = L"Interactive User";
  64. WCHAR const g_wszRegLocalService[] = L"LocalService";
  65. // do not change the order, add new audit resources at the end
  66. // g_pwszAllow,
  67. // g_pwszDeny,
  68. // g_pwszCAAdmin,
  69. // g_pwszOfficer,
  70. // g_pwszRead,
  71. // g_pwszEnroll,
  72. LPCWSTR g_pwszAuditResources[6];
  73. using namespace CertSrv;
  74. HRESULT
  75. OpenRegistryComKey(
  76. IN HKEY hKeyParent,
  77. IN CLSID const *pclsid,
  78. IN BOOL fWrite,
  79. OUT HKEY *phKey)
  80. {
  81. HRESULT hr;
  82. WCHAR *pwsz = NULL;
  83. *phKey = NULL;
  84. hr = StringFromCLSID(*pclsid, &pwsz);
  85. _JumpIfError(hr, error, "StringFromCLSID");
  86. hr = RegOpenKeyEx(
  87. hKeyParent,
  88. pwsz,
  89. 0,
  90. fWrite? KEY_ALL_ACCESS : KEY_READ,
  91. phKey);
  92. _JumpIfError(hr, error, "RegOpenKeyEx");
  93. error:
  94. if (NULL != pwsz)
  95. {
  96. CoTaskMemFree(pwsz);
  97. }
  98. return(hr);
  99. }
  100. BOOL
  101. IsMissingRegistryValue(
  102. IN HKEY hKey,
  103. IN WCHAR const *pwszRegValueName)
  104. {
  105. HRESULT hr;
  106. DWORD dwLen;
  107. DWORD dwType;
  108. hr = RegQueryValueEx(hKey, pwszRegValueName, NULL, &dwType, NULL, &dwLen);
  109. if (S_OK != hr)
  110. {
  111. hr = myHError(hr);
  112. }
  113. _JumpIfError2(
  114. hr,
  115. error,
  116. "RegQueryValueEx",
  117. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  118. error:
  119. return(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr);
  120. }
  121. BOOL
  122. IsMatchingRegistryValue(
  123. IN HKEY hKey,
  124. IN WCHAR const *pwszRegValueName,
  125. IN WCHAR const *pwszRegValueString)
  126. {
  127. HRESULT hr;
  128. DWORD dwLen;
  129. DWORD dwType;
  130. BOOL fMatch = FALSE;
  131. WCHAR buf[MAX_PATH];
  132. dwLen = sizeof(buf);
  133. hr = RegQueryValueEx(
  134. hKey,
  135. pwszRegValueName,
  136. NULL,
  137. &dwType,
  138. (BYTE *) buf,
  139. &dwLen);
  140. _JumpIfErrorStr(hr, error, "RegQueryValueEx", pwszRegValueName);
  141. if (REG_SZ == dwType && 0 == mylstrcmpiL(buf, pwszRegValueString))
  142. {
  143. fMatch = TRUE;
  144. }
  145. error:
  146. return(fMatch);
  147. }
  148. HRESULT
  149. SetRegistryStringValue(
  150. IN HKEY hKey,
  151. IN WCHAR const *pwszRegValueName,
  152. IN WCHAR const *pwszRegValueString)
  153. {
  154. HRESULT hr;
  155. hr = RegSetValueEx(
  156. hKey,
  157. pwszRegValueName,
  158. 0,
  159. REG_SZ,
  160. (const BYTE *) pwszRegValueString,
  161. (wcslen(pwszRegValueString) + 1) * sizeof(WCHAR));
  162. return(hr);
  163. }
  164. HRESULT
  165. CertSrvSetRegistryFileTimeValue(
  166. IN BOOL fConfigLevel,
  167. IN WCHAR const *pwszRegValueName,
  168. IN DWORD cpwszDelete,
  169. OPTIONAL IN WCHAR const * const *papwszRegValueNameDelete)
  170. {
  171. HRESULT hr;
  172. HKEY hKey = NULL;
  173. HKEY hKey1 = NULL;
  174. FILETIME ftCurrent;
  175. DWORD i;
  176. GetSystemTimeAsFileTime(&ftCurrent);
  177. hr = RegOpenKeyEx(
  178. HKEY_LOCAL_MACHINE,
  179. wszREGKEYCONFIGPATH,
  180. 0,
  181. KEY_ALL_ACCESS,
  182. &hKey);
  183. _JumpIfError(hr, error, "RegOpenKeyEx");
  184. if (!fConfigLevel)
  185. {
  186. hKey1 = hKey;
  187. hKey = NULL;
  188. hr = RegOpenKeyEx(
  189. hKey1,
  190. g_wszSanitizedName,
  191. 0,
  192. KEY_ALL_ACCESS,
  193. &hKey);
  194. _JumpIfError(hr, error, "RegOpenKeyEx");
  195. }
  196. hr = RegSetValueEx(
  197. hKey,
  198. pwszRegValueName,
  199. 0,
  200. REG_BINARY,
  201. (BYTE const *) &ftCurrent,
  202. sizeof(ftCurrent));
  203. _JumpIfError(hr, error, "RegSetValueEx");
  204. for (i = 0; i < cpwszDelete; i++)
  205. {
  206. hr = RegDeleteValue(hKey, papwszRegValueNameDelete[i]);
  207. _PrintIfError2(hr, "RegDeleteValue", ERROR_FILE_NOT_FOUND);
  208. }
  209. hr = S_OK;
  210. error:
  211. if (NULL != hKey1)
  212. {
  213. RegCloseKey(hKey1);
  214. }
  215. if (NULL != hKey)
  216. {
  217. RegCloseKey(hKey);
  218. }
  219. return(myHError(hr));
  220. }
  221. HRESULT
  222. SetRegistryDcomConfig(
  223. IN BOOL fConsoleActive)
  224. {
  225. HRESULT hr;
  226. HKEY hKeyAppId = NULL;
  227. HKEY hKeyRequest = NULL;
  228. DWORD cChanged = 0;
  229. hr = RegOpenKeyEx(
  230. HKEY_LOCAL_MACHINE,
  231. g_wszRegKeyAppId,
  232. 0,
  233. KEY_ALL_ACCESS,
  234. &hKeyAppId);
  235. _JumpIfError(hr, error, "RegOpenKeyEx");
  236. hr = OpenRegistryComKey(hKeyAppId, &CLSID_CCertRequestD, TRUE, &hKeyRequest);
  237. _JumpIfError(hr, error, "OpenRegistryComKey");
  238. if (fConsoleActive)
  239. {
  240. // Running in console mode:
  241. // Delete both LocalService registry values
  242. // Create both RunAs = InteractiveUser registry values
  243. if (!IsMissingRegistryValue(hKeyRequest, g_wszRegLocalService))
  244. {
  245. cChanged++;
  246. hr = RegDeleteValue(hKeyRequest, g_wszRegLocalService);
  247. _JumpIfError(hr, error, "RegDeleteValue");
  248. }
  249. if (!IsMatchingRegistryValue(
  250. hKeyRequest,
  251. g_wszRegRunAs,
  252. g_wszRegValueInteractiveUser))
  253. {
  254. cChanged++;
  255. hr = SetRegistryStringValue(
  256. hKeyRequest,
  257. g_wszRegRunAs,
  258. g_wszRegValueInteractiveUser);
  259. _JumpIfError(hr, error, "SetRegistryStringValue");
  260. }
  261. if (0 != cChanged)
  262. {
  263. DBGPRINT((
  264. DBG_SS_CERTSRV,
  265. "SetRegistryDcomConfig(%u): setting %ws=%ws\n",
  266. cChanged,
  267. g_wszRegRunAs,
  268. g_wszRegValueInteractiveUser));
  269. }
  270. }
  271. else
  272. {
  273. // Running as a service:
  274. // Delete both RunAs registry values
  275. // Create both LocalService = CertSvc registry values
  276. if (!IsMissingRegistryValue(hKeyRequest, g_wszRegRunAs))
  277. {
  278. cChanged++;
  279. hr = RegDeleteValue(hKeyRequest, g_wszRegRunAs);
  280. _JumpIfError(hr, error, "RegDeleteValue");
  281. }
  282. if (!IsMatchingRegistryValue(
  283. hKeyRequest,
  284. g_wszRegLocalService,
  285. g_wszCertSrvServiceName))
  286. {
  287. cChanged++;
  288. hr = SetRegistryStringValue(
  289. hKeyRequest,
  290. g_wszRegLocalService,
  291. g_wszCertSrvServiceName);
  292. _JumpIfError(hr, error, "SetRegistryStringValue");
  293. }
  294. if (0 != cChanged)
  295. {
  296. DBGPRINT((
  297. DBG_SS_CERTSRV,
  298. "SetRegistryDcomConfig(%u): setting %ws=%ws\n",
  299. cChanged,
  300. g_wszRegLocalService,
  301. g_wszCertSrvServiceName));
  302. }
  303. }
  304. error:
  305. if (NULL != hKeyRequest)
  306. {
  307. RegCloseKey(hKeyRequest);
  308. }
  309. if (NULL != hKeyAppId)
  310. {
  311. RegCloseKey(hKeyAppId);
  312. }
  313. return(myHError(hr));
  314. }
  315. DWORD
  316. GetRegistryDwordValue(
  317. IN WCHAR const *pwszRegValueName)
  318. {
  319. HRESULT hr;
  320. HKEY hKeyConfig = NULL;
  321. DWORD dwVal;
  322. DWORD dwType;
  323. DWORD dwLen;
  324. dwVal = 0;
  325. hr = RegOpenKeyEx(
  326. HKEY_LOCAL_MACHINE,
  327. g_wszRegKeyConfigPath,
  328. 0,
  329. KEY_READ,
  330. &hKeyConfig);
  331. _JumpIfError(hr, error, "RegOpenKeyEx");
  332. dwLen = sizeof(dwVal);
  333. hr = RegQueryValueEx(
  334. hKeyConfig,
  335. pwszRegValueName,
  336. NULL,
  337. &dwType,
  338. (BYTE *) &dwVal,
  339. &dwLen);
  340. if (S_OK != hr || REG_DWORD != dwType || sizeof(dwVal) != dwLen)
  341. {
  342. dwVal = 0;
  343. goto error;
  344. }
  345. error:
  346. if (NULL != hKeyConfig)
  347. {
  348. RegCloseKey(hKeyConfig);
  349. }
  350. return(dwVal);
  351. }
  352. HRESULT
  353. CertSrvResetRegistryWatch(
  354. IN OUT HANDLE *phRegistryModified)
  355. {
  356. HRESULT hr;
  357. CSASSERT(NULL != phRegistryModified);
  358. //////////////////////////////////////
  359. // Initialization of registry events
  360. if (NULL == g_hkeyCABase)
  361. {
  362. DWORD dwDisposition;
  363. LPWSTR pszCAPath;
  364. pszCAPath = (LPWSTR) LocalAlloc(
  365. LMEM_FIXED,
  366. (WSZARRAYSIZE(wszREGKEYCONFIGPATH_BS) +
  367. wcslen(g_wszSanitizedName) +
  368. 1) * sizeof(WCHAR));
  369. if (NULL == pszCAPath)
  370. {
  371. hr = E_OUTOFMEMORY;
  372. _JumpError(hr, error, "LocalAlloc");
  373. }
  374. wcscpy(pszCAPath, wszREGKEYCONFIGPATH_BS);
  375. wcscat(pszCAPath, g_wszSanitizedName);
  376. hr = RegCreateKeyEx(
  377. HKEY_LOCAL_MACHINE,
  378. pszCAPath,
  379. 0, // reserved
  380. NULL, // class
  381. 0, // options
  382. KEY_ALL_ACCESS, // sec desired
  383. NULL, // sec attr
  384. &g_hkeyCABase, // phk
  385. &dwDisposition);
  386. LocalFree(pszCAPath); pszCAPath = NULL;
  387. _JumpIfError(hr, error, "RegCreateKeyEx base key");
  388. }
  389. if (NULL == *phRegistryModified)
  390. {
  391. *phRegistryModified = CreateEvent(NULL, TRUE, FALSE, NULL);
  392. if (NULL == *phRegistryModified)
  393. {
  394. hr = myHLastError();
  395. _JumpError(hr, error, "CreateEvent registry watch");
  396. }
  397. }
  398. else
  399. {
  400. // reset registry event
  401. ResetEvent( *phRegistryModified );
  402. }
  403. // register our registry lookout trigger
  404. hr = RegNotifyChangeKeyValue(
  405. g_hkeyCABase,
  406. FALSE,
  407. REG_NOTIFY_CHANGE_LAST_SET,
  408. *phRegistryModified,
  409. TRUE);
  410. _JumpIfError(hr, error, "RegNotifyChangeKeyValue on base key");
  411. error:
  412. return(myHError(hr));
  413. }
  414. VOID
  415. CertSrvLogOpen()
  416. {
  417. BOOL fOpenLog;
  418. static BOOL s_fLogOpened = FALSE;
  419. DbgPrintfInit("+"); // reinitialize debug print mask first
  420. fOpenLog = DbgIsSSActive(DBG_SS_OPENLOG);
  421. if (fOpenLog)
  422. {
  423. if (!s_fLogOpened)
  424. {
  425. DbgPrintfInit("+certsrv.log"); // open the log file
  426. s_fLogOpened = TRUE;
  427. DbgLogFileVersion("certsrv.exe", szCSVER_STR);
  428. }
  429. }
  430. else
  431. {
  432. if (s_fLogOpened)
  433. {
  434. DbgPrintfInit("-"); // close the log file
  435. s_fLogOpened = FALSE;
  436. }
  437. }
  438. }
  439. HRESULT
  440. CertSrvRegistryModificationEvent(
  441. IN FILETIME const *pftWait,
  442. IN OUT DWORD *pdwTimeOut)
  443. {
  444. HRESULT hr;
  445. DWORD dwVal;
  446. BOOL fDisabledNew;
  447. FILETIME ftCurrent;
  448. BOOL fSetEvent = FALSE;
  449. DWORD dwMSTimeOut;
  450. CertSrvLogOpen(); // open log if registry changed to enable logging
  451. // see if Base CRL publish enabled state has changed
  452. hr = myGetCertRegDWValue(
  453. g_wszSanitizedName,
  454. NULL,
  455. NULL,
  456. wszREGCRLPERIODCOUNT,
  457. &dwVal);
  458. if (S_OK == hr)
  459. {
  460. fDisabledNew = 0 == dwVal;
  461. if (fDisabledNew != g_fCRLPublishDisabled)
  462. {
  463. fSetEvent = TRUE;
  464. }
  465. }
  466. // see if Delta CRL publish enabled state has changed
  467. hr = myGetCertRegDWValue(
  468. g_wszSanitizedName,
  469. NULL,
  470. NULL,
  471. wszREGCRLDELTAPERIODCOUNT,
  472. &dwVal);
  473. if (S_OK == hr)
  474. {
  475. fDisabledNew = 0 == dwVal;
  476. if (fDisabledNew != g_fDeltaCRLPublishDisabled)
  477. {
  478. fSetEvent = TRUE;
  479. }
  480. }
  481. GetSystemTimeAsFileTime(&ftCurrent);
  482. CRLComputeTimeOut(pftWait, &ftCurrent, &dwMSTimeOut);
  483. if (dwMSTimeOut >= *pdwTimeOut)
  484. {
  485. dwMSTimeOut = *pdwTimeOut;
  486. fSetEvent = TRUE;
  487. }
  488. *pdwTimeOut -= dwMSTimeOut;
  489. if (fSetEvent)
  490. {
  491. SetEvent(g_hCRLManualPublishEvent); // pulse to get up-to-date
  492. }
  493. return(hr);
  494. }
  495. #if DBG_CERTSRV
  496. WCHAR const *
  497. certsrvGetCurrentTimeWsz()
  498. {
  499. HRESULT hr;
  500. FILETIME ft;
  501. WCHAR *pwszTime = NULL;
  502. static WCHAR s_wszTime[128];
  503. GetSystemTimeAsFileTime(&ft);
  504. hr = myGMTFileTimeToWszLocalTime(&ft, TRUE, &pwszTime);
  505. _PrintIfError(hr, "myGMTFileTimeToWszLocalTime");
  506. s_wszTime[0] = L'\0';
  507. if (NULL != pwszTime)
  508. {
  509. wcsncpy(s_wszTime, pwszTime, ARRAYSIZE(s_wszTime));
  510. s_wszTime[ARRAYSIZE(s_wszTime) - 1] = L'\0';
  511. LocalFree(pwszTime);
  512. }
  513. return(s_wszTime);
  514. }
  515. #endif
  516. HRESULT
  517. CertSrvBlockThreadUntilStop()
  518. {
  519. HRESULT hr;
  520. HANDLE hRegistryModified = NULL;
  521. DWORD dwTimeOut;
  522. // check CRL publish, get next timeout interval
  523. hr = CRLPubWakeupEvent(&dwTimeOut);
  524. _PrintIfError(hr, "CRLPubWakeupEvent");
  525. hr = CertSrvResetRegistryWatch(&hRegistryModified);
  526. _PrintIfError(hr, "CertSrvResetRegistryWatch");
  527. for (;;)
  528. {
  529. FILETIME ftWait;
  530. DWORD dw;
  531. HANDLE hmultiObjects[] = {
  532. hRegistryModified,
  533. g_hServiceStoppingEvent,
  534. g_hCRLManualPublishEvent
  535. };
  536. #if DBG_CERTSRV
  537. {
  538. LLFILETIME llft;
  539. WCHAR *pwszTimePeriod = NULL;
  540. llft.ll = dwTimeOut;
  541. llft.ll *= (CVT_BASE / 1000); // convert msecs to 100ns
  542. llft.ll = -llft.ll;
  543. hr = myFileTimePeriodToWszTimePeriod(
  544. &llft.ft,
  545. TRUE, // fExact
  546. &pwszTimePeriod);
  547. _PrintIfError(hr, "myFileTimePeriodToWszTimePeriod");
  548. DBGPRINT((
  549. DBG_SS_CERTSRV,
  550. "WaitForMultipleObjects(%u ms) %ws @%ws\n",
  551. dwTimeOut,
  552. pwszTimePeriod,
  553. certsrvGetCurrentTimeWsz()));
  554. if (NULL != pwszTimePeriod)
  555. {
  556. LocalFree(pwszTimePeriod);
  557. }
  558. }
  559. #endif
  560. GetSystemTimeAsFileTime(&ftWait);
  561. dw = WaitForMultipleObjects(
  562. ARRAYSIZE(hmultiObjects),
  563. hmultiObjects,
  564. FALSE, // any object will cause bailout
  565. dwTimeOut);
  566. DBGPRINT((
  567. DBG_SS_CERTSRV,
  568. "WaitForMultipleObjects(%u ms)->%x, %ws\n",
  569. dwTimeOut,
  570. dw,
  571. certsrvGetCurrentTimeWsz()));
  572. if (WAIT_FAILED == dw)
  573. {
  574. hr = GetLastError();
  575. _JumpError(hr, error, "WaitForMultipleObjects worker");
  576. }
  577. if (dw == WAIT_TIMEOUT) // CRL
  578. {
  579. hr = CRLPubWakeupEvent(&dwTimeOut);
  580. _PrintIfError(hr, "Error during CRLPubWakeupEvent");
  581. DBGPRINT((DBG_SS_CERTSRVI, "CRLPub: TimeOut %u ms\n", dwTimeOut));
  582. }
  583. else if (dw == WAIT_OBJECT_0) // Registry modification
  584. {
  585. // In either case, determine if CRL needs to be published
  586. hr = CertSrvRegistryModificationEvent(&ftWait, &dwTimeOut);
  587. _PrintIfError(hr, "Error during CertSrvRegistryModificationEvent");
  588. // in registry case, reset registry trigger
  589. DBGPRINT((
  590. DBG_SS_CERTSRVI,
  591. "CRLPub: Registry change trigger, TimeOut=%u ms\n",
  592. dwTimeOut));
  593. hr = CertSrvResetRegistryWatch(&hRegistryModified);
  594. _PrintIfError(hr, "Error during CertSrvResetRegistryWatch");
  595. }
  596. else if (dw == WAIT_OBJECT_0 + 1)
  597. {
  598. // found "service done" event
  599. DBGPRINT((DBG_SS_CERTSRV, "Service is pending stop request\n"));
  600. break; // exit wait loop
  601. }
  602. else if (dw == WAIT_OBJECT_0 + 2)
  603. {
  604. // found "g_hCRLManualPublishEvent" event: recalc timeout
  605. hr = CRLPubWakeupEvent(&dwTimeOut);
  606. _PrintIfError(hr, "Error during CRLPubWakeupEvent");
  607. DBGPRINT((
  608. DBG_SS_CERTSRVI,
  609. "CRLPub: Manual publish recalc, TimeOut=%u ms\n",
  610. dwTimeOut));
  611. }
  612. else
  613. {
  614. CSASSERT(CSExpr(!"unexpected wait return"));
  615. hr = E_UNEXPECTED;
  616. _JumpError(hr, error, "WaitForMultipleObjects");
  617. }
  618. }
  619. hr = S_OK;
  620. error:
  621. CloseHandle(hRegistryModified);
  622. return hr;
  623. }
  624. HRESULT certsrvGetCACertAndKeyHash(
  625. OUT WCHAR **ppwszCertHash,
  626. OUT WCHAR **ppwszPublicKeyHash)
  627. {
  628. HRESULT hr;
  629. WCHAR wszCertHash[CBMAX_CRYPT_HASH_LEN * 3]; // 20 bytes @ 3 WCHARs/byte
  630. DWORD cbCertHashStr;
  631. WCHAR wszPublicKeyHash[CBMAX_CRYPT_HASH_LEN * 3];
  632. DWORD cbPublicKeyHashStr;
  633. BYTE abCertHash[CBMAX_CRYPT_HASH_LEN];
  634. DWORD cbCertHash;
  635. CAutoPBYTE autopbPublicKeyHash;
  636. DWORD cbPublicKeyHash;
  637. *ppwszCertHash = NULL;
  638. *ppwszPublicKeyHash = NULL;
  639. cbCertHash = sizeof(abCertHash);
  640. if (!CertGetCertificateContextProperty(
  641. g_pCAContextCurrent->pccCA,
  642. CERT_SHA1_HASH_PROP_ID,
  643. abCertHash,
  644. &cbCertHash))
  645. {
  646. hr = myHLastError();
  647. _JumpError(hr, error, "CertGetCertificateContextProperty");
  648. }
  649. cbCertHashStr = sizeof(wszCertHash);
  650. hr = MultiByteIntegerToWszBuf(
  651. TRUE, // byte multiple
  652. cbCertHash,
  653. abCertHash,
  654. &cbCertHashStr,
  655. wszCertHash);
  656. _JumpIfError(hr, error, "MultiByteIntegerToWszBuf");
  657. hr = myGetPublicKeyHash(
  658. g_pCAContextCurrent->pccCA->pCertInfo,
  659. &g_pCAContextCurrent->pccCA->pCertInfo->SubjectPublicKeyInfo,
  660. &autopbPublicKeyHash,
  661. &cbPublicKeyHash);
  662. _JumpIfError(hr, error, "myGetPublicKeyHash");
  663. cbPublicKeyHashStr = sizeof(wszPublicKeyHash);
  664. hr = MultiByteIntegerToWszBuf(
  665. TRUE, // byte multiple
  666. cbPublicKeyHash,
  667. autopbPublicKeyHash,
  668. &cbPublicKeyHashStr,
  669. wszPublicKeyHash);
  670. _JumpIfError(hr, error, "MultiByteIntegerToWszBuf");
  671. hr = myDupString(wszCertHash, ppwszCertHash);
  672. _JumpIfError(hr, error, "myDupString");
  673. hr = myDupString(wszPublicKeyHash, ppwszPublicKeyHash);
  674. _JumpIfError(hr, error, "myDupString");
  675. error:
  676. return hr;
  677. }
  678. #define CSECSLEEP 2 // time to sleep each time through the loop
  679. #define CSECSLEEPTOTAL 30 // total time to wait before giving up
  680. #define wsz3QM L"???" // audit data collection failure placeholder
  681. HRESULT
  682. CertSrvAuditShutdown(
  683. IN ULARGE_INTEGER *puliKeyUsageCount,
  684. IN WCHAR const *pwszCertHash,
  685. IN WCHAR const *pwszPublicKeyHash)
  686. {
  687. HRESULT hr;
  688. HRESULT hr2;
  689. DWORD i;
  690. WCHAR const *pwsz;
  691. CertSrv::CAuditEvent event(
  692. SE_AUDITID_CERTSRV_SERVICESTOP,
  693. g_dwAuditFilter);
  694. hr = S_OK;
  695. for (i = 0; i < CSECSLEEPTOTAL / CSECSLEEP; i++)
  696. {
  697. g_pwszDBFileHash.Cleanup();
  698. hr = myComputeMAC(g_wszDatabase, &g_pwszDBFileHash);
  699. if (S_OK == hr || HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION) != hr)
  700. {
  701. break;
  702. }
  703. _PrintError(hr, "myComputeMAC");
  704. Sleep(CSECSLEEP * 1000);
  705. }
  706. _PrintIfErrorStr(hr, "myComputeMAC", g_wszDatabase);
  707. hr2 = hr; // save first error
  708. // %1 database hash
  709. pwsz = g_pwszDBFileHash; // avoid CAutoLPWSTR freeing static wsz3QM string!
  710. hr = event.AddData(pwsz != NULL? pwsz : wsz3QM);
  711. g_pwszDBFileHash.Cleanup();
  712. _JumpIfError(hr, error, "CAuditEvent::AddData");
  713. // %2 key usage count
  714. hr = event.AddData(puliKeyUsageCount);
  715. _JumpIfError(hr, error, "CAuditEvent::AddData");
  716. // %3 CA cert hash
  717. hr = event.AddData(NULL != pwszCertHash? pwszCertHash : wsz3QM);
  718. _JumpIfError(hr, error, "CAuditEvent::AddData");
  719. // %4 CA public key hash
  720. hr = event.AddData(NULL != pwszPublicKeyHash? pwszPublicKeyHash : wsz3QM);
  721. _JumpIfError(hr, error, "CAuditEvent::AddData");
  722. hr = event.Report();
  723. _JumpIfError(hr, error, "CAuditEvent::Report");
  724. error:
  725. if (S_OK != hr2)
  726. {
  727. hr = hr2; // return first error
  728. }
  729. return(hr);
  730. }
  731. // returns TRUE if we shutdown correctly
  732. BOOL
  733. CertSrvStopServer(
  734. IN BOOL fConsoleActive)
  735. {
  736. HRESULT hr;
  737. BOOL fCoInit = FALSE;
  738. BOOL fShutDown = FALSE;
  739. ULARGE_INTEGER uliKeyUsageCount;
  740. CAutoLPWSTR autoszCertHash;
  741. CAutoLPWSTR autoszPublicKeyHash;
  742. if (!g_fStartInProgress) // ignore while starting the server
  743. {
  744. fShutDown = TRUE;
  745. DBGPRINT((
  746. DBG_SS_CERTSRV,
  747. "CertSrvStopServer(fConsoleActive=%u, tid=%d)\n",
  748. fConsoleActive,
  749. GetCurrentThreadId()));
  750. SetEvent(g_hServiceStoppingEvent);
  751. if (g_hkeyCABase)
  752. {
  753. RegCloseKey(g_hkeyCABase);
  754. g_hkeyCABase = NULL;
  755. }
  756. hr = CoInitializeEx(NULL, GetCertsrvComThreadingModel());
  757. if (S_OK != hr && S_FALSE != hr)
  758. {
  759. _JumpError(hr, error, "CoInitializeEx");
  760. }
  761. fCoInit = TRUE;
  762. // don't allow new callers in
  763. if (0 == (IF_NORPCICERTREQUEST & g_InterfaceFlags))
  764. {
  765. hr = RPCTeardown();
  766. _PrintIfError(hr, "RPCTeardown");
  767. }
  768. CertStopClassFactories();
  769. // retrieve private key usage count if auditing enabled
  770. if (AUDIT_FILTER_STARTSTOP & g_dwAuditFilter)
  771. {
  772. BOOL fSupported;
  773. BOOL fEnabled;
  774. uliKeyUsageCount.QuadPart = 0;
  775. hr = myGetSigningKeyUsageCount(
  776. g_pCAContextCurrent->hProvCA,
  777. &fSupported,
  778. &fEnabled,
  779. &uliKeyUsageCount);
  780. _PrintIfError(hr, "myGetSigningKeyUsageCount");
  781. hr = certsrvGetCACertAndKeyHash(
  782. &autoszCertHash,
  783. &autoszPublicKeyHash);
  784. _PrintIfError(hr, "certsrvGetCACertAndKeyHash");
  785. }
  786. CoreTerminate();
  787. if (g_fStarted)
  788. {
  789. if (CERTLOG_TERSE <= g_dwLogLevel)
  790. {
  791. LogEventString(
  792. EVENTLOG_INFORMATION_TYPE,
  793. MSG_I_SERVER_STOPPED,
  794. g_wszCommonName);
  795. }
  796. CONSOLEPRINT0((
  797. DBG_SS_CERTSRV,
  798. "Certification Authority Service Stopped\n"));
  799. // only perform Hash if the auditing is enabled
  800. if (AUDIT_FILTER_STARTSTOP & g_dwAuditFilter)
  801. {
  802. hr = CertSrvAuditShutdown(
  803. &uliKeyUsageCount,
  804. autoszCertHash,
  805. autoszPublicKeyHash);
  806. _PrintError(hr, "CertSrvAuditShutdown");
  807. }
  808. }
  809. g_fStarted = FALSE;
  810. AuthzFreeResourceManager(g_AuthzCertSrvRM);
  811. g_AuthzCertSrvRM = NULL;
  812. g_CASD.Uninitialize();
  813. g_OfficerRightsSD.Uninitialize();
  814. // set "completely stopped" event
  815. if (!fConsoleActive)
  816. {
  817. SetEvent(g_hServiceStoppedEvent);
  818. }
  819. }
  820. error:
  821. if (fCoInit)
  822. {
  823. CoUninitialize();
  824. }
  825. return(fShutDown);
  826. }
  827. // Control-C handler
  828. BOOL
  829. StopServer(
  830. IN DWORD /* dwCtrlType */ )
  831. {
  832. HRESULT hr;
  833. // if successful shutdown
  834. if (SendMessage(g_hwndMain, WM_STOPSERVER, 0, 0))
  835. {
  836. if (!PostMessage(g_hwndMain, WM_SYNC_CLOSING_THREADS, S_OK, 0))
  837. {
  838. hr = myHLastError();
  839. _PrintError(hr, "PostMessage");
  840. }
  841. SetConsoleCtrlHandler(StopServer, FALSE);
  842. }
  843. return(TRUE);
  844. }
  845. VOID
  846. ReleaseOldViews()
  847. {
  848. if (0 < g_cCAView)
  849. {
  850. FILETIME ftTooOld;
  851. FILETIME ftTooIdle;
  852. CAVIEW *pCAView;
  853. CAVIEW **ppCAViewLast;
  854. GetSystemTimeAsFileTime(&ftTooIdle);
  855. ftTooOld = ftTooIdle;
  856. myMakeExprDateTime(
  857. &ftTooOld,
  858. -(LONG) g_dwViewAgeMinutes,
  859. ENUM_PERIOD_MINUTES);
  860. myMakeExprDateTime(
  861. &ftTooIdle,
  862. -(LONG) g_dwViewIdleMinutes,
  863. ENUM_PERIOD_MINUTES);
  864. ppCAViewLast = &g_pCAViewList;
  865. pCAView = g_pCAViewList;
  866. for (;;)
  867. {
  868. if (NULL == pCAView)
  869. {
  870. break;
  871. }
  872. //CERTSRVDBGPRINTTIME("ftTooOld", &ftTooOld);
  873. //CERTSRVDBGPRINTTIME("ftCreate", &pCAView->ftCreate);
  874. //CERTSRVDBGPRINTTIME("ftTooIdle", &ftTooIdle);
  875. //CERTSRVDBGPRINTTIME("ftLastAccess", &pCAView->ftLastAccess);
  876. if (g_fCAViewForceCleanup ||
  877. g_fRefuseIncoming ||
  878. 0 < CompareFileTime(&ftTooOld, &pCAView->ftCreate) ||
  879. 0 < CompareFileTime(&ftTooIdle, &pCAView->ftLastAccess))
  880. {
  881. CAVIEW *pCAViewFree;
  882. // Release this view, then Delink and free the list element.
  883. DBGPRINT((
  884. DBG_SS_CERTSRV,
  885. "ReleaseOldViews(%u: Force=%u Refuse=%u old=%u idle=%u pv=%p View=%p)\n",
  886. g_cCAView,
  887. g_fCAViewForceCleanup,
  888. g_fRefuseIncoming,
  889. 0 < CompareFileTime(&ftTooOld, &pCAView->ftCreate),
  890. 0 < CompareFileTime(&ftTooIdle, &pCAView->ftLastAccess),
  891. pCAView->pvSearch,
  892. pCAView->pView));
  893. pCAViewFree = pCAView;
  894. *ppCAViewLast = pCAView->pCAViewNext;
  895. pCAView = pCAView->pCAViewNext;
  896. pCAViewFree->pView->Release();
  897. LocalFree(pCAViewFree);
  898. g_cCAView--;
  899. }
  900. else
  901. {
  902. ppCAViewLast = &pCAView->pCAViewNext;
  903. pCAView = pCAView->pCAViewNext;
  904. }
  905. }
  906. g_fCAViewForceCleanup = FALSE;
  907. }
  908. }
  909. HRESULT
  910. CertSrvEnterServer(
  911. OUT DWORD *pState)
  912. {
  913. HRESULT hr;
  914. BOOL fEntered = FALSE;
  915. *pState = 0; // Caller need not exit server
  916. if (!g_fShutdownCritSec)
  917. {
  918. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  919. _JumpError(hr, error, "InitializeCriticalSection");
  920. }
  921. EnterCriticalSection(&g_ShutdownCriticalSection);
  922. fEntered = TRUE;
  923. hr = CertSrvTestServerState();
  924. _JumpIfError(hr, error, "CertSrvTestServerState");
  925. g_cCalls++;
  926. g_cCallsActive++;
  927. if (g_cCallsActiveMax < g_cCallsActive)
  928. {
  929. g_cCallsActiveMax = g_cCallsActive;
  930. }
  931. *pState = 1; // Caller must exit server
  932. hr = S_OK;
  933. error:
  934. if (fEntered)
  935. {
  936. LeaveCriticalSection(&g_ShutdownCriticalSection);
  937. }
  938. return(hr);
  939. }
  940. HRESULT
  941. CertSrvTestServerState()
  942. {
  943. HRESULT hr;
  944. if (g_fRefuseIncoming)
  945. {
  946. hr = HRESULT_FROM_WIN32(ERROR_SHUTDOWN_IN_PROGRESS);
  947. _JumpError(hr, error, "g_fRefuseIncoming");
  948. }
  949. hr = S_OK;
  950. error:
  951. return(hr);
  952. }
  953. HRESULT
  954. CertSrvLockServer(
  955. IN OUT DWORD *pState)
  956. {
  957. HRESULT hr;
  958. BOOL fEntered = FALSE;
  959. // Eliminate this thread from the active thread count
  960. CertSrvExitServer(*pState, S_OK);
  961. *pState = 0; // Caller no longer needs to exit server
  962. if (!g_fShutdownCritSec)
  963. {
  964. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  965. _JumpError(hr, error, "InitializeCriticalSection");
  966. }
  967. EnterCriticalSection(&g_ShutdownCriticalSection);
  968. fEntered = TRUE;
  969. g_fRefuseIncoming = TRUE;
  970. ReleaseOldViews();
  971. hr = DBShutDown(TRUE);
  972. _PrintIfError(hr, "DBShutDown");
  973. DBGPRINT((DBG_SS_CERTSRV, "LockServer(thread count = %u)\n", g_cCallsActive));
  974. while (0 < g_cCallsActive)
  975. {
  976. LONG cCalls = g_cCallsActive;
  977. LeaveCriticalSection(&g_ShutdownCriticalSection);
  978. // Wait 15 seconds plus 2 seconds for each active call.
  979. hr = WaitForSingleObject(g_hShutdownEvent, (15 + 2 * cCalls) * 1000);
  980. EnterCriticalSection(&g_ShutdownCriticalSection);
  981. _PrintIfError(hr, "WaitForSingleObject");
  982. if ((HRESULT) WAIT_OBJECT_0 == hr)
  983. {
  984. DBGPRINT((DBG_SS_CERTSRV, "LockServer(last thread exit event)\n"));
  985. }
  986. else if ((HRESULT) WAIT_TIMEOUT == hr)
  987. {
  988. DBGPRINT((DBG_SS_CERTSRV, "LockServer(timeout)\n"));
  989. if (cCalls <= g_cCallsActive)
  990. {
  991. break; // no reduction in active threads -- abort anyway
  992. }
  993. }
  994. else if ((HRESULT) WAIT_ABANDONED == hr)
  995. {
  996. DBGPRINT((DBG_SS_CERTSRV, "LockServer(wait abandoned)\n"));
  997. }
  998. DBGPRINT((DBG_SS_CERTSRV, "LockServer(thread count = %u)\n", g_cCallsActive));
  999. }
  1000. DBGPRINT((DBG_SS_CERTSRV, "LockServer(done: thread count = %u)\n", g_cCallsActive));
  1001. hr = S_OK;
  1002. error:
  1003. if (fEntered)
  1004. {
  1005. LeaveCriticalSection(&g_ShutdownCriticalSection);
  1006. }
  1007. return(hr);
  1008. }
  1009. VOID
  1010. CertSrvExitServer(
  1011. IN DWORD State,
  1012. IN HRESULT hrExit)
  1013. {
  1014. HRESULT hr;
  1015. BOOL fEntered = FALSE;
  1016. if (S_OK != hrExit && g_hrJetVersionStoreOutOfMemory == hrExit)
  1017. {
  1018. g_fCAViewForceCleanup = TRUE;
  1019. }
  1020. if (!g_fShutdownCritSec)
  1021. {
  1022. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  1023. _JumpError(hr, error, "InitializeCriticalSection");
  1024. }
  1025. EnterCriticalSection(&g_ShutdownCriticalSection);
  1026. fEntered = TRUE;
  1027. ReleaseOldViews();
  1028. if (State)
  1029. {
  1030. CSASSERT(0 < g_cCallsActive);
  1031. if (0 == --g_cCallsActive && g_fRefuseIncoming)
  1032. {
  1033. DBGPRINT((DBG_SS_CERTSRV, "ExitServer(set last thread exit event)\n"));
  1034. SetEvent(g_hShutdownEvent);
  1035. }
  1036. }
  1037. error:
  1038. if (fEntered)
  1039. {
  1040. LeaveCriticalSection(&g_ShutdownCriticalSection);
  1041. }
  1042. }
  1043. HRESULT
  1044. CertSrvDelinkCAView(
  1045. IN VOID *pvSearch,
  1046. OPTIONAL OUT CAVIEW **ppCAViewOut)
  1047. {
  1048. HRESULT hr;
  1049. BOOL fEntered = FALSE;
  1050. CAVIEW *pCAView;
  1051. CAVIEW **ppCAViewLast;
  1052. if (NULL != ppCAViewOut)
  1053. {
  1054. *ppCAViewOut = NULL;
  1055. }
  1056. if (!g_fShutdownCritSec)
  1057. {
  1058. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  1059. _JumpError(hr, error, "InitializeCriticalSection");
  1060. }
  1061. EnterCriticalSection(&g_ShutdownCriticalSection);
  1062. fEntered = TRUE;
  1063. ppCAViewLast = &g_pCAViewList;
  1064. pCAView = g_pCAViewList;
  1065. for (;;)
  1066. {
  1067. if (NULL == pCAView)
  1068. {
  1069. hr = E_HANDLE;
  1070. _JumpError2(hr, error, "pvSearch not in list", hr);
  1071. }
  1072. if (pvSearch == pCAView->pvSearch)
  1073. {
  1074. break;
  1075. }
  1076. ppCAViewLast = &pCAView->pCAViewNext;
  1077. pCAView = pCAView->pCAViewNext;
  1078. }
  1079. if (NULL != ppCAViewOut)
  1080. {
  1081. *ppCAViewLast = pCAView->pCAViewNext;
  1082. pCAView->pCAViewNext = NULL;
  1083. *ppCAViewOut = pCAView;
  1084. g_cCAView--;
  1085. }
  1086. hr = S_OK;
  1087. error:
  1088. if (fEntered)
  1089. {
  1090. LeaveCriticalSection(&g_ShutdownCriticalSection);
  1091. }
  1092. return(hr);
  1093. }
  1094. HRESULT
  1095. CertSrvLinkCAView(
  1096. IN BOOL fNew,
  1097. IN VOID *pvSearch,
  1098. IN CAVIEW *pCAViewIn)
  1099. {
  1100. HRESULT hr;
  1101. BOOL fEntered = FALSE;
  1102. GetSystemTimeAsFileTime(&pCAViewIn->ftLastAccess);
  1103. if (fNew)
  1104. {
  1105. pCAViewIn->ftCreate = pCAViewIn->ftLastAccess;
  1106. pCAViewIn->pvSearch = pvSearch;
  1107. }
  1108. else
  1109. {
  1110. CSASSERT(pCAViewIn->pvSearch == pvSearch);
  1111. }
  1112. if (!g_fShutdownCritSec)
  1113. {
  1114. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  1115. _JumpError(hr, error, "InitializeCriticalSection");
  1116. }
  1117. EnterCriticalSection(&g_ShutdownCriticalSection);
  1118. fEntered = TRUE;
  1119. pCAViewIn->pCAViewNext = g_pCAViewList;
  1120. g_pCAViewList = pCAViewIn;
  1121. g_cCAView++;
  1122. hr = S_OK;
  1123. error:
  1124. if (fEntered)
  1125. {
  1126. LeaveCriticalSection(&g_ShutdownCriticalSection);
  1127. }
  1128. return(hr);
  1129. }
  1130. // Test for alignment faults in the C runtimes.
  1131. // If the bug hasn't been fixed yet, log an event during cert server startup.
  1132. VOID
  1133. certsrvLogAlignmentFaultStatus()
  1134. {
  1135. HRESULT hr;
  1136. HRESULT hr2;
  1137. ULONG_PTR ExceptionAddress;
  1138. WCHAR awcAddress[2 + 2 * cwcDWORDSPRINTF];
  1139. WCHAR const *apwsz[2];
  1140. WORD cpwsz;
  1141. WCHAR awchr[cwcHRESULTSTRING];
  1142. WCHAR const *pwszStringErr = NULL;
  1143. ExceptionAddress = 0;
  1144. apwsz[1] = NULL;
  1145. hr = S_OK;
  1146. __try
  1147. {
  1148. fwprintf(stdout, L"."); // may fault if I/O buffer is odd aligned
  1149. fprintf(stdout, ".");
  1150. fwprintf(stdout, L".\n"); // may fault if I/O buffer is odd aligned
  1151. hr = S_OK;
  1152. }
  1153. __except(
  1154. ExceptionAddress = (ULONG_PTR) (GetExceptionInformation())->ExceptionRecord->ExceptionAddress,
  1155. hr = myHEXCEPTIONCODE(),
  1156. EXCEPTION_EXECUTE_HANDLER)
  1157. {
  1158. _PrintError(hr, "certsrvLogAlignmentFaultStatus: Exception");
  1159. }
  1160. if (S_OK != hr)
  1161. {
  1162. ALIGNIOB(stdout); // align the stdio buffer
  1163. wprintf(L"STDIO exception: 0x%x\n", hr);
  1164. wsprintf(awcAddress, L"0x%p", (VOID *) ExceptionAddress);
  1165. CSASSERT(wcslen(awcAddress) < ARRAYSIZE(awcAddress));
  1166. apwsz[0] = awcAddress;
  1167. pwszStringErr = myGetErrorMessageText(hr, TRUE);
  1168. apwsz[1] = pwszStringErr;
  1169. if (NULL == pwszStringErr)
  1170. {
  1171. apwsz[1] = myHResultToString(awchr, hr);
  1172. }
  1173. cpwsz = ARRAYSIZE(apwsz);
  1174. hr2 = LogEvent(
  1175. EVENTLOG_WARNING_TYPE,
  1176. MSG_E_STARTUP_EXCEPTION,
  1177. cpwsz,
  1178. apwsz);
  1179. _JumpIfError(hr2, error, "LogEvent");
  1180. }
  1181. error:
  1182. if (NULL != pwszStringErr)
  1183. {
  1184. LocalFree(const_cast<WCHAR *>(pwszStringErr));
  1185. }
  1186. }
  1187. #define MSTOSEC(ms) (((ms) + 1000 - 1)/1000)
  1188. FNLOGEXCEPTION certsrvLogException;
  1189. HRESULT
  1190. certsrvStartServer(
  1191. IN BOOL fConsoleActive)
  1192. {
  1193. HRESULT hr;
  1194. DWORD TimeStart;
  1195. WCHAR awc[ARRAYSIZE(SAFEBOOT_DSREPAIR_STR_W)];
  1196. DWORD cwc;
  1197. DWORD dwEventType = EVENTLOG_ERROR_TYPE;
  1198. DWORD dwIdEvent = 0;
  1199. bool fAuditPrivilegeEnabled = false;
  1200. BOOL fAuditEnabled = FALSE;
  1201. WCHAR const *pwszDC0;
  1202. g_fStartInProgress = TRUE;
  1203. DBGPRINT((
  1204. DBG_SS_CERTSRV,
  1205. "StartServer(tid=%d, fConsoleActive=%u)\n",
  1206. GetCurrentThreadId(),
  1207. fConsoleActive));
  1208. TimeStart = GetTickCount();
  1209. if (fConsoleActive)
  1210. {
  1211. g_fStartAsService = FALSE;
  1212. SetConsoleCtrlHandler(StopServer, TRUE);
  1213. }
  1214. else
  1215. {
  1216. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  1217. }
  1218. if (!FIsServer())
  1219. {
  1220. // don't allow startup on non-server SKU
  1221. hr = HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION);
  1222. _JumpError(hr, error, "FIsServer");
  1223. }
  1224. cwc = GetEnvironmentVariable(L"SAFEBOOT_OPTION", awc, ARRAYSIZE(awc));
  1225. if (0 != cwc &&
  1226. ARRAYSIZE(awc) > cwc &&
  1227. 0 == LSTRCMPIS(awc, SAFEBOOT_DSREPAIR_STR_W))
  1228. {
  1229. // log an error to the event log and stop immediately
  1230. dwEventType = EVENTLOG_INFORMATION_TYPE;
  1231. dwIdEvent = MSG_SAFEBOOT_DETECTED;
  1232. hr = HRESULT_FROM_WIN32(ERROR_RETRY);
  1233. _JumpError(hr, error, "Not starting service: booted in DSRepair mode");
  1234. }
  1235. g_fAdvancedServer = FIsAdvancedServer();
  1236. if (fConsoleActive)
  1237. {
  1238. hr = myEnablePrivilege(SE_AUDIT_NAME, TRUE);
  1239. if (S_OK != hr)
  1240. {
  1241. _PrintError(hr, "myEnablePrivilege(SE_AUDIT_NAME)");
  1242. if (E_ACCESSDENIED != hr || 2 > g_fAdvancedServer)
  1243. {
  1244. goto error;
  1245. }
  1246. }
  1247. else
  1248. {
  1249. fAuditPrivilegeEnabled = true;
  1250. }
  1251. }
  1252. if (!AuthzInitializeResourceManager(
  1253. 0,
  1254. CallbackAccessCheck,
  1255. NULL,
  1256. NULL,
  1257. L"CertSrv",
  1258. &g_AuthzCertSrvRM))
  1259. {
  1260. hr = myHLastError();
  1261. _PrintError(hr, "AuthzInitializeResourceManager");
  1262. if (E_INVALIDARG != hr || (2 > g_fAdvancedServer && IsWhistler()))
  1263. {
  1264. if (HRESULT_FROM_WIN32(ERROR_PRIVILEGE_NOT_HELD) != hr ||
  1265. !fConsoleActive ||
  1266. fAuditPrivilegeEnabled)
  1267. {
  1268. goto error;
  1269. }
  1270. }
  1271. }
  1272. else
  1273. {
  1274. fAuditEnabled = TRUE;
  1275. }
  1276. if (fAuditPrivilegeEnabled)
  1277. {
  1278. hr = myEnablePrivilege(SE_AUDIT_NAME, FALSE);
  1279. _JumpIfError(hr, error, "myDisablePrivilege(SE_AUDIT_NAME)");
  1280. fAuditPrivilegeEnabled = false;
  1281. }
  1282. hr = CoreInit(fAuditEnabled);
  1283. if (S_OK != hr)
  1284. {
  1285. dwIdEvent = MAXDWORD; // Error event already logged
  1286. _JumpError(hr, error, "CoreInit");
  1287. }
  1288. certsrvLogAlignmentFaultStatus();
  1289. myLogExceptionInit(certsrvLogException);
  1290. if (0 == (IF_NORPCICERTREQUEST & g_InterfaceFlags))
  1291. {
  1292. hr = RPCInit();
  1293. if (S_OK != hr)
  1294. {
  1295. dwIdEvent = MSG_E_RPC_INIT;
  1296. _JumpError(hr, error, "RPCInit");
  1297. }
  1298. }
  1299. hr = SetRegistryDcomConfig(fConsoleActive);
  1300. if (S_OK != hr)
  1301. {
  1302. dwIdEvent = MSG_E_REGISTRY_DCOM;
  1303. _JumpError(hr, error, "SetRegistryDcomConfig");
  1304. }
  1305. hr = CertStartClassFactories();
  1306. if (S_OK != hr)
  1307. {
  1308. dwIdEvent = CO_E_WRONG_SERVER_IDENTITY == hr?
  1309. MSG_E_SERVER_IDENTITY : MSG_E_CLASS_FACTORIES;
  1310. _JumpError(hr, error, "CertStartClassFactories");
  1311. }
  1312. {
  1313. // only perform Hash if the auditing is enabled
  1314. if (AUDIT_FILTER_STARTSTOP & g_dwAuditFilter)
  1315. {
  1316. BOOL fSupported;
  1317. BOOL fEnabled;
  1318. CertSrv::CAuditEvent event(
  1319. SE_AUDITID_CERTSRV_SERVICESTART,
  1320. g_dwAuditFilter);
  1321. ULARGE_INTEGER uliKeyUsageCount;
  1322. CAutoLPWSTR autoszCertHash;
  1323. CAutoLPWSTR autoszPublicKeyHash;
  1324. hr = event.AddData(g_pwszDBFileHash); // %1 database hash
  1325. _JumpIfError(hr, error, "CAuditEvent::AddData");
  1326. // retrieve private key usage count if auditing enabled
  1327. uliKeyUsageCount.QuadPart = 0;
  1328. hr = myGetSigningKeyUsageCount(
  1329. g_pCAContextCurrent->hProvCA,
  1330. &fSupported,
  1331. &fEnabled,
  1332. &uliKeyUsageCount);
  1333. _PrintIfError(hr, "myGetSigningKeyUsageCount");
  1334. hr = event.AddData(&uliKeyUsageCount); // %2 key usage count
  1335. _JumpIfError(hr, error, "CAuditEvent::AddData");
  1336. hr = certsrvGetCACertAndKeyHash(
  1337. &autoszCertHash,
  1338. &autoszPublicKeyHash);
  1339. _JumpIfError(hr, error, "certsrvGetCACertAndKeyHash");
  1340. hr = event.AddData((LPCWSTR)autoszCertHash); // %3 CA cert hash
  1341. _JumpIfError(hr, error, "CAuditEvent::AddData");
  1342. hr = event.AddData((LPCWSTR)autoszPublicKeyHash); // %4 CA public key hash
  1343. _JumpIfError(hr, error, "CAuditEvent::AddData");
  1344. hr = event.Report();
  1345. _JumpIfError(hr, error, "CAuditEvent::Report");
  1346. }
  1347. }
  1348. {
  1349. CertSrv::CAuditEvent event(
  1350. SE_AUDITID_CERTSRV_ROLESEPARATIONSTATE,
  1351. g_dwAuditFilter);
  1352. hr = event.AddData(CAuditEvent::RoleSeparationIsEnabled()); // %1 is role separation enabled?
  1353. _JumpIfError(hr, error, "CAuditEvent::AddData");
  1354. hr = event.Report();
  1355. _JumpIfError(hr, error, "CAuditEvent::Report");
  1356. }
  1357. pwszDC0 = (g_fUseDS || L'\0' != g_wszPolicyDCName[0])? L" DC=" : L"";
  1358. if (CERTLOG_TERSE <= g_dwLogLevel)
  1359. {
  1360. WCHAR const *apwsz[3];
  1361. apwsz[0] = g_wszCommonName;
  1362. apwsz[1] = pwszDC0;
  1363. apwsz[2] = g_wszPolicyDCName;
  1364. LogEvent(
  1365. EVENTLOG_INFORMATION_TYPE,
  1366. MSG_I_SERVER_STARTED,
  1367. ARRAYSIZE(apwsz),
  1368. apwsz);
  1369. }
  1370. CONSOLEPRINT1((
  1371. DBG_SS_CERTSRV,
  1372. "Certification Authority Service Ready (%us)%ws%ws ...\n",
  1373. MSTOSEC(GetTickCount() - TimeStart),
  1374. pwszDC0,
  1375. g_wszPolicyDCName));
  1376. g_fStarted = TRUE;
  1377. CSASSERT(S_OK == hr);
  1378. error:
  1379. g_pwszDBFileHash.Cleanup();
  1380. if (fAuditPrivilegeEnabled)
  1381. {
  1382. myEnablePrivilege(SE_AUDIT_NAME, FALSE);
  1383. }
  1384. if (S_OK != hr)
  1385. {
  1386. if (MAXDWORD != dwIdEvent)
  1387. {
  1388. if (0 == dwIdEvent)
  1389. {
  1390. dwIdEvent = MSG_E_GENERIC_STARTUP_FAILURE;
  1391. }
  1392. LogEventStringHResult(
  1393. dwEventType,
  1394. dwIdEvent,
  1395. g_wszCommonName,
  1396. EVENTLOG_INFORMATION_TYPE == dwEventType? S_OK : hr);
  1397. }
  1398. CertSrvStopServer(fConsoleActive);
  1399. // returning error here results in repost to scm
  1400. }
  1401. g_fStartInProgress = FALSE;
  1402. return(hr);
  1403. }
  1404. VOID
  1405. certsrvLogException(
  1406. IN HRESULT hrEvent,
  1407. IN EXCEPTION_POINTERS const *pep,
  1408. OPTIONAL IN char const *, // pszFileName
  1409. IN DWORD dwFile,
  1410. IN DWORD dwLine)
  1411. {
  1412. HRESULT hr;
  1413. WCHAR awcFile[2 + 3 * cwcDWORDSPRINTF];
  1414. WCHAR awcFlags[3 + cwcDWORDSPRINTF];
  1415. WCHAR awcAddress[2 + 2 * cwcDWORDSPRINTF];
  1416. WCHAR const *apwsz[4];
  1417. WORD cpwsz;
  1418. WCHAR awchr[cwcHRESULTSTRING];
  1419. WCHAR const *pwszStringErr = NULL;
  1420. wsprintf(awcFile, L"%u.%u.%u", dwFile, dwLine, MSG_E_EXCEPTION);
  1421. CSASSERT(wcslen(awcFile) < ARRAYSIZE(awcFile));
  1422. wsprintf(awcFlags, L"0x%08x", pep->ExceptionRecord->ExceptionFlags);
  1423. CSASSERT(wcslen(awcFlags) < ARRAYSIZE(awcFlags));
  1424. wsprintf(awcAddress, L"0x%p", pep->ExceptionRecord->ExceptionAddress);
  1425. CSASSERT(wcslen(awcAddress) < ARRAYSIZE(awcAddress));
  1426. apwsz[0] = awcFile;
  1427. apwsz[1] = awcAddress;
  1428. apwsz[2] = awcFlags;
  1429. pwszStringErr = myGetErrorMessageText(hrEvent, TRUE);
  1430. apwsz[3] = pwszStringErr;
  1431. if (NULL == pwszStringErr)
  1432. {
  1433. apwsz[3] = myHResultToString(awchr, hrEvent);
  1434. }
  1435. cpwsz = ARRAYSIZE(apwsz);
  1436. hr = LogEvent(EVENTLOG_ERROR_TYPE, MSG_E_EXCEPTION, cpwsz, apwsz);
  1437. _JumpIfError(hr, error, "LogEvent");
  1438. error:
  1439. if (NULL != pwszStringErr)
  1440. {
  1441. LocalFree(const_cast<WCHAR *>(pwszStringErr));
  1442. }
  1443. }
  1444. DWORD
  1445. CertSrvStartServerThread(
  1446. IN VOID *pvArg)
  1447. {
  1448. HRESULT hr = S_OK;
  1449. DWORD Flags = (DWORD) (ULONG_PTR) pvArg;
  1450. BOOL b;
  1451. ULONG_PTR ulp;
  1452. // Anatomy of startup code
  1453. // if g_fStartAsService, just registers this new thread as the main
  1454. // thread and blocks until the ServiceMain fxn returns.
  1455. // We're in a non-rpc thread; check if we need to create VRoots. I would
  1456. // have liked to have moved this into CoreInit, but we're limited in where
  1457. // we can do this (can't be calling into RPC during RPC call).
  1458. //
  1459. // If the SetupStatus SETUP_ATTEMPT_VROOT_CREATE registry flag is clear,
  1460. // this call is a nop. A separate thread is created to access the IIS
  1461. // metabase. If it hangs, it will be nuked -- after the specified timeout.
  1462. // This call returns immediately, so the only detectable error is likely
  1463. // to be a thread creation problem.
  1464. // if we're doing anything other than starting the service controller,
  1465. // check to see if the vroots need to be created.
  1466. if (0 == (Flags & CSST_STARTSERVICECONTROLLER))
  1467. {
  1468. WCHAR *pwszPath = NULL;
  1469. DWORD cb = sizeof(ENUM_CATYPES);
  1470. DWORD dwType;
  1471. ENUM_CATYPES CAType = ENUM_UNKNOWN_CA;
  1472. HKEY hkey = NULL;
  1473. hr = myRegOpenRelativeKey(
  1474. NULL,
  1475. L"ca",
  1476. RORKF_CREATESUBKEYS,
  1477. &pwszPath,
  1478. NULL, // ppwszName
  1479. &hkey);
  1480. _PrintIfError(hr, "myRegOpenRelativeKey");
  1481. if (S_OK == hr)
  1482. {
  1483. DBGPRINT((DBG_SS_CERTLIBI, "%ws\n", pwszPath));
  1484. cb = sizeof(CAType);
  1485. hr = RegQueryValueEx(
  1486. hkey,
  1487. wszREGCATYPE,
  1488. NULL,
  1489. &dwType,
  1490. (BYTE *) &CAType,
  1491. &cb);
  1492. _PrintIfErrorStr(hr, "RegQueryValueEx", wszREGCATYPE);
  1493. }
  1494. if (pwszPath)
  1495. LocalFree(pwszPath);
  1496. if (hkey)
  1497. RegCloseKey(hkey);
  1498. hr = myModifyVirtualRootsAndFileShares(
  1499. VFF_CREATEVROOTS | // Create VRoots
  1500. VFF_CREATEFILESHARES | // Create File Shares
  1501. VFF_CHECKREGFLAGFIRST | // Skip if reg flag clear
  1502. VFF_CLEARREGFLAGFIRST, // Clear flag before attempt
  1503. CAType,
  1504. TRUE, // asynch call -- don't block
  1505. VFCSEC_TIMEOUT, // wait this long before giving up
  1506. NULL,
  1507. NULL);
  1508. if (S_OK != hr)
  1509. {
  1510. LogEventHResult(
  1511. EVENTLOG_INFORMATION_TYPE,
  1512. MSG_E_IIS_INTEGRATION_ERROR,
  1513. hr);
  1514. }
  1515. }
  1516. // StartServiceCtrlDispatcher should hang until certsrv terminates
  1517. if ((CSST_STARTSERVICECONTROLLER & Flags) &&
  1518. !StartServiceCtrlDispatcher(steDispatchTable))
  1519. {
  1520. hr = myHLastError();
  1521. if (HRESULT_FROM_WIN32(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) != hr)
  1522. {
  1523. _JumpError(hr, error, "StartServiceCtrlDispatcher");
  1524. }
  1525. CONSOLEPRINT0((
  1526. DBG_SS_CERTSRV,
  1527. "CertSrv: Failed to connect to service controller -- running in standalone mode\n"));
  1528. Flags &= ~CSST_STARTSERVICECONTROLLER;
  1529. Flags |= CSST_CONSOLE;
  1530. }
  1531. if (0 == (CSST_STARTSERVICECONTROLLER & Flags))
  1532. {
  1533. DBGPRINT((
  1534. DBG_SS_CERTSRVI,
  1535. "SendMessageTimeout(tid=%d, hwnd=0x%x, msg=0x%x)\n",
  1536. GetCurrentThreadId(),
  1537. g_hwndMain,
  1538. WM_STARTSERVER));
  1539. b = SendMessageTimeout(
  1540. g_hwndMain,
  1541. WM_STARTSERVER,
  1542. (CSST_CONSOLE & Flags)? TRUE : FALSE, // fConsoleActive
  1543. 0,
  1544. SMTO_BLOCK,
  1545. MAXLONG,
  1546. &ulp) != 0;
  1547. if (!b)
  1548. {
  1549. hr = myHLastError();
  1550. _JumpError(hr, error, "SendMessageTimeout");
  1551. }
  1552. else if (ulp != S_OK)
  1553. {
  1554. hr = (HRESULT) ulp;
  1555. _JumpError(hr, error, "SendMessageTimeout");
  1556. }
  1557. }
  1558. if (Flags & CSST_CONSOLE)
  1559. {
  1560. // we're running as console, and so don't have a CRL publishing thread.
  1561. // Use this one since no one cares if it returns
  1562. // if svc, we do this in the caller of this function
  1563. CertSrvBlockThreadUntilStop();
  1564. }
  1565. error:
  1566. // on return, this thread dies
  1567. return(hr);
  1568. }
  1569. VOID
  1570. DisplayUsage(
  1571. IN DWORD idsMsg)
  1572. {
  1573. WCHAR *pwsz = myLoadResourceStringNoCache(g_hInstApp, idsMsg);
  1574. if (NULL != pwsz)
  1575. {
  1576. wprintf(L"%ws", pwsz);
  1577. LocalFree(pwsz);
  1578. }
  1579. }
  1580. VOID
  1581. Usage(
  1582. IN BOOL fUsageInternal)
  1583. {
  1584. DisplayUsage(IDS_USAGE);
  1585. if (fUsageInternal)
  1586. {
  1587. DisplayUsage(IDS_USAGE_FULL);
  1588. #if DBG_COMTEST
  1589. DisplayUsage(IDS_USAGE_COMTEST);
  1590. #endif
  1591. }
  1592. }
  1593. int
  1594. ArgvParseCommandLine(
  1595. IN int argc,
  1596. IN WCHAR *argv[])
  1597. {
  1598. HRESULT hr;
  1599. myVerifyResourceStrings(g_hInstApp);
  1600. hr = E_INVALIDARG;
  1601. while (1 < argc && myIsSwitchChar(argv[1][0]))
  1602. {
  1603. WCHAR *pwsz = argv[1];
  1604. BOOL fUsage = FALSE;
  1605. BOOL fUsageInternal = FALSE;
  1606. while (*++pwsz != L'\0')
  1607. {
  1608. switch (*pwsz)
  1609. {
  1610. #if DBG_COMTEST
  1611. case L'C':
  1612. case L'c':
  1613. fComTest = TRUE;
  1614. break;
  1615. #endif
  1616. case L'N':
  1617. case L'n':
  1618. g_fCreateDB = TRUE;
  1619. break;
  1620. case L'Z':
  1621. case L'z':
  1622. g_fStartAsService = FALSE;
  1623. break;
  1624. case L'S':
  1625. case L's':
  1626. g_CryptSilent = CRYPT_SILENT;
  1627. break;
  1628. case L'?':
  1629. case L'u':
  1630. fUsage = TRUE;
  1631. if (0 == lstrcmp(pwsz, L"uSAGE"))
  1632. {
  1633. fUsageInternal = TRUE;
  1634. }
  1635. // FALLTHROUGH
  1636. default:
  1637. Usage(fUsageInternal);
  1638. if (fUsage)
  1639. {
  1640. goto error;
  1641. }
  1642. _JumpError(hr, error, "bad command line option");
  1643. }
  1644. }
  1645. argc--;
  1646. argv++;
  1647. }
  1648. if (argc != 1)
  1649. {
  1650. Usage(FALSE);
  1651. _JumpError(hr, error, "extra args");
  1652. }
  1653. if (g_fStartAsService)
  1654. {
  1655. BOOL fSilent;
  1656. hr = ServiceQueryInteractiveFlag(&fSilent);
  1657. _PrintIfError(hr, "ServiceQueryInteractiveFlag");
  1658. if (S_OK == hr && fSilent)
  1659. {
  1660. g_CryptSilent = CRYPT_SILENT;
  1661. }
  1662. }
  1663. hr = S_OK;
  1664. error:
  1665. return(hr);
  1666. }
  1667. typedef int (FNARGVMAIN)(
  1668. IN int argc,
  1669. IN WCHAR *argv[]);
  1670. //+------------------------------------------------------------------------
  1671. // FUNCTION: CertArgvMainDispatch
  1672. //
  1673. // NOTES: Takes a WCHAR * command line and chews it up into argc/argv
  1674. // form so it can be passed on to a traditional C-style main.
  1675. //-------------------------------------------------------------------------
  1676. HRESULT
  1677. CertArgvMainDispatch(
  1678. IN FNARGVMAIN *pfnMain,
  1679. IN WCHAR *pwszAppName,
  1680. IN WCHAR const *pwszCmdLine)
  1681. {
  1682. HRESULT hr;
  1683. WCHAR *pwcBuf = NULL;
  1684. WCHAR *apwszArg[20];
  1685. int cArg;
  1686. WCHAR *p;
  1687. WCHAR wcEnd;
  1688. WCHAR const *pwszT;
  1689. pwcBuf = (WCHAR *) LocalAlloc(
  1690. LMEM_FIXED,
  1691. (wcslen(pwszCmdLine) + 1) * sizeof(WCHAR));
  1692. if (NULL == pwcBuf)
  1693. {
  1694. hr = E_OUTOFMEMORY;
  1695. _JumpError(hr, error, "LocalAlloc");
  1696. }
  1697. p = pwcBuf;
  1698. cArg = 0;
  1699. apwszArg[cArg++] = pwszAppName;
  1700. pwszT = pwszCmdLine;
  1701. while (*pwszT != L'\0')
  1702. {
  1703. while (*pwszT == L' ')
  1704. {
  1705. pwszT++;
  1706. }
  1707. if (*pwszT != L'\0')
  1708. {
  1709. wcEnd = L' ';
  1710. if (*pwszT == L'"')
  1711. {
  1712. wcEnd = *pwszT++;
  1713. }
  1714. apwszArg[cArg++] = p;
  1715. if (ARRAYSIZE(apwszArg) <= cArg)
  1716. {
  1717. hr = E_INVALIDARG;
  1718. _JumpError(hr, error, "Too many args");
  1719. }
  1720. while (*pwszT != L'\0' && *pwszT != wcEnd)
  1721. {
  1722. *p++ = *pwszT++;
  1723. }
  1724. *p++ = L'\0';
  1725. if (*pwszT != L'\0')
  1726. {
  1727. pwszT++; // skip blank or quote character
  1728. }
  1729. }
  1730. }
  1731. CSASSERT(
  1732. L'\0' == *pwszCmdLine ||
  1733. wcslen(pwszCmdLine) + 1 >= SAFE_SUBTRACT_POINTERS(p, pwcBuf));
  1734. CSASSERT(ARRAYSIZE(apwszArg) > cArg);
  1735. apwszArg[cArg] = NULL;
  1736. hr = (*pfnMain)(cArg, apwszArg);
  1737. error:
  1738. if (NULL != pwcBuf)
  1739. {
  1740. LocalFree(pwcBuf);
  1741. }
  1742. return(hr);
  1743. }
  1744. //+------------------------------------------------------------------------
  1745. // FUNCTION: MainWndProc(...)
  1746. //-------------------------------------------------------------------------
  1747. LRESULT APIENTRY
  1748. MainWndProc(
  1749. IN HWND hWnd,
  1750. IN UINT msg,
  1751. IN WPARAM wParam,
  1752. IN LPARAM lParam)
  1753. {
  1754. HRESULT hr;
  1755. LPARAM lRet = 0;
  1756. DBGPRINT((
  1757. DBG_SS_CERTSRVI,
  1758. "MainWndProc(tid=%d) msg=0x%x, wp=0x%x, lp=0x%x\n",
  1759. GetCurrentThreadId(),
  1760. msg,
  1761. wParam,
  1762. lParam));
  1763. switch (msg)
  1764. {
  1765. case WM_CREATE:
  1766. case WM_SIZE:
  1767. break;
  1768. case WM_DESTROY:
  1769. if (!g_fStartAsService)
  1770. {
  1771. PostQuitMessage(S_OK);
  1772. }
  1773. break;
  1774. case WM_ENDSESSION:
  1775. // only stop on a real shutdown,
  1776. // never look at this msg if running as svc
  1777. if (g_fStartAsService || (0 == wParam) || (0 != lParam))
  1778. {
  1779. break;
  1780. }
  1781. // fall through
  1782. case WM_STOPSERVER:
  1783. lRet = CertSrvStopServer(!g_fStartAsService);
  1784. break;
  1785. case WM_SYNC_CLOSING_THREADS:
  1786. hr = (HRESULT) lParam;
  1787. // sync: wait for SCM to return control to exiting CertSrvStartServerThread
  1788. if (WAIT_OBJECT_0 != WaitForSingleObject(g_hServiceThread, 10 * 1000))
  1789. {
  1790. hr = WAIT_TIMEOUT;
  1791. }
  1792. PostQuitMessage(hr);
  1793. break;
  1794. case WM_STARTSERVER:
  1795. hr = CoInitializeEx(NULL, GetCertsrvComThreadingModel());
  1796. if (S_FALSE == hr)
  1797. {
  1798. hr = S_OK;
  1799. }
  1800. if (S_OK != hr)
  1801. {
  1802. LogEventString(
  1803. EVENTLOG_ERROR_TYPE,
  1804. MSG_E_OLE_INIT_FAILED,
  1805. NULL);
  1806. _PrintError(hr, "CoInitializeEx");
  1807. }
  1808. else
  1809. {
  1810. hr = certsrvStartServer((BOOL) wParam);
  1811. _PrintIfError(hr, "certsrvStartServer");
  1812. }
  1813. if (S_OK != hr)
  1814. {
  1815. if ((BOOL) wParam) // fConsoleActive
  1816. {
  1817. PostQuitMessage(hr);
  1818. }
  1819. lRet = hr; // set this so caller knows we failed
  1820. }
  1821. break;
  1822. case WM_SUSPENDSERVER:
  1823. break;
  1824. case WM_RESTARTSERVER:
  1825. break;
  1826. default:
  1827. lRet = DefWindowProc(hWnd, msg, wParam, lParam);
  1828. }
  1829. return(lRet);
  1830. }
  1831. /*
  1832. Complete anatomy of certificate server startup/shutdown
  1833. WinMain():
  1834. |
  1835. |g_hSvcThread = CreateThread(CertSrvStartServerThread(SVC_CONTROLLER))
  1836. | |
  1837. |[MessageLoop \
  1838. | processing CertSrvStartServerThread(SVC_CONTROLLER):
  1839. | until |StartSvcCtrlDispatcher(ServiceMain)
  1840. | WM_QUIT] ||ServiceMain:
  1841. | ||RegisterSvcCtrlHandler(ServiceControlHandler())
  1842. | ||hStartThread = CreateThread(CertSrvStartServerThread(0))
  1843. | || |
  1844. | || \
  1845. | || CertSrvStartServerThread(0):
  1846. | || |SendMessage(WM_STARTSERVER)
  1847. | || \return // CertSrvStartServerThread(0)
  1848. | || (Thread Terminates)
  1849. | ||WaitForSingleObject(hStartThread), pinging SCM
  1850. | ||CertSrvBlockThreadUntilStop()
  1851. | |||WaitForSingleObject(g_hSvcStoppingEvent) ***steady state***
  1852. | ||\return // CertSrvBlockThreadUntilStop()
  1853. | ||WaitForSingleObject(g_hSvcStoppedEvent), pinging SCM
  1854. | ||PostMessage(WM_SYNC_CLOSING_THREADS)
  1855. | |\return // StartSvcCtrlDispatcher(ServiceMain)
  1856. | \return // CertSrvStartServerThread(SVC_CONTROLLER)
  1857. | (Thread Terminates)
  1858. | WM_QUIT:
  1859. \ return
  1860. (Process Terminates)
  1861. ServiceControlHandler special functions:
  1862. SERVICE_CONTROL_STOP:
  1863. |PostMessage(WM_STOPSERVER)
  1864. \break
  1865. MessageLoop special functions:
  1866. WM_SYNC_CLOSING_THREADS:
  1867. |WaitForSingleObject(g_hSvcThread)
  1868. |PostQuitMessage() // WM_QUIT to msgloop
  1869. \break
  1870. WM_STOPSERVER:
  1871. |CertSrvStopServer():
  1872. || Signal(g_hServiceStoppingEvent)
  1873. || Signal(g_hServiceStoppedEvent)
  1874. |\ return // CertSrvStopServer()
  1875. \break
  1876. */
  1877. //+------------------------------------------------------------------------
  1878. // Function: wWinMain()
  1879. //
  1880. // Synopsis: Entry Point
  1881. //
  1882. // Arguments: [hInstance] -- Instance handle
  1883. // [hPrevInstance] -- Obsolete
  1884. // [lpCmdLine] -- App command line
  1885. // [nCmdShow] -- Starting show state
  1886. //-------------------------------------------------------------------------
  1887. extern "C" int APIENTRY
  1888. wWinMain(
  1889. IN HINSTANCE hInstance,
  1890. IN HINSTANCE, // hPrevInstance
  1891. IN LPWSTR lpCmdLine,
  1892. IN int /* nCmdShow */ )
  1893. {
  1894. MSG msg;
  1895. WNDCLASSEX wcApp;
  1896. ATOM atomClass;
  1897. HRESULT hr;
  1898. BOOL fCoInit = FALSE;
  1899. WCHAR awchr[cwcHRESULTSTRING];
  1900. WCHAR const *pwszMsgAlloc;
  1901. WCHAR const *pwszMsg;
  1902. _setmode(_fileno(stdout), _O_TEXT);
  1903. _wsetlocale(LC_ALL, L".OCP");
  1904. mySetThreadUILanguage(0);
  1905. CertSrvLogOpen();
  1906. DBGPRINT((DBG_SS_CERTSRVI, "Main Thread = %x\n", GetCurrentThreadId()));
  1907. g_dwDelay0 = GetRegistryDwordValue(L"Delay0");
  1908. g_dwDelay1 = GetRegistryDwordValue(L"Delay1");
  1909. g_dwDelay2 = GetRegistryDwordValue(L"Delay2");
  1910. if (0 != g_dwDelay0)
  1911. {
  1912. DBGPRINT((
  1913. DBG_SS_CERTSRV,
  1914. "wWinMain(0): sleeping %u seconds\n",
  1915. g_dwDelay0));
  1916. Sleep(1000 * g_dwDelay0);
  1917. }
  1918. // Save the current instance
  1919. g_hInstApp = hInstance;
  1920. ZeroMemory(&wcApp, sizeof(wcApp));
  1921. // Set up the application's window class
  1922. wcApp.cbSize = sizeof(wcApp);
  1923. wcApp.lpfnWndProc = MainWndProc;
  1924. wcApp.hInstance = hInstance;
  1925. wcApp.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  1926. wcApp.hCursor = LoadCursor(NULL, IDC_ARROW);
  1927. wcApp.hbrBackground = NULL; // try to not pull in GDI32
  1928. wcApp.lpszClassName = g_wszAppName;
  1929. atomClass = RegisterClassEx(&wcApp);
  1930. if (!atomClass)
  1931. {
  1932. hr = myHLastError();
  1933. _JumpError(hr, error, "RegisterClassEx");
  1934. }
  1935. // Create Main Window
  1936. g_hwndMain = CreateWindowEx(
  1937. 0, // dwExStyle
  1938. (WCHAR const *) atomClass, // lpClassName
  1939. L"Certification Authority",// lpWindowName
  1940. WS_OVERLAPPEDWINDOW, // dwStyle
  1941. //0, // dwStyle
  1942. CW_USEDEFAULT, // x
  1943. CW_USEDEFAULT, // y
  1944. CW_USEDEFAULT, // nWidth
  1945. CW_USEDEFAULT, // nHeight
  1946. NULL, // hWndParent
  1947. NULL, // hMenu
  1948. hInstance, // hInstance
  1949. NULL); // lpParam
  1950. if (NULL == g_hwndMain)
  1951. {
  1952. hr = myHLastError();
  1953. _JumpError(hr, error, "CreateWindowEx");
  1954. }
  1955. DBGPRINT((DBG_SS_CERTSRVI, "Main Window = %x\n", g_hwndMain));
  1956. // Make window visible
  1957. // ShowWindow(g_hwndMain,nCmdShow);
  1958. hr = CertArgvMainDispatch(ArgvParseCommandLine, g_wszAppName, lpCmdLine);
  1959. _JumpIfError2(hr, error, "CertArgvMainDispatch", E_INVALIDARG);
  1960. // Update window client area
  1961. // UpdateWindow(g_hwndMain);
  1962. if (0 != g_dwDelay1)
  1963. {
  1964. DBGPRINT((
  1965. DBG_SS_CERTSRV,
  1966. "wWinMain(1): sleeping %u seconds\n",
  1967. g_dwDelay1));
  1968. Sleep(1000 * g_dwDelay1);
  1969. }
  1970. hr = CoInitializeEx(NULL, GetCertsrvComThreadingModel());
  1971. if (S_OK != hr && S_FALSE != hr)
  1972. {
  1973. LogEventStringHResult(
  1974. EVENTLOG_ERROR_TYPE,
  1975. MSG_E_CO_INITIALIZE,
  1976. g_wszCommonName,
  1977. hr);
  1978. _JumpError(hr, error, "CoInitializeEx");
  1979. }
  1980. fCoInit = TRUE;
  1981. g_hServiceStoppingEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1982. if (NULL == g_hServiceStoppingEvent)
  1983. {
  1984. hr = myHLastError();
  1985. _JumpError(hr, error, "CreateEvent");
  1986. }
  1987. g_hServiceStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1988. if (NULL == g_hServiceStoppedEvent)
  1989. {
  1990. hr = myHLastError();
  1991. _JumpError(hr, error, "CreateEvent");
  1992. }
  1993. g_hCRLManualPublishEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  1994. if (NULL == g_hCRLManualPublishEvent)
  1995. {
  1996. hr = myHLastError();
  1997. _JumpError(hr, error, "CreateEvent");
  1998. }
  1999. g_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  2000. if (NULL == g_hShutdownEvent)
  2001. {
  2002. hr = myHLastError();
  2003. _JumpError(hr, error, "CreateEvent");
  2004. }
  2005. __try
  2006. {
  2007. InitializeCriticalSection(&g_ShutdownCriticalSection);
  2008. g_fShutdownCritSec = TRUE;
  2009. hr = S_OK;
  2010. }
  2011. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  2012. {
  2013. }
  2014. _JumpIfError(hr, error, "InitializeCriticalSection");
  2015. g_hServiceThread = CreateThread(
  2016. NULL, // lpThreadAttributes (Security Attr)
  2017. 0, // dwStackSize
  2018. CertSrvStartServerThread,
  2019. (VOID *) UlongToPtr((g_fStartAsService? CSST_STARTSERVICECONTROLLER : CSST_CONSOLE)), // lpParameter
  2020. 0, // dwCreationFlags
  2021. &g_ServiceThreadId);
  2022. if (NULL == g_hServiceThread)
  2023. {
  2024. hr = myHLastError();
  2025. LogEventStringHResult(
  2026. EVENTLOG_ERROR_TYPE,
  2027. MSG_E_SERVICE_THREAD,
  2028. g_wszCommonName,
  2029. hr);
  2030. _JumpError(hr, error, "CreateThread");
  2031. }
  2032. DBGPRINT((DBG_SS_CERTSRVI, "Service Thread = %x\n", g_ServiceThreadId));
  2033. // Message Loop
  2034. for (;;)
  2035. {
  2036. BOOL b;
  2037. b = GetMessage(&msg, NULL, 0, 0);
  2038. if (!b)
  2039. {
  2040. hr = (HRESULT)msg.wParam;
  2041. _JumpIfError(hr, error, "WM_QUIT");
  2042. break;
  2043. }
  2044. if (-1 == (LONG) b)
  2045. {
  2046. hr = myHLastError();
  2047. _JumpError(hr, error, "GetMessage");
  2048. }
  2049. DBGPRINT((
  2050. DBG_SS_CERTSRVI,
  2051. "DispatchMessage(tid=%d) msg=0x%x, wp=0x%x, lp=0x%x\n",
  2052. GetCurrentThreadId(),
  2053. msg.message,
  2054. msg.wParam,
  2055. msg.lParam));
  2056. DispatchMessage(&msg);
  2057. }
  2058. error:
  2059. if (fCoInit)
  2060. {
  2061. CoUninitialize();
  2062. }
  2063. if (g_fShutdownCritSec)
  2064. {
  2065. DeleteCriticalSection(&g_ShutdownCriticalSection);
  2066. g_fShutdownCritSec = FALSE;
  2067. }
  2068. if (NULL != g_hShutdownEvent)
  2069. {
  2070. CloseHandle(g_hShutdownEvent);
  2071. }
  2072. if (NULL != g_hServiceThread)
  2073. {
  2074. CloseHandle(g_hServiceThread);
  2075. }
  2076. if (NULL != g_hServiceStoppingEvent)
  2077. {
  2078. CloseHandle(g_hServiceStoppingEvent);
  2079. }
  2080. if (NULL != g_hServiceStoppedEvent)
  2081. {
  2082. CloseHandle(g_hServiceStoppedEvent);
  2083. }
  2084. if (NULL != g_hCRLManualPublishEvent)
  2085. {
  2086. CloseHandle(g_hCRLManualPublishEvent);
  2087. }
  2088. CAuditEvent::CleanupAuditEventTypeHandles();
  2089. pwszMsgAlloc = NULL;
  2090. pwszMsg = L"S_OK";
  2091. if (S_OK != hr)
  2092. {
  2093. pwszMsgAlloc = myGetErrorMessageText(hr, TRUE);
  2094. if (NULL != pwszMsgAlloc)
  2095. {
  2096. pwszMsg = pwszMsgAlloc;
  2097. }
  2098. else
  2099. {
  2100. pwszMsg = myHResultToString(awchr, hr);
  2101. }
  2102. }
  2103. _PrintError(hr, "Exit Status");
  2104. CONSOLEPRINT1((DBG_SS_CERTSRV, "Exit Status = %ws\n", pwszMsg));
  2105. if (NULL != pwszMsgAlloc)
  2106. {
  2107. LocalFree(const_cast<WCHAR *>(pwszMsgAlloc));
  2108. }
  2109. myFreeResourceStrings("certsrv.exe");
  2110. myFreeColumnDisplayNames();
  2111. myRegisterMemDump();
  2112. return(hr);
  2113. }