Source code of Windows XP (NT5)
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.

1463 lines
32 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: com.cpp
  7. //
  8. // Contents: Cert Server Policy & Exit module callouts
  9. //
  10. // History: 7-Feb-97 vich created
  11. //
  12. //---------------------------------------------------------------------------
  13. #include <pch.cpp>
  14. #pragma hdrstop
  15. #include <stdio.h>
  16. #include "csdisp.h"
  17. #include "elog.h"
  18. #include "certlog.h"
  19. #include "cscom.h"
  20. #include "csprop.h"
  21. #include "com.h"
  22. #define __dwFILE__ __dwFILE_CERTSRV_COM_CPP__
  23. BSTR g_strPolicyDescription = NULL;
  24. BOOL g_fEnablePolicy = FALSE;
  25. MarshalInterface g_miPolicy;
  26. typedef struct _CERTSRV_COM_CONTEXT_ENTRY
  27. {
  28. USHORT usFlags;
  29. CERTSRV_COM_CONTEXT *pComContext;
  30. } CERTSRV_COM_CONTEXT_ENTRY;
  31. // data structure to pass handles between server and policy/exit modules
  32. CERTSRV_COM_CONTEXT_ENTRY *g_pComContextTable = NULL;
  33. DWORD g_dwComContextCount = 0;
  34. USHORT g_usComContextId = 0; // id increament
  35. CRITICAL_SECTION g_ComCriticalSection;
  36. BOOL g_fComCritSec = FALSE;
  37. CERTSRV_COM_CONTEXT *g_pExitComContext = NULL;
  38. // NOTE: GlobalInterfaceTable better to use than CoMarshalInterface
  39. static IGlobalInterfaceTable* g_pGIT = NULL;
  40. // Clear out any error info
  41. VOID
  42. comClearError(VOID)
  43. {
  44. IErrorInfo *pErrorInfo = NULL;
  45. if (S_OK == GetErrorInfo(0, &pErrorInfo))
  46. {
  47. if (NULL != pErrorInfo)
  48. {
  49. pErrorInfo->Release();
  50. }
  51. }
  52. }
  53. HRESULT
  54. MarshalInterface::SetConfig(
  55. IN LPCWSTR pwszSanitizedName)
  56. {
  57. HRESULT hr = S_OK;
  58. if (NULL == pwszSanitizedName)
  59. {
  60. hr = E_POINTER;
  61. _JumpError(hr, error, "SetConfig");
  62. }
  63. m_szConfig = (LPWSTR) LocalAlloc(
  64. LMEM_FIXED,
  65. (wcslen(g_pwszServerName) + 1 + wcslen(pwszSanitizedName) + 1) * sizeof(WCHAR));
  66. if (NULL == m_szConfig)
  67. {
  68. hr = E_OUTOFMEMORY;
  69. _JumpError(hr, error, "LocalAlloc");
  70. }
  71. // config comes to us without server name: add it
  72. wcscpy((LPWSTR)m_szConfig, g_pwszServerName);
  73. wcscat((LPWSTR)m_szConfig, L"\\");
  74. wcscat((LPWSTR)m_szConfig, pwszSanitizedName);
  75. error:
  76. return hr;
  77. }
  78. VOID
  79. MarshalInterface::Initialize(
  80. IN WCHAR const *pwszProgID,
  81. IN CLSID const *pclsid,
  82. IN DWORD cver,
  83. IN IID const * const *ppiid, // cver elements
  84. IN DWORD const *pcDispatch, // cver elements
  85. IN DISPATCHTABLE *adt)
  86. {
  87. if (NULL != pwszProgID)
  88. {
  89. m_pwszProgID = (LPWSTR) LocalAlloc(
  90. LMEM_FIXED,
  91. (wcslen(pwszProgID) + 1) * sizeof(WCHAR));
  92. if (NULL != m_pwszProgID)
  93. {
  94. wcscpy(m_pwszProgID, pwszProgID);
  95. }
  96. }
  97. m_pclsid = pclsid;
  98. m_cver = cver;
  99. m_ppiid = ppiid;
  100. m_pcDispatch = pcDispatch;
  101. m_adt = adt;
  102. m_fIDispatch = FALSE;
  103. m_dwIFCookie = 0;
  104. m_fInitialized = TRUE;
  105. }
  106. HRESULT
  107. MarshalInterface::Setup(
  108. OUT DISPATCHINTERFACE **ppDispatchInterface)
  109. {
  110. HRESULT hr;
  111. CSASSERT(m_fInitialized);
  112. *ppDispatchInterface = NULL;
  113. hr = DispatchSetup2(
  114. DISPSETUP_COMFIRST,
  115. CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER,
  116. m_pwszProgID,
  117. m_pclsid,
  118. m_cver,
  119. m_ppiid,
  120. m_pcDispatch,
  121. m_adt,
  122. &m_DispatchInterface);
  123. // Don't complain if no class is registered.
  124. _JumpIfError2(
  125. hr,
  126. error,
  127. "DispatchSetup",
  128. HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  129. m_fIDispatch = NULL != m_DispatchInterface.m_adispid;
  130. CSASSERT(
  131. 0 < m_DispatchInterface.m_dwVersion &&
  132. m_cver >= m_DispatchInterface.m_dwVersion);
  133. m_iiid = m_cver - m_DispatchInterface.m_dwVersion;
  134. // create GIT if it doesn't yet exist
  135. if (NULL == g_pGIT)
  136. {
  137. hr = CoCreateInstance(
  138. CLSID_StdGlobalInterfaceTable,
  139. NULL,
  140. CLSCTX_INPROC_SERVER,
  141. IID_IGlobalInterfaceTable,
  142. (void **) &g_pGIT);
  143. _JumpIfError(hr, error, "CoCreateInstance(GIT)");
  144. }
  145. hr = Marshal(&m_DispatchInterface);
  146. _JumpIfError(hr, error, "Marshal");
  147. *ppDispatchInterface = &m_DispatchInterface;
  148. error:
  149. if (S_OK != hr)
  150. {
  151. TearDown();
  152. }
  153. return(hr);
  154. }
  155. VOID
  156. MarshalInterface::TearDown(VOID)
  157. {
  158. if (m_fInitialized)
  159. {
  160. if (NULL != g_pGIT && 0 != m_dwIFCookie)
  161. {
  162. g_pGIT->RevokeInterfaceFromGlobal(m_dwIFCookie);
  163. m_dwIFCookie = 0;
  164. }
  165. DispatchRelease(&m_DispatchInterface);
  166. m_fInitialized = 0;
  167. }
  168. if (NULL != m_pwszProgID)
  169. {
  170. LocalFree(m_pwszProgID);
  171. m_pwszProgID = NULL;
  172. }
  173. if (NULL != m_szConfig)
  174. {
  175. LocalFree((LPWSTR)m_szConfig);
  176. m_szConfig = NULL;
  177. }
  178. }
  179. HRESULT
  180. MarshalInterface::Marshal(
  181. IN DISPATCHINTERFACE *pDispatchInterface)
  182. {
  183. HRESULT hr;
  184. CSASSERT(g_pGIT);
  185. if (g_pGIT == NULL)
  186. {
  187. hr = E_UNEXPECTED;
  188. _JumpIfError(hr, error, "GlobalInterfaceTable not initialized");
  189. }
  190. hr = g_pGIT->RegisterInterfaceInGlobal(
  191. m_fIDispatch?
  192. pDispatchInterface->pDispatch :
  193. pDispatchInterface->pUnknown,
  194. m_fIDispatch? IID_IDispatch : *m_ppiid[m_iiid],
  195. &m_dwIFCookie);
  196. _JumpIfError(hr, error, "RegisterInterfaceInGlobal");
  197. error:
  198. return(hr);
  199. }
  200. HRESULT
  201. MarshalInterface::Remarshal(
  202. OUT DISPATCHINTERFACE *pDispatchInterface)
  203. {
  204. HRESULT hr;
  205. BOOL fRetrying = FALSE;
  206. DBGPRINT((DBG_SS_CERTSRVI, "Remarshal(tid=%d)\n", GetCurrentThreadId()));
  207. CSASSERT(m_fInitialized);
  208. pDispatchInterface->pDispatch = NULL;
  209. pDispatchInterface->pUnknown = NULL;
  210. CSASSERT(g_pGIT);
  211. if (g_pGIT == NULL)
  212. {
  213. hr = E_UNEXPECTED;
  214. _JumpIfError(hr, error, "GlobalInterfaceTable not initialized");
  215. }
  216. hr = g_pGIT->GetInterfaceFromGlobal(
  217. m_dwIFCookie,
  218. m_fIDispatch? IID_IDispatch : *m_ppiid[m_iiid],
  219. m_fIDispatch?
  220. (VOID **) &pDispatchInterface->pDispatch :
  221. (VOID **) &pDispatchInterface->pUnknown);
  222. DBGPRINT((
  223. DBG_SS_CERTSRVI,
  224. "Remarshal(tid=%d) --> 0x%x\n",
  225. GetCurrentThreadId(),
  226. hr));
  227. _JumpIfError(hr, error, "GetInterfaceFromGlobal");
  228. // Copy invariants to the marshaled interface:
  229. pDispatchInterface->SetIID(m_ppiid[m_iiid]);
  230. pDispatchInterface->pDispatchTable = m_DispatchInterface.pDispatchTable;
  231. pDispatchInterface->m_cDispatchTable = m_DispatchInterface.m_cDispatchTable;
  232. pDispatchInterface->m_cdispid = m_DispatchInterface.m_cdispid;
  233. pDispatchInterface->m_adispid = m_DispatchInterface.m_adispid;
  234. error:
  235. return(hr);
  236. }
  237. VOID
  238. MarshalInterface::Unmarshal(
  239. IN OUT DISPATCHINTERFACE *pDispatchInterface)
  240. {
  241. // Don't free global DISPID table from marshaled interface:
  242. pDispatchInterface->m_adispid = NULL;
  243. DispatchRelease(pDispatchInterface);
  244. }
  245. // forwards
  246. VOID PolicyRelease(VOID);
  247. VOID ExitRelease(VOID);
  248. #define COMCONTEXTCOUNTMIN 4
  249. #define COMCONTEXTCOUNTMAX 1024 // must less than 64K
  250. #define COMCONTEXTCOUNTDEFAULT 20
  251. HRESULT
  252. ComInit(VOID)
  253. {
  254. HRESULT hr;
  255. HKEY hKey = NULL;
  256. DWORD dwSize;
  257. CSASSERT(NULL == g_pComContextTable);
  258. hr = RegOpenKey(HKEY_LOCAL_MACHINE, g_wszRegKeyConfigPath, &hKey);
  259. _JumpIfError(hr, error, "RegOpenKey(Config)");
  260. dwSize = sizeof(g_dwComContextCount);
  261. hr = RegQueryValueEx(
  262. hKey,
  263. wszREGDBSESSIONCOUNT, // just use db session count
  264. // bug, may not be logic related
  265. NULL,
  266. NULL,
  267. (BYTE *) &g_dwComContextCount,
  268. &dwSize);
  269. if (S_OK != hr)
  270. {
  271. _PrintErrorStr(hr, "RegQueryValueEx", wszREGDBSESSIONCOUNT);
  272. g_dwComContextCount = COMCONTEXTCOUNTDEFAULT;
  273. }
  274. if (COMCONTEXTCOUNTMIN > g_dwComContextCount)
  275. {
  276. g_dwComContextCount = COMCONTEXTCOUNTMIN;
  277. }
  278. if (COMCONTEXTCOUNTMAX < g_dwComContextCount)
  279. {
  280. g_dwComContextCount = COMCONTEXTCOUNTMAX;
  281. }
  282. g_pComContextTable = (CERTSRV_COM_CONTEXT_ENTRY *) LocalAlloc(
  283. LMEM_FIXED | LMEM_ZEROINIT,
  284. g_dwComContextCount *
  285. sizeof(g_pComContextTable[0]));
  286. if (NULL == g_pComContextTable)
  287. {
  288. hr = E_OUTOFMEMORY;
  289. _JumpError(hr, error, "LocalAlloc");
  290. }
  291. __try
  292. {
  293. InitializeCriticalSection(&g_ComCriticalSection);
  294. g_fComCritSec = TRUE;
  295. hr = S_OK;
  296. }
  297. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  298. {
  299. }
  300. error:
  301. if (NULL != hKey)
  302. {
  303. RegCloseKey(hKey);
  304. }
  305. return hr;
  306. }
  307. VOID
  308. ComShutDown(VOID)
  309. {
  310. if (NULL != g_pComContextTable)
  311. {
  312. PolicyRelease();
  313. ExitRelease();
  314. if (NULL != g_pGIT)
  315. {
  316. g_pGIT->Release();
  317. g_pGIT = NULL;
  318. }
  319. if (g_fComCritSec)
  320. {
  321. DeleteCriticalSection(&g_ComCriticalSection);
  322. g_fComCritSec = FALSE;
  323. }
  324. LocalFree(g_pComContextTable);
  325. g_pComContextTable = NULL;
  326. g_dwComContextCount = 0;
  327. }
  328. }
  329. HRESULT
  330. RegisterComContext(
  331. IN CERTSRV_COM_CONTEXT *pComContext,
  332. IN OUT DWORD *pdwIndex)
  333. {
  334. HRESULT hr = S_OK;
  335. BOOL fCS = FALSE;
  336. DWORD i;
  337. CSASSERT(NULL != pComContext);
  338. CSASSERT(NULL != g_pComContextTable);
  339. if (NULL == pComContext)
  340. {
  341. hr = E_POINTER;
  342. _JumpError(hr, error, "null com context pointer");
  343. }
  344. if (!g_fComCritSec)
  345. {
  346. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  347. _JumpError(hr, error, "InitializeCriticalSection");
  348. }
  349. EnterCriticalSection(&g_ComCriticalSection);
  350. fCS = TRUE;
  351. for (i = 0; NULL != g_pComContextTable[i].pComContext; ++i)
  352. {
  353. if (i + 1 == g_dwComContextCount)
  354. {
  355. //hr = HRESULT_FROM_WIN32(ERROR_BUSY);
  356. hr = HRESULT_FROM_WIN32(RPC_S_SERVER_TOO_BUSY);
  357. _JumpError(hr, error, "com context table full");
  358. }
  359. }
  360. // pick an id
  361. if (0 == g_usComContextId)
  362. {
  363. // it could make module context to be 0 which is a special flag
  364. // avoid 0
  365. ++g_usComContextId;
  366. }
  367. g_pComContextTable[i].usFlags = g_usComContextId++;
  368. // point to com context
  369. g_pComContextTable[i].pComContext = pComContext;
  370. *pdwIndex = i;
  371. error:
  372. if (fCS)
  373. {
  374. LeaveCriticalSection(&g_ComCriticalSection);
  375. }
  376. return hr;
  377. }
  378. VOID
  379. UnregisterComContext(
  380. IN CERTSRV_COM_CONTEXT *pComContext,
  381. IN DWORD dwIndex)
  382. {
  383. HRESULT hr = S_OK;
  384. BOOL fCS = FALSE;
  385. // if shutdown in progress after wait timeout
  386. if (NULL == g_pComContextTable)
  387. {
  388. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  389. _JumpError(hr, error, "NULL g_pComContextTable");
  390. }
  391. CSASSERT(dwIndex < g_dwComContextCount);
  392. if (!g_fComCritSec)
  393. {
  394. hr = HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED);
  395. _JumpError(hr, error, "InitializeCriticalSection");
  396. }
  397. EnterCriticalSection(&g_ComCriticalSection);
  398. fCS = TRUE;
  399. if (dwIndex < g_dwComContextCount)
  400. {
  401. CSASSERT(0 != g_pComContextTable[dwIndex].usFlags);
  402. CSASSERT(NULL != g_pComContextTable[dwIndex].pComContext);
  403. CSASSERT(pComContext == g_pComContextTable[dwIndex].pComContext);
  404. g_pComContextTable[dwIndex].usFlags = 0;
  405. g_pComContextTable[dwIndex].pComContext = NULL;
  406. }
  407. error:
  408. if (fCS)
  409. {
  410. LeaveCriticalSection(&g_ComCriticalSection);
  411. }
  412. }
  413. CERTSRV_COM_CONTEXT *
  414. GetComContextFromIndex(
  415. IN DWORD dwIndex)
  416. {
  417. CERTSRV_COM_CONTEXT *pComContext = NULL;
  418. CSASSERT(NULL != g_pComContextTable);
  419. CSASSERT(dwIndex < g_dwComContextCount);
  420. if (dwIndex < g_dwComContextCount)
  421. {
  422. CSASSERT(0 != g_pComContextTable[dwIndex].usFlags);
  423. CSASSERT(NULL != g_pComContextTable[dwIndex].pComContext);
  424. pComContext = g_pComContextTable[dwIndex].pComContext;
  425. }
  426. return(pComContext);
  427. }
  428. DWORD
  429. ComContextToModuleContext(
  430. IN DWORD dwComContextIndex)
  431. {
  432. CSASSERT(NULL != g_pComContextTable);
  433. CSASSERT(dwComContextIndex < g_dwComContextCount);
  434. CSASSERT(0 != g_pComContextTable[dwComContextIndex].usFlags);
  435. CSASSERT(NULL != g_pComContextTable[dwComContextIndex].pComContext);
  436. DWORD dwHigh =
  437. (dwComContextIndex << 16) & 0xFFFF0000; // move index to high 16 bits
  438. DWORD dwLow =
  439. ((DWORD)g_pComContextTable[dwComContextIndex].usFlags) & 0x0000FFFF;
  440. return(dwHigh | dwLow);
  441. }
  442. HRESULT
  443. ModuleContextToComContextIndex(
  444. IN DWORD dwModuleContext,
  445. OUT DWORD *pdwIndex)
  446. {
  447. HRESULT hr = S_OK;
  448. USHORT usFlags = (USHORT)(dwModuleContext & 0x0000FFFF);
  449. DWORD dwIndex = (dwModuleContext >> 16) & 0x0000FFFF;
  450. CSASSERT(NULL != pdwIndex);
  451. *pdwIndex = MAXDWORD;
  452. if (dwIndex >= g_dwComContextCount ||
  453. 0 == usFlags ||
  454. g_pComContextTable[dwIndex].usFlags != usFlags)
  455. {
  456. // module passed a bogus handle
  457. hr = E_INVALIDARG;
  458. _JumpError(hr, error, "invalid context from policy/exit");
  459. }
  460. CSASSERT(NULL != g_pComContextTable[dwIndex].pComContext);
  461. // for return
  462. *pdwIndex = dwIndex;
  463. error:
  464. return hr;
  465. }
  466. HRESULT
  467. ModuleContextToRequestId(
  468. IN DWORD dwModuleContext,
  469. OUT DWORD *pdwRequestId)
  470. {
  471. DWORD dwIndex;
  472. HRESULT hr = ModuleContextToComContextIndex(dwModuleContext, &dwIndex);
  473. _JumpIfError(hr, error, "ModuleContextToComContextIndex");
  474. // for return
  475. *pdwRequestId = g_pComContextTable[dwIndex].pComContext->RequestId;
  476. error:
  477. return hr;
  478. }
  479. HRESULT
  480. ComVerifyRequestContext(
  481. IN BOOL fAllowZero,
  482. IN DWORD Flags,
  483. IN LONG Context,
  484. OUT DWORD *pRequestId)
  485. {
  486. HRESULT hr;
  487. *pRequestId = 0;
  488. if (0 == Context)
  489. {
  490. hr = S_OK;
  491. if (!fAllowZero)
  492. {
  493. hr = E_HANDLE;
  494. }
  495. }
  496. else
  497. {
  498. switch (PROPCALLER_MASK & Flags)
  499. {
  500. case PROPCALLER_EXIT:
  501. hr = ModuleContextToRequestId(Context, pRequestId);
  502. _JumpIfError(hr, error, "ModuleContextToRequestId");
  503. break;
  504. case PROPCALLER_POLICY:
  505. hr = ModuleContextToRequestId(Context, pRequestId);
  506. _JumpIfError(hr, error, "ModuleContextToRequestId");
  507. break;
  508. default:
  509. CSASSERT(FALSE);
  510. hr = E_HANDLE;
  511. _JumpError(hr, error, "unexpected policy/exit flags");
  512. break;
  513. }
  514. }
  515. error:
  516. return(hr);
  517. }
  518. VOID
  519. LogComError(
  520. OPTIONAL IN WCHAR const *pwszModuleDescription,
  521. IN WCHAR const *pwszMethod,
  522. IN HRESULT ErrCode,
  523. IN BOOL fException,
  524. IN ULONG_PTR ExceptionAddress,
  525. IN IID const *piid,
  526. IN DWORD dwIdEvent)
  527. {
  528. BSTR bstrErrorMessage = NULL;
  529. WCHAR const *pwszStringErr = NULL;
  530. if (CERTLOG_ERROR <= g_dwLogLevel)
  531. {
  532. HRESULT hr;
  533. WCHAR const *apwsz[5];
  534. WCHAR awchr[cwcHRESULTSTRING];
  535. WCHAR awcAddress[2 + 2 * cwcDWORDSPRINTF];
  536. if (fException)
  537. {
  538. apwsz[3] = awcAddress;
  539. wsprintf(awcAddress, L"0x%p", ExceptionAddress);
  540. }
  541. else
  542. {
  543. IErrorInfo *pErrorInfo = NULL;
  544. // Get the error info
  545. hr = GetErrorInfo(0, &pErrorInfo);
  546. if (S_OK == hr && NULL != pErrorInfo)
  547. {
  548. GUID ErrorGuid;
  549. hr = pErrorInfo->GetGUID(&ErrorGuid);
  550. if (S_OK == hr && InlineIsEqualGUID(ErrorGuid, *piid))
  551. {
  552. hr = pErrorInfo->GetDescription(&bstrErrorMessage);
  553. if (S_OK == hr && NULL != bstrErrorMessage)
  554. {
  555. myRegisterMemAlloc(bstrErrorMessage, -1, CSM_SYSALLOC);
  556. }
  557. }
  558. SetErrorInfo(0, pErrorInfo);
  559. pErrorInfo->Release();
  560. }
  561. apwsz[3] = NULL != bstrErrorMessage? bstrErrorMessage : L"";
  562. }
  563. if (S_OK == ErrCode)
  564. {
  565. if (!fException && NULL == bstrErrorMessage)
  566. {
  567. goto error; // skip if no error, no exception & no com error
  568. }
  569. // This is the best generic fit for policy module initialization.
  570. // Hopefully it's generic enough to not be too confusing.
  571. ErrCode = CRYPT_E_NOT_FOUND;
  572. _PrintError(hr, "Invented ErrCode");
  573. }
  574. apwsz[0] = NULL != pwszModuleDescription? pwszModuleDescription : L"";
  575. apwsz[1] = pwszMethod;
  576. // some errors like textual conversions. no HRESULT pasted on here
  577. pwszStringErr = myGetErrorMessageText(ErrCode, FALSE);
  578. apwsz[2] = myHResultToStringRaw(awchr, ErrCode);
  579. apwsz[4] = pwszStringErr == NULL? L"" : pwszStringErr;
  580. hr = LogEvent(EVENTLOG_ERROR_TYPE, dwIdEvent, ARRAYSIZE(apwsz), apwsz);
  581. _PrintIfError(hr, "LogEvent");
  582. }
  583. error:
  584. if (NULL != bstrErrorMessage)
  585. {
  586. SysFreeString(bstrErrorMessage);
  587. }
  588. if (NULL != pwszStringErr)
  589. {
  590. LocalFree(const_cast<WCHAR *>(pwszStringErr));
  591. }
  592. }
  593. VOID
  594. LogPolicyError(
  595. IN HRESULT ErrCode,
  596. IN WCHAR const *pwszMethod,
  597. IN BOOL fException,
  598. IN ULONG_PTR ExceptionAddress)
  599. {
  600. LogComError(
  601. g_strPolicyDescription,
  602. pwszMethod,
  603. ErrCode,
  604. fException,
  605. ExceptionAddress,
  606. &IID_ICertPolicy,
  607. fException? MSG_E_POLICY_EXCEPTION : MSG_E_POLICY_ERROR);
  608. }
  609. VOID
  610. LogExitError(
  611. IN HRESULT ErrCode,
  612. IN WCHAR const *pwszDescription,
  613. IN WCHAR const *pwszMethod,
  614. IN BOOL fException,
  615. IN ULONG_PTR ExceptionAddress)
  616. {
  617. LogComError(
  618. pwszDescription,
  619. pwszMethod,
  620. ErrCode,
  621. fException,
  622. ExceptionAddress,
  623. &IID_ICertExit,
  624. fException? MSG_E_EXIT_EXCEPTION : MSG_E_EXIT_ERROR);
  625. }
  626. HRESULT
  627. PolicyInit(
  628. IN WCHAR const *pwszConfig,
  629. IN WCHAR const *pwszSanitizedName)
  630. {
  631. HRESULT hr;
  632. DISPATCHINTERFACE *pdiPolicy;
  633. BOOL fException = FALSE;
  634. ULONG_PTR ExceptionAddress = NULL;
  635. // support installable modules
  636. CLSID clsidPolicy;
  637. LPOLESTR lpszProgID = NULL;
  638. DBGPRINT((DBG_SS_CERTSRVI, "PolicyInit: tid=%d\n", GetCurrentThreadId()));
  639. comClearError();
  640. __try
  641. {
  642. // get active module
  643. hr = myGetActiveModule(
  644. NULL,
  645. pwszSanitizedName,
  646. TRUE,
  647. 0,
  648. &lpszProgID,
  649. &clsidPolicy);
  650. _LeaveIfError(hr, "myGetActiveModule");
  651. g_miPolicy.Initialize(
  652. lpszProgID,
  653. &clsidPolicy,
  654. ARRAYSIZE(s_acPolicyDispatch),
  655. s_apPolicyiid,
  656. s_acPolicyDispatch,
  657. g_adtPolicy);
  658. // free olestr
  659. CoTaskMemFree(lpszProgID);
  660. hr = g_miPolicy.SetConfig(pwszConfig);
  661. _LeaveIfError(hr, "SetConfig");
  662. hr = g_miPolicy.Setup(&pdiPolicy);
  663. // Don't complain if no class is registered.
  664. _LeaveIfError2(hr, "Setup", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  665. hr = Policy_GetDescription(pdiPolicy, &g_strPolicyDescription);
  666. _PrintIfError(hr, "Policy_GetDescription");
  667. hr = Policy_Initialize(pdiPolicy, pwszConfig);
  668. _LeaveIfError(hr, "Policy_Initialize");
  669. g_fEnablePolicy = TRUE; // we have a policy module loaded now
  670. hr = S_OK;
  671. CONSOLEPRINT1((
  672. DBG_SS_CERTSRV,
  673. "Policy Module Enabled (%ws)\n",
  674. g_strPolicyDescription));
  675. }
  676. __except(
  677. ExceptionAddress = (ULONG_PTR) (GetExceptionInformation())->ExceptionRecord->ExceptionAddress,
  678. hr = myHEXCEPTIONCODE(),
  679. EXCEPTION_EXECUTE_HANDLER)
  680. {
  681. _PrintError(hr, "Initialize: Exception");
  682. fException = TRUE;
  683. }
  684. //error:
  685. LogPolicyError(hr, L"PolicyInit", fException, ExceptionAddress);
  686. return(hr);
  687. }
  688. VOID
  689. PolicyRelease(VOID)
  690. {
  691. HRESULT hr;
  692. BOOL fException = FALSE;
  693. ULONG_PTR ExceptionAddress = NULL;
  694. DBGPRINT((DBG_SS_CERTSRV, "PolicyRelease: tid=%d\n", GetCurrentThreadId()));
  695. comClearError();
  696. __try
  697. {
  698. // if we loaded a policy module
  699. if (g_fEnablePolicy)
  700. {
  701. DISPATCHINTERFACE diPolicy;
  702. hr = g_miPolicy.Remarshal(&diPolicy);
  703. _PrintIfError(hr, "Remarshal");
  704. if (hr == S_OK)
  705. {
  706. Policy_ShutDown(&diPolicy);
  707. g_miPolicy.Unmarshal(&diPolicy);
  708. }
  709. g_fEnablePolicy = FALSE;
  710. }
  711. if (NULL != g_strPolicyDescription)
  712. {
  713. SysFreeString(g_strPolicyDescription);
  714. g_strPolicyDescription = NULL;
  715. }
  716. g_miPolicy.TearDown();
  717. }
  718. __except(
  719. ExceptionAddress = (ULONG_PTR) (GetExceptionInformation())->ExceptionRecord->ExceptionAddress,
  720. hr = myHEXCEPTIONCODE(),
  721. EXCEPTION_EXECUTE_HANDLER)
  722. {
  723. _PrintError(hr, "ShutDown: Exception");
  724. fException = TRUE;
  725. }
  726. LogPolicyError(hr, L"PolicyRelease", fException, ExceptionAddress);
  727. }
  728. HRESULT
  729. PolicyVerifyRequest(
  730. IN WCHAR const *pwszConfig,
  731. IN LONG RequestId,
  732. IN LONG Flags,
  733. IN BOOL fNewRequest,
  734. IN DWORD dwComContextIndex,
  735. OUT LPWSTR *ppwszDispositionMessage, // LocalAlloced.
  736. OUT DWORD *pVerifyStatus) // VR_PENDING || VR_INSTANT_OK || VR_INSTANT_BAD
  737. {
  738. HRESULT hr;
  739. ULONG_PTR ExceptionAddress = NULL;
  740. DWORD rc;
  741. LONG Result;
  742. DISPATCHINTERFACE diPolicy;
  743. BOOL fMustRelease = FALSE;
  744. BSTR bstrDispositionDetail = NULL;
  745. CERTSRV_COM_CONTEXT *pComContext;
  746. comClearError();
  747. if (!g_fEnablePolicy)
  748. {
  749. hr = S_OK;
  750. rc = VR_INSTANT_OK;
  751. goto error;
  752. }
  753. rc = VR_INSTANT_BAD;
  754. hr = g_miPolicy.Remarshal(&diPolicy);
  755. _JumpIfError(hr, error, "Remarshal");
  756. fMustRelease = TRUE;
  757. pComContext = GetComContextFromIndex(dwComContextIndex);
  758. if (NULL == pComContext)
  759. {
  760. hr = E_HANDLE;
  761. _JumpError(hr, error, "NULL com context");
  762. }
  763. pComContext->RequestId = RequestId;
  764. __try
  765. {
  766. hr = Policy_VerifyRequest(
  767. &diPolicy,
  768. pwszConfig,
  769. ComContextToModuleContext(dwComContextIndex),
  770. fNewRequest,
  771. Flags,
  772. &Result);
  773. _LeaveIfError(hr, "Policy_VerifyRequest");
  774. switch (Result)
  775. {
  776. default:
  777. if (SUCCEEDED(Result))
  778. {
  779. hr = E_INVALIDARG;
  780. _LeaveError(Result, "Result");
  781. }
  782. // FALLTHROUGH
  783. case VR_PENDING:
  784. case VR_INSTANT_OK:
  785. case VR_INSTANT_BAD:
  786. rc = Result;
  787. break;
  788. }
  789. }
  790. __except(
  791. ExceptionAddress = (ULONG_PTR) (GetExceptionInformation())->ExceptionRecord->ExceptionAddress,
  792. hr = myHEXCEPTIONCODE(),
  793. EXCEPTION_EXECUTE_HANDLER)
  794. {
  795. _PrintError(hr, "VerifyRequest: Exception");
  796. LogPolicyError(hr, L"VerifyRequest", TRUE, ExceptionAddress);
  797. }
  798. pComContext->RequestId = 0;
  799. error:
  800. // Errors will be logged at the coreVerifyRequest level
  801. if (NULL != ppwszDispositionMessage)
  802. {
  803. HRESULT hr2;
  804. IErrorInfo *pErrorInfo = NULL;
  805. *ppwszDispositionMessage = NULL;
  806. hr2 = GetErrorInfo(0, &pErrorInfo);
  807. if (S_OK == hr2 && NULL != pErrorInfo)
  808. {
  809. GUID ErrorGuid;
  810. hr2 = pErrorInfo->GetGUID(&ErrorGuid);
  811. if (S_OK == hr2 && InlineIsEqualGUID(ErrorGuid, IID_ICertPolicy))
  812. {
  813. hr2 = pErrorInfo->GetDescription(&bstrDispositionDetail);
  814. if (S_OK == hr2 && NULL != bstrDispositionDetail)
  815. {
  816. myRegisterMemAlloc(bstrDispositionDetail, -1, CSM_SYSALLOC);
  817. *ppwszDispositionMessage = (LPWSTR) LocalAlloc(
  818. LMEM_FIXED,
  819. SysStringByteLen(bstrDispositionDetail) + sizeof(WCHAR));
  820. if (NULL != *ppwszDispositionMessage)
  821. {
  822. wcscpy(*ppwszDispositionMessage, bstrDispositionDetail);
  823. }
  824. SysFreeString(bstrDispositionDetail);
  825. }
  826. }
  827. SetErrorInfo(0, pErrorInfo);
  828. pErrorInfo->Release();
  829. }
  830. }
  831. if (fMustRelease)
  832. {
  833. g_miPolicy.Unmarshal(&diPolicy);
  834. }
  835. *pVerifyStatus = rc;
  836. return(hr);
  837. }
  838. typedef struct _EXITMOD
  839. {
  840. MarshalInterface *pmi;
  841. BOOL fEnabled;
  842. BSTR strDescription;
  843. LONG EventMask;
  844. } EXITMOD;
  845. BOOL g_fEnableExit = FALSE;
  846. EXITMOD *g_aExitMod = NULL;
  847. DWORD g_cExitMod;
  848. LONG g_ExitEventMask;
  849. TCHAR g_wszRegKeyExitClsid[] = wszCLASS_CERTEXIT TEXT("\\Clsid");
  850. VOID
  851. ExitModRelease(
  852. OPTIONAL IN OUT EXITMOD *pExitMod)
  853. {
  854. HRESULT hr;
  855. if (NULL != pExitMod)
  856. {
  857. MarshalInterface *pmiExit = pExitMod->pmi;
  858. if (NULL != pmiExit)
  859. {
  860. __try
  861. {
  862. pmiExit->TearDown();
  863. }
  864. __except(hr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  865. {
  866. _PrintIfError(hr, "TearDown");
  867. }
  868. delete pmiExit;
  869. pExitMod->pmi = NULL;
  870. }
  871. if (NULL != pExitMod->strDescription)
  872. {
  873. SysFreeString(pExitMod->strDescription);
  874. pExitMod->strDescription = NULL;
  875. }
  876. }
  877. }
  878. HRESULT
  879. ExitModInit(
  880. IN WCHAR const *pwszProgId,
  881. IN CLSID const *pclsid,
  882. IN WCHAR const *pwszConfig)
  883. {
  884. HRESULT hr;
  885. EXITMOD *pExitMod = NULL;
  886. DISPATCHINTERFACE *pdiExit;
  887. MarshalInterface *pmiExit;
  888. CERTSRV_COM_CONTEXT ComContext;
  889. BOOL fException = FALSE;
  890. ULONG_PTR ExceptionAddress = NULL;
  891. comClearError();
  892. __try
  893. {
  894. if (0 == g_cExitMod)
  895. {
  896. pExitMod = (EXITMOD *) LocalAlloc(LMEM_FIXED, sizeof(*g_aExitMod));
  897. }
  898. else
  899. {
  900. pExitMod = (EXITMOD *) LocalReAlloc(
  901. g_aExitMod,
  902. (g_cExitMod + 1) * sizeof(*g_aExitMod),
  903. LMEM_MOVEABLE);
  904. }
  905. if (NULL == pExitMod)
  906. {
  907. hr = E_OUTOFMEMORY;
  908. _JumpError(hr, error, 0 == g_cExitMod? "LocalAlloc" : "LocalReAlloc");
  909. }
  910. g_aExitMod = pExitMod;
  911. pExitMod += g_cExitMod++;
  912. // Zero structure here because a previous failed Exit Module load may leave
  913. // garbage in leftover structure, causing LocalReAlloc to do nothing.
  914. ZeroMemory(pExitMod, sizeof(*pExitMod));
  915. pmiExit = new MarshalInterface;
  916. if (NULL == pmiExit)
  917. {
  918. hr = E_OUTOFMEMORY;
  919. _JumpError(hr, error, "new");
  920. }
  921. pExitMod->pmi = pmiExit;
  922. pmiExit->Initialize(
  923. pwszProgId,
  924. pclsid,
  925. ARRAYSIZE(s_acExitDispatch),
  926. s_apExitiid,
  927. s_acExitDispatch,
  928. g_adtExit);
  929. hr = pmiExit->SetConfig(pwszConfig);
  930. _JumpIfError(hr, error, "SetConfig");
  931. hr = pmiExit->Setup(&pdiExit);
  932. // Don't complain if no class is registered.
  933. _JumpIfError2(hr, error, "Setup", HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
  934. ComContext.iExitModActive = g_cExitMod - 1;
  935. g_pExitComContext = &ComContext;
  936. hr = Exit_Initialize(
  937. pdiExit,
  938. pExitMod->strDescription,
  939. pwszConfig,
  940. &pExitMod->EventMask);
  941. _JumpIfError(hr, error, "Exit_Initialize");
  942. pExitMod->fEnabled = TRUE;
  943. g_fEnableExit = TRUE; // we have at least one exit module loaded now
  944. g_ExitEventMask |= pExitMod->EventMask;
  945. hr = Exit_GetDescription(pdiExit, &pExitMod->strDescription);
  946. _PrintIfError(hr, "Exit_GetDescription");
  947. hr = S_OK;
  948. CONSOLEPRINT3((
  949. DBG_SS_CERTSRV,
  950. "Exit Module[%d] Enabled: %x (%ws)\n",
  951. g_cExitMod,
  952. pExitMod->EventMask,
  953. pExitMod->strDescription));
  954. }
  955. __except(
  956. ExceptionAddress = (ULONG_PTR) (GetExceptionInformation())->ExceptionRecord->ExceptionAddress,
  957. hr = myHEXCEPTIONCODE(),
  958. EXCEPTION_EXECUTE_HANDLER)
  959. {
  960. _PrintError(hr, "Initialize: Exception");
  961. fException = TRUE;
  962. }
  963. error:
  964. LogExitError(
  965. hr,
  966. pExitMod->strDescription,
  967. L"ExitModeInit",
  968. fException,
  969. ExceptionAddress);
  970. if (S_OK != hr && NULL != pExitMod)
  971. {
  972. ExitModRelease(pExitMod);
  973. CSASSERT(0 != g_cExitMod);
  974. g_cExitMod--;
  975. }
  976. // reset
  977. g_pExitComContext = NULL;
  978. return(hr);
  979. }
  980. HRESULT
  981. ExitModNotify(
  982. IN EXITMOD *pExitMod,
  983. IN LONG Event,
  984. IN LONG RequestId,
  985. IN DWORD dwComContextIndex)
  986. {
  987. HRESULT hr;
  988. DISPATCHINTERFACE diExit;
  989. BOOL fMustRelease = FALSE;
  990. CERTSRV_COM_CONTEXT *pComContext;
  991. BOOL fException = FALSE;
  992. ULONG_PTR ExceptionAddress = NULL;
  993. comClearError();
  994. __try
  995. {
  996. if (!pExitMod->fEnabled || 0 == (Event & pExitMod->EventMask))
  997. {
  998. hr = S_OK;
  999. goto error;
  1000. }
  1001. hr = pExitMod->pmi->Remarshal(&diExit);
  1002. _JumpIfError(hr, error, "Remarshal");
  1003. fMustRelease = TRUE;
  1004. pComContext = GetComContextFromIndex(dwComContextIndex);
  1005. if (NULL == pComContext)
  1006. {
  1007. hr = E_HANDLE;
  1008. _JumpError(hr, error, "null com context");
  1009. }
  1010. pComContext->RequestId = RequestId;
  1011. hr = Exit_Notify(
  1012. &diExit,
  1013. pExitMod->strDescription,
  1014. Event,
  1015. ComContextToModuleContext(dwComContextIndex));
  1016. pComContext->RequestId = 0;
  1017. if (S_OK != hr)
  1018. {
  1019. //_PrintError(hr, "Exit_Notify");
  1020. goto error;
  1021. }
  1022. }
  1023. __except(
  1024. ExceptionAddress = (ULONG_PTR) (GetExceptionInformation())->ExceptionRecord->ExceptionAddress,
  1025. hr = myHEXCEPTIONCODE(),
  1026. EXCEPTION_EXECUTE_HANDLER)
  1027. {
  1028. _PrintError(hr, "Notify: Exception");
  1029. fException = TRUE;
  1030. }
  1031. error:
  1032. LogExitError(
  1033. hr,
  1034. pExitMod->strDescription,
  1035. L"Notify",
  1036. fException,
  1037. ExceptionAddress);
  1038. if (fMustRelease)
  1039. {
  1040. pExitMod->pmi->Unmarshal(&diExit);
  1041. }
  1042. return(hr);
  1043. }
  1044. HRESULT
  1045. ExitInit(
  1046. IN WCHAR const *pwszConfig,
  1047. IN WCHAR const *pwszSanitizedName)
  1048. {
  1049. HRESULT hr;
  1050. LPOLESTR pwszProgId = NULL;
  1051. CLSID clsid;
  1052. DWORD i;
  1053. CSASSERT(NULL == g_aExitMod);
  1054. CSASSERT(0 == g_cExitMod);
  1055. CSASSERT(0 == g_ExitEventMask);
  1056. CSASSERT(!g_fEnableExit);
  1057. for (i = 0; ; i++)
  1058. {
  1059. if (NULL != pwszProgId)
  1060. {
  1061. CoTaskMemFree(pwszProgId);
  1062. pwszProgId = NULL;
  1063. }
  1064. // get active module
  1065. hr = myGetActiveModule(
  1066. NULL,
  1067. pwszSanitizedName,
  1068. FALSE,
  1069. i,
  1070. &pwszProgId,
  1071. &clsid);
  1072. _JumpIfError(hr, error, "myGetActiveModule");
  1073. hr = ExitModInit(pwszProgId, &clsid, pwszConfig);
  1074. _PrintIfError(hr, "ExitModInit");
  1075. }
  1076. hr = S_OK;
  1077. error:
  1078. if (NULL != pwszProgId)
  1079. {
  1080. CoTaskMemFree(pwszProgId);
  1081. }
  1082. return(hr);
  1083. }
  1084. VOID
  1085. ExitRelease(VOID)
  1086. {
  1087. HRESULT hr;
  1088. ExitNotify(EXITEVENT_SHUTDOWN, 0, MAXDWORD);
  1089. for ( ; 0 != g_cExitMod; g_cExitMod--)
  1090. {
  1091. ExitModRelease(&g_aExitMod[g_cExitMod - 1]);
  1092. }
  1093. if (g_aExitMod)
  1094. {
  1095. LocalFree(g_aExitMod);
  1096. g_aExitMod = NULL;
  1097. }
  1098. }
  1099. HRESULT
  1100. ExitNotify(
  1101. IN LONG Event,
  1102. IN LONG RequestId,
  1103. IN DWORD dwComContextIndex)
  1104. {
  1105. HRESULT hr = S_OK;
  1106. HRESULT hr2;
  1107. CERTSRV_COM_CONTEXT ComContext;
  1108. CERTSRV_COM_CONTEXT *pComContext;
  1109. BOOL fRegComContext = FALSE;
  1110. if (MAXDWORD == dwComContextIndex)
  1111. {
  1112. ZeroMemory(&ComContext, sizeof(ComContext));
  1113. pComContext = &ComContext;
  1114. hr = RegisterComContext(pComContext, &dwComContextIndex);
  1115. _JumpIfError(hr, error, "RegisterComContext");
  1116. fRegComContext = TRUE;
  1117. }
  1118. else
  1119. {
  1120. pComContext = GetComContextFromIndex(dwComContextIndex);
  1121. if (NULL == pComContext)
  1122. {
  1123. hr = E_HANDLE;
  1124. _JumpError(hr, error, "null com context");
  1125. }
  1126. }
  1127. CSASSERT(0 == (Event & (Event >> 1))); // must be a single bit!
  1128. if (!g_fEnableExit || 0 == (Event & g_ExitEventMask))
  1129. {
  1130. goto error;
  1131. }
  1132. for (
  1133. pComContext->iExitModActive = 0;
  1134. pComContext->iExitModActive < g_cExitMod;
  1135. pComContext->iExitModActive++)
  1136. {
  1137. hr2 = ExitModNotify(
  1138. &g_aExitMod[pComContext->iExitModActive],
  1139. Event,
  1140. RequestId,
  1141. dwComContextIndex);
  1142. if (S_OK == hr)
  1143. {
  1144. hr = hr2;
  1145. }
  1146. _PrintIfError(hr2, "ExitModNotify");
  1147. }
  1148. error:
  1149. if (fRegComContext)
  1150. {
  1151. // context is used in local
  1152. UnregisterComContext(&ComContext, dwComContextIndex);
  1153. }
  1154. else if (NULL != pComContext)
  1155. {
  1156. // return index
  1157. pComContext->iExitModActive = 0;
  1158. }
  1159. return(hr);
  1160. }
  1161. HRESULT
  1162. ExitGetActiveModule(
  1163. IN LONG Context,
  1164. OUT MarshalInterface **ppmi)
  1165. {
  1166. HRESULT hr;
  1167. // This is for exit module only, it expects Context
  1168. // to be 0. It will use g_pExitComContext instead of table
  1169. // init
  1170. *ppmi = NULL;
  1171. #if 0
  1172. DWORD dwIndex;
  1173. hr = ModuleContextToComContextIndex(Context, &dwIndex);
  1174. _JumpIfError(hr, error, "ModuleContextToComContextIndex");
  1175. // return
  1176. *ppmi =
  1177. g_aExitMod[g_pComContextTable[dwIndex].pComContext->iExitModActive].pmi;
  1178. #endif
  1179. CSASSERT(0 == Context);
  1180. CSASSERT(NULL != g_pExitComContext);
  1181. if (0 != Context || NULL == g_pExitComContext)
  1182. {
  1183. hr = E_UNEXPECTED;
  1184. _JumpError(hr, error, "unexpected exit context");
  1185. }
  1186. // return
  1187. *ppmi = g_aExitMod[g_pExitComContext->iExitModActive].pmi;
  1188. hr = S_OK;
  1189. error:
  1190. return (hr);
  1191. }
  1192. HRESULT
  1193. ComGetClientInfo(
  1194. IN LONG Context,
  1195. IN DWORD dwComContextIndex,
  1196. OUT CERTSRV_COM_CONTEXT **ppComContext)
  1197. {
  1198. HRESULT hr;
  1199. *ppComContext = NULL;
  1200. if (MAXDWORD == dwComContextIndex)
  1201. {
  1202. hr = ModuleContextToComContextIndex(Context, &dwComContextIndex);
  1203. _JumpIfError(hr, error, "ModuleContextToComContextIndex");
  1204. }
  1205. *ppComContext = g_pComContextTable[dwComContextIndex].pComContext;
  1206. hr = S_OK;
  1207. error:
  1208. return(hr);
  1209. }
  1210. BSTR
  1211. ExitGetDescription(
  1212. IN DWORD iExitMod)
  1213. {
  1214. BSTR str = NULL;
  1215. if (iExitMod < g_cExitMod)
  1216. {
  1217. str = g_aExitMod[iExitMod].strDescription;
  1218. }
  1219. return(str);
  1220. }