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.

1547 lines
36 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows NT
  4. //
  5. // Copyright (C) Microsoft Corporation, 1995 - 1998
  6. //
  7. // File: mscep.cpp
  8. //
  9. // Contents: Cisco enrollment protocal implementation
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "global.hxx"
  13. #include <dbgdef.h>
  14. CRITICAL_SECTION CriticalSec;
  15. CRITICAL_SECTION PasswordCriticalSec;
  16. static BOOL g_fInit=FALSE;
  17. static BOOL g_fRelease=FALSE;
  18. HCERTSTORE g_HCACertStore=NULL;
  19. CEP_RA_INFO g_RAInfo;
  20. CEP_CA_INFO g_CAInfo={NULL, NULL, NULL, NULL, NULL, FALSE, NULL};
  21. HCRYPTASN1MODULE ICM_hAsn1Module=NULL;
  22. HMODULE g_hMSCEPModule=NULL;
  23. HANDLE g_hEventSource = NULL;
  24. ULARGE_INTEGER g_ftRAExpiration;
  25. ULARGE_INTEGER g_ftRACloseToExpire;
  26. ULARGE_INTEGER g_ftRAWarn;
  27. LPWSTR g_pwszComputerName=NULL;
  28. //-----------------------------------------------------------------------------------
  29. //
  30. // DllMain
  31. //
  32. //------------------------------------------------------------------------------------
  33. BOOL WINAPI DllMain(
  34. HMODULE hInstDLL,
  35. DWORD fdwReason,
  36. LPVOID lpvReserved
  37. )
  38. {
  39. BOOL fResult = TRUE;
  40. //we use the try{}except here to prevent malicous requests
  41. __try
  42. {
  43. switch(fdwReason)
  44. {
  45. case DLL_PROCESS_ATTACH:
  46. g_hMSCEPModule=hInstDLL;
  47. InitializeCriticalSection(&CriticalSec);
  48. InitializeCriticalSection(&PasswordCriticalSec);
  49. CEPASN_Module_Startup();
  50. if (0 == (ICM_hAsn1Module = I_CryptInstallAsn1Module(
  51. CEPASN_Module, 0, NULL)))
  52. fResult = FALSE;
  53. g_hEventSource = RegisterEventSourceW(NULL, MSCEP_EVENT_LOG);
  54. break;
  55. case DLL_PROCESS_DETACH:
  56. if (g_hEventSource)
  57. DeregisterEventSource(g_hEventSource);
  58. I_CryptUninstallAsn1Module(ICM_hAsn1Module);
  59. CEPASN_Module_Cleanup();
  60. DeleteCriticalSection(&PasswordCriticalSec);
  61. DeleteCriticalSection(&CriticalSec);
  62. break;
  63. }
  64. }
  65. __except(EXCEPTION_EXECUTE_HANDLER)
  66. {
  67. // return failure
  68. fResult = FALSE;
  69. }
  70. return(fResult);
  71. }
  72. //-----------------------------------------------------------------------------------
  73. //
  74. // DllRegisterServer
  75. //
  76. //------------------------------------------------------------------------------------
  77. STDAPI DllRegisterServer()
  78. {
  79. HRESULT hr = S_OK;
  80. return hr;
  81. }
  82. //-----------------------------------------------------------------------------------
  83. //
  84. // DllUnregisterServer
  85. //
  86. //------------------------------------------------------------------------------------
  87. STDAPI DllUnregisterServer()
  88. {
  89. HRESULT hr = S_OK;
  90. return hr;
  91. }
  92. //-----------------------------------------------------------------------------------
  93. //
  94. // DecodeIssuerAndSerialNumber
  95. //
  96. // Decoding routine to decode a IssuerAndSerialNumber blob and return the
  97. // SerialNumber
  98. //
  99. //------------------------------------------------------------------------------------
  100. BOOL WINAPI GetSerialNumberFromBlob(BYTE *pbEncoded,
  101. DWORD cbEncoded,
  102. CRYPT_INTEGER_BLOB *pSerialNumber)
  103. {
  104. BOOL fResult = FALSE;
  105. ASN1error_e Asn1Err;
  106. ASN1decoding_t pDec;
  107. IssuerAndSerialNumber *pisn=NULL;
  108. if((!pSerialNumber) || (!pbEncoded))
  109. goto InvalidArgErr;
  110. pDec = I_CryptGetAsn1Decoder(ICM_hAsn1Module);
  111. if (0 != (Asn1Err = PkiAsn1Decode(
  112. pDec,
  113. (void **)&pisn,
  114. IssuerAndSerialNumber_PDU,
  115. pbEncoded,
  116. cbEncoded)))
  117. goto DecodeIssuerAndSerialNumberError;
  118. //we now reverse the byte
  119. PkiAsn1ReverseBytes(pisn->serialNumber.value,
  120. pisn->serialNumber.length);
  121. pSerialNumber->cbData=pisn->serialNumber.length;
  122. if(!(pSerialNumber->pbData = (BYTE *)malloc(pSerialNumber->cbData)))
  123. goto MemoryErr;
  124. memcpy(pSerialNumber->pbData, pisn->serialNumber.value, pSerialNumber->cbData);
  125. fResult = TRUE;
  126. CommonReturn:
  127. if(pisn)
  128. PkiAsn1FreeInfo(pDec, IssuerAndSerialNumber_PDU, pisn);
  129. return fResult;
  130. ErrorReturn:
  131. fResult=FALSE;
  132. goto CommonReturn;
  133. SET_ERROR(InvalidArgErr, E_INVALIDARG);
  134. SET_ERROR_VAR(DecodeIssuerAndSerialNumberError, PkiAsn1ErrToHr(Asn1Err))
  135. SET_ERROR(MemoryErr, E_OUTOFMEMORY);
  136. }
  137. //-----------------------------------------------------------------------------------
  138. //
  139. // GetExtensionVersion
  140. //
  141. // IIS initialization code
  142. //
  143. //------------------------------------------------------------------------------------
  144. BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
  145. {
  146. BOOL fResult = FALSE;
  147. HRESULT hr = S_OK;
  148. BOOL fOleInit=FALSE;
  149. DWORD dwSize=0;
  150. //copy the version/description
  151. pVer->dwExtensionVersion = MAKELONG( HSE_VERSION_MINOR,
  152. HSE_VERSION_MAJOR );
  153. lstrcpyn( pVer->lpszExtensionDesc,
  154. "This is the implementation of cisco enrollment protocol",
  155. HSE_MAX_EXT_DLL_NAME_LEN);
  156. if(g_fInit)
  157. {
  158. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_LOADED, 0);
  159. return TRUE;
  160. }
  161. EnterCriticalSection(&CriticalSec);
  162. //retest in the case of lock: the second thread has passed the 1st test
  163. //and was waiting for the criticcal section
  164. if(g_fInit)
  165. {
  166. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_LOADED, 0);
  167. LeaveCriticalSection(&CriticalSec);
  168. return TRUE;
  169. }
  170. memset(&g_ftRAExpiration, 0, sizeof(ULARGE_INTEGER));
  171. memset(&g_ftRACloseToExpire, 0, sizeof(ULARGE_INTEGER));
  172. memset(&g_ftRAWarn, 0, sizeof(ULARGE_INTEGER));
  173. //get the computer name
  174. dwSize=0;
  175. GetComputerNameExW(ComputerNamePhysicalDnsHostname,
  176. NULL,
  177. &dwSize);
  178. g_pwszComputerName=(LPWSTR)malloc(dwSize * sizeof(WCHAR));
  179. if(NULL==g_pwszComputerName)
  180. goto InitErr;
  181. if(!GetComputerNameExW(ComputerNamePhysicalDnsHostname,
  182. g_pwszComputerName,
  183. &dwSize))
  184. goto InitErr;
  185. //initialize the state information
  186. if(FAILED(hr=CoInitialize(NULL)))
  187. goto OleErr;
  188. fOleInit=TRUE;
  189. if(!InitCAInformation(&g_CAInfo))
  190. {
  191. LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAILED_CA_INFO, 1, g_pwszComputerName);
  192. goto InitErr;
  193. }
  194. if(!GetCACertFromInfo(&g_CAInfo, &g_HCACertStore))
  195. {
  196. LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAILED_CA_CERT, 1, g_pwszComputerName);
  197. goto InitErr;
  198. }
  199. if(!GetRAInfo(&g_RAInfo))
  200. {
  201. LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAILED_RA_CERT, 1, g_pwszComputerName);
  202. goto InitErr;
  203. }
  204. //we add the RA and CA cert to the g_hCACertStore
  205. if(!CertAddCertificateContextToStore(g_HCACertStore,
  206. g_RAInfo.pRACert,
  207. CERT_STORE_ADD_NEW,
  208. NULL))
  209. goto InitErr;
  210. if(!CertAddCertificateContextToStore(g_HCACertStore,
  211. g_RAInfo.pRASign,
  212. CERT_STORE_ADD_NEW,
  213. NULL))
  214. goto InitErr;
  215. if(!InitHashTable())
  216. goto InitErr;
  217. if(!InitPasswordTable())
  218. goto InitErr;
  219. if(!InitRequestTable())
  220. goto InitErr;
  221. //copy the time when the RAs will expire
  222. if( 1 == CompareFileTime(&((g_RAInfo.pRACert->pCertInfo)->NotAfter), &((g_RAInfo.pRASign->pCertInfo)->NotAfter)))
  223. {
  224. g_ftRAExpiration.QuadPart=((ULARGE_INTEGER UNALIGNED *)&((g_RAInfo.pRASign->pCertInfo)->NotAfter))->QuadPart;
  225. }
  226. else
  227. g_ftRAExpiration.QuadPart=((ULARGE_INTEGER UNALIGNED *)&((g_RAInfo.pRACert->pCertInfo)->NotAfter))->QuadPart;
  228. //start to give out warnings two weeks before the RA Certificates expire
  229. g_ftRACloseToExpire.QuadPart=g_ftRAExpiration.QuadPart-Int32x32To64(FILETIME_TICKS_PER_SECOND, OVERLAP_TWO_WEEKS);
  230. fResult=TRUE;
  231. CommonReturn:
  232. g_fInit=fResult;
  233. if(fResult)
  234. {
  235. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_LOADED, 0);
  236. }
  237. else
  238. {
  239. LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_FAILED_TO_LOAD, 0);
  240. }
  241. LeaveCriticalSection(&CriticalSec);
  242. return fResult;
  243. ErrorReturn:
  244. //clean up the global data.
  245. if(g_HCACertStore)
  246. {
  247. CertCloseStore(g_HCACertStore, 0);
  248. g_HCACertStore=NULL;
  249. }
  250. FreeRAInformation(&g_RAInfo);
  251. FreeCAInformation(&g_CAInfo);
  252. if(fOleInit)
  253. CoUninitialize();
  254. fResult=FALSE;
  255. goto CommonReturn;
  256. TRACE_ERROR(InitErr);
  257. SET_ERROR_VAR(OleErr, hr);
  258. }
  259. //--------------------------------------------------------------------
  260. //
  261. // Verify if the user is a member of the BUILTIN\Administrators group
  262. //
  263. //--------------------------------------------------------------------
  264. BOOL WINAPI IsUserInLocalAdminGroup()
  265. {
  266. BOOL bIsMember=FALSE;
  267. SID_IDENTIFIER_AUTHORITY siaNtAuthority=SECURITY_NT_AUTHORITY;
  268. HANDLE hThread=NULL; //no need to close
  269. SID * psidLocalAdmins=NULL;
  270. HANDLE hToken=NULL;
  271. hThread=GetCurrentThread();
  272. if(NULL == hThread)
  273. goto error;
  274. //we want to check with the impersonation token
  275. if(!OpenThreadToken(hThread,
  276. TOKEN_IMPERSONATE | TOKEN_QUERY,
  277. FALSE,
  278. &hToken))
  279. goto error;
  280. // get the well-known SID
  281. if (!AllocateAndInitializeSid(&siaNtAuthority, 2,
  282. SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
  283. 0, 0, 0, 0, 0, 0, (void **)&psidLocalAdmins))
  284. goto error;
  285. // check for membership
  286. if (!CheckTokenMembership(hToken, psidLocalAdmins, &bIsMember))
  287. {
  288. bIsMember=FALSE;
  289. goto error;
  290. }
  291. error:
  292. if(hToken)
  293. {
  294. CloseHandle(hToken);
  295. }
  296. if (NULL!=psidLocalAdmins)
  297. {
  298. FreeSid(psidLocalAdmins);
  299. }
  300. return bIsMember;
  301. }
  302. //-----------------------------------------------------------------------------------
  303. //
  304. // CEPPasswordAllowALL
  305. //
  306. // Detect if the registry to allow password to everyone is enabled for
  307. // standalone CA ONLY.
  308. //
  309. //------------------------------------------------------------------------------------
  310. BOOL WINAPI CEPPasswordAllowALL()
  311. {
  312. BOOL fAllowALL=FALSE;
  313. DWORD cbData=0;
  314. DWORD dwData=0;
  315. DWORD dwType=0;
  316. HKEY hKey=NULL;
  317. if(ERROR_SUCCESS == RegOpenKeyExU(
  318. HKEY_LOCAL_MACHINE,
  319. MSCEP_LOCATION,
  320. 0,
  321. KEY_READ,
  322. &hKey))
  323. {
  324. cbData=sizeof(dwData);
  325. if(ERROR_SUCCESS == RegQueryValueExU(
  326. hKey,
  327. MSCEP_KEY_ALLOW_ALL,
  328. NULL,
  329. &dwType,
  330. (BYTE *)&dwData,
  331. &cbData))
  332. {
  333. if (REG_DWORD == dwType)
  334. {
  335. if(0 != dwData)
  336. {
  337. fAllowALL=TRUE;
  338. }
  339. }
  340. }
  341. }
  342. if(hKey)
  343. RegCloseKey(hKey);
  344. return fAllowALL;
  345. }
  346. //-----------------------------------------------------------------------------------
  347. //
  348. // GetExtensionVersion.
  349. //
  350. // IIS load/initialization code.
  351. //
  352. //------------------------------------------------------------------------------------
  353. DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
  354. {
  355. DWORD dwHttp = HSE_STATUS_ERROR;
  356. LPSTR pszTagValue=NULL;
  357. LPSTR pszMsgValue=NULL;
  358. DWORD dwOpType = 0;
  359. DWORD cbData=0;
  360. DWORD cbFree=0;
  361. CHAR szBuff[1024];
  362. DWORD cbBuff;
  363. LPSTR pszContentType=NULL;
  364. DWORD dwException=0;
  365. BOOL f401Response=FALSE;
  366. ULARGE_INTEGER ftTime;
  367. HANDLE hThread=NULL; //no need to close
  368. BYTE *pbData=NULL;
  369. HANDLE hToken=NULL;
  370. //we use the try{}except here to prevent malicous requests
  371. __try {
  372. EnterCriticalSection(&CriticalSec);
  373. if(NULL==pECB)
  374. goto InvalidArgErr;
  375. if(NULL==(pECB->lpszQueryString))
  376. goto InvalidArgErr;
  377. //user are asking for the CEP information/password
  378. if(0 == strlen(pECB->lpszQueryString))
  379. {
  380. pszContentType=CONTENT_TYPE_HTML;
  381. if(g_RAInfo.fPassword)
  382. {
  383. if(IsAnonymousAccess(pECB))
  384. {
  385. //LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_PASSWORD_ANONYMOUS, 1, g_pwszComputerName);
  386. f401Response=TRUE;
  387. }
  388. else
  389. {
  390. if(g_CAInfo.fEnterpriseCA)
  391. {
  392. //we want to check with the impersonation token
  393. if(S_OK != CheckACLOnCertTemplate(TRUE, g_CAInfo.bstrDSName, wszCERTTYPE_IPSEC_INTERMEDIATE_OFFLINE))
  394. {
  395. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_PASSWORD_TEMPLATE, 1, g_pwszComputerName);
  396. //return HTML error messages
  397. if(!OperationDisplayAccessHTML(&pbData, &cbData))
  398. goto OperationErr;
  399. if(NULL == pbData)
  400. goto OperationErr;
  401. }
  402. }
  403. else
  404. {
  405. if(!CEPPasswordAllowALL())
  406. {
  407. if(FALSE == IsUserInLocalAdminGroup())
  408. {
  409. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_PASSWORD_STANDALONE, 1, g_pwszComputerName);
  410. //return HTML error messages
  411. if(!OperationDisplayAccessHTML(&pbData, &cbData))
  412. goto OperationErr;
  413. if(NULL == pbData)
  414. goto OperationErr;
  415. }
  416. }
  417. }
  418. }
  419. }
  420. if((FALSE==f401Response) && (NULL==pbData))
  421. {
  422. if(!OperationGetDisplayInfoForCEP(g_CAInfo.pwszCAHash,
  423. g_CAInfo.hProv,
  424. g_RAInfo.fPassword,
  425. &pbData,
  426. &cbData))
  427. goto OperationErr;
  428. }
  429. }
  430. else
  431. {
  432. hThread=GetCurrentThread();
  433. if(NULL != hThread)
  434. {
  435. if(OpenThreadToken(hThread,
  436. TOKEN_IMPERSONATE | TOKEN_QUERY,
  437. FALSE,
  438. &hToken))
  439. {
  440. if(hToken)
  441. {
  442. //no need to check for return here. If this failed, just go on
  443. RevertToSelf();
  444. }
  445. }
  446. }
  447. //get the operation
  448. if(NULL==(pszTagValue=GetTagValue(pECB->lpszQueryString, GET_TAG_OP)))
  449. {
  450. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_OPERATION, 1, g_pwszComputerName);
  451. goto InvalidArgErr;
  452. }
  453. if(strlen(pszTagValue) > strlen(GET_OP_CA))
  454. {
  455. if(0==_strnicmp(pszTagValue, GET_OP_CA, strlen(GET_OP_CA)))
  456. {
  457. dwOpType = OPERATION_GET_CACERT;
  458. pszTagValue += strlen(GET_OP_CA);
  459. }
  460. }
  461. if( 0 == dwOpType)
  462. {
  463. if(strlen(pszTagValue) > strlen(GET_OP_PKI))
  464. {
  465. if(0==_strnicmp(pszTagValue, GET_OP_PKI, strlen(GET_OP_PKI)))
  466. {
  467. dwOpType = OPERATION_GET_PKI;
  468. pszTagValue += strlen(GET_OP_PKI);
  469. }
  470. }
  471. }
  472. if(0 == dwOpType)
  473. {
  474. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_OPERATION, 1, g_pwszComputerName);
  475. goto InvalidArgErr;
  476. }
  477. //get the message value
  478. if(NULL==(pszMsgValue=GetTagValue(pszTagValue, GET_TAG_MSG)))
  479. {
  480. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_NO_MESSAGE, 1, g_pwszComputerName);
  481. goto InvalidArgErr;
  482. }
  483. //check if the RA certificates are close to expire
  484. GetSystemTimeAsFileTime((LPFILETIME)&ftTime);
  485. if(ftTime.QuadPart >= g_ftRAExpiration.QuadPart)
  486. {
  487. //RA Certificate has expired
  488. LogSCEPEvent(0, FALSE, S_OK, EVENT_SCEP_RA_EXPIRE, 1, g_pwszComputerName);
  489. }
  490. else
  491. {
  492. if(ftTime.QuadPart >= g_ftRACloseToExpire.QuadPart)
  493. {
  494. if( (0 == g_ftRAWarn.QuadPart) || (ftTime.QuadPart >= g_ftRAWarn.QuadPart))
  495. {
  496. //RA Certificate is close to expire
  497. LogSCEPEvent(0, FALSE, S_OK, EVENT_SCEP_RA_CLOSE_TO_EXPIRE, 1, g_pwszComputerName);
  498. //only give out an warning once an hour
  499. g_ftRAWarn.QuadPart = ftTime.QuadPart + Int32x32To64(FILETIME_TICKS_PER_SECOND, OVERLAP_ONE_HOUR);
  500. }
  501. }
  502. }
  503. //get the return blob
  504. switch(dwOpType)
  505. {
  506. case OPERATION_GET_CACERT:
  507. if(!OperationGetCACert(g_HCACertStore,
  508. pszMsgValue,
  509. &pbData,
  510. &cbData))
  511. {
  512. LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_MSCEP_GET_CA_CERT_FAILED, 1, g_pwszComputerName);
  513. goto OperationErr;
  514. }
  515. pszContentType = CONTENT_TYPE_CA_RA;
  516. break;
  517. case OPERATION_GET_PKI:
  518. if(!OperationGetPKI(
  519. &g_RAInfo,
  520. &g_CAInfo,
  521. pszMsgValue,
  522. &pbData,
  523. &cbData))
  524. goto OperationErr;
  525. pszContentType = CONTENT_TYPE_PKI;
  526. break;
  527. default:
  528. goto InvalidArgErr;
  529. break;
  530. }
  531. }
  532. if(f401Response)
  533. {
  534. if(!(pECB->ServerSupportFunction(pECB->ConnID,HSE_REQ_SEND_RESPONSE_HEADER,
  535. ACCESS_MESSAGE,
  536. NULL,
  537. NULL)))
  538. {
  539. LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_SCEP_SERVER_SUPPORT, 1, g_pwszComputerName);
  540. goto WriteErr;
  541. }
  542. dwHttp = HSE_STATUS_ERROR;
  543. }
  544. else
  545. {
  546. //write the header and the real data
  547. pECB->dwHttpStatusCode = 200;
  548. // write headers
  549. sprintf(szBuff, "Content-Length: %d\r\nContent-Type: %hs\r\n\r\n", cbData, pszContentType);
  550. cbBuff = strlen(szBuff);
  551. if(!(pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_SEND_RESPONSE_HEADER, NULL, &cbBuff, (LPDWORD)szBuff)))
  552. {
  553. LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_SCEP_SERVER_SUPPORT, 1, g_pwszComputerName);
  554. goto WriteErr;
  555. }
  556. // write users data
  557. cbFree=cbData;
  558. if(!(pECB->WriteClient(pECB->ConnID, pbData, &cbData, HSE_IO_SYNC)))
  559. {
  560. LogSCEPEvent(0, TRUE, HRESULT_FROM_WIN32(GetLastError()), EVENT_SCEP_WRITE_DATA, 1, g_pwszComputerName);
  561. goto WriteErr;
  562. }
  563. dwHttp = HSE_STATUS_SUCCESS;
  564. }
  565. } __except(EXCEPTION_EXECUTE_HANDLER)
  566. {
  567. dwException = GetExceptionCode();
  568. goto ExceptionErr;
  569. }
  570. CommonReturn:
  571. if(pbData)
  572. {
  573. if(cbFree)
  574. {
  575. SecureZeroMemory(pbData, cbFree);
  576. }
  577. free(pbData);
  578. }
  579. if(hToken)
  580. {
  581. SetThreadToken(&hThread, hToken);
  582. CloseHandle(hToken);
  583. }
  584. LeaveCriticalSection(&CriticalSec);
  585. return dwHttp;
  586. ErrorReturn:
  587. dwHttp = HSE_STATUS_ERROR;
  588. goto CommonReturn;
  589. SET_ERROR(InvalidArgErr, E_INVALIDARG);
  590. TRACE_ERROR(OperationErr);
  591. TRACE_ERROR(WriteErr);
  592. SET_ERROR_VAR(ExceptionErr, dwException);
  593. }
  594. //-----------------------------------------------------------------------------------
  595. //
  596. // TerminateExtension.
  597. //
  598. // IIS unload/cleanup code
  599. //
  600. //------------------------------------------------------------------------------------
  601. BOOL WINAPI TerminateExtension(DWORD dwFlags)
  602. {
  603. if(g_fRelease)
  604. {
  605. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_UNLOADED, 0);
  606. return TRUE;
  607. }
  608. EnterCriticalSection(&CriticalSec);
  609. //retest in the case of lock: the second thread has passed the 1st test
  610. //and was waiting for the criticcal section
  611. if(g_fRelease)
  612. {
  613. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_UNLOADED, 0);
  614. LeaveCriticalSection(&CriticalSec);
  615. return TRUE;
  616. }
  617. if(g_pwszComputerName)
  618. {
  619. free(g_pwszComputerName);
  620. g_pwszComputerName=NULL;
  621. }
  622. ReleaseRequestTable();
  623. ReleasePasswordTable();
  624. ReleaseHashTable();
  625. if(g_HCACertStore)
  626. {
  627. CertCloseStore(g_HCACertStore, 0);
  628. g_HCACertStore=NULL;
  629. }
  630. FreeRAInformation(&g_RAInfo);
  631. FreeCAInformation(&g_CAInfo);
  632. //only if fInit is TRUE, that we have an outstanding CoInitialize() call
  633. if(g_fInit)
  634. CoUninitialize();
  635. g_fRelease=TRUE;
  636. LogSCEPEvent(0, FALSE, S_OK, EVENT_MSCEP_UNLOADED, 0);
  637. LeaveCriticalSection(&CriticalSec);
  638. //we always allow unload
  639. return TRUE;
  640. }
  641. //***********************************************************************************
  642. //
  643. // Helper functions for the password table
  644. //
  645. //***********************************************************************************
  646. //-----------------------------------------------------------------------------------
  647. //
  648. // CEPObtainPassword
  649. //
  650. //------------------------------------------------------------------------------------
  651. BOOL WINAPI CEPObtainPassword(HCRYPTPROV hProv,
  652. LPWSTR *ppwszPassword)
  653. {
  654. BYTE pbData[CEP_PASSWORD_LENGTH];
  655. BOOL fResult=FALSE;
  656. memset(pbData, 0, CEP_PASSWORD_LENGTH);
  657. if(!CryptGenRandom(hProv, CEP_PASSWORD_LENGTH, pbData))
  658. return FALSE;
  659. fResult=ConvertByteToWstr(pbData, CEP_PASSWORD_LENGTH, ppwszPassword, FALSE);
  660. SecureZeroMemory(pbData, CEP_PASSWORD_LENGTH);
  661. return fResult;
  662. }
  663. //***********************************************************************************
  664. //
  665. // Helper functions for ISAPI dll entry points
  666. //
  667. //***********************************************************************************
  668. //-----------------------------------------------------------------------------------
  669. //
  670. // IsAnonymousAccess
  671. //
  672. //------------------------------------------------------------------------------------
  673. BOOL WINAPI IsAnonymousAccess(EXTENSION_CONTROL_BLOCK *pECB)
  674. {
  675. BOOL fAccess=TRUE;
  676. DWORD dwSize=0;
  677. BYTE *pbData=NULL;
  678. pECB->GetServerVariable(pECB->ConnID,
  679. "REMOTE_USER",
  680. NULL,
  681. &dwSize);
  682. if(0==dwSize)
  683. goto CLEANUP;
  684. pbData=(BYTE *)malloc(dwSize);
  685. if(NULL==pbData)
  686. goto CLEANUP;
  687. if(!(pECB->GetServerVariable(pECB->ConnID,
  688. "REMOTE_USER",
  689. pbData,
  690. &dwSize)))
  691. goto CLEANUP;
  692. if(0 == strlen((LPSTR)pbData))
  693. goto CLEANUP;
  694. fAccess=FALSE;
  695. CLEANUP:
  696. if(pbData)
  697. free(pbData);
  698. return fAccess;
  699. }
  700. //-----------------------------------------------------------------------------------
  701. //
  702. // CheckACLOnCertTemplate
  703. //
  704. //------------------------------------------------------------------------------------
  705. HRESULT WINAPI CheckACLOnCertTemplate(BOOL fSelf, LPWSTR pwszCAName, LPWSTR pwszCertType)
  706. {
  707. HRESULT hr=S_OK;
  708. HANDLE hThread=NULL; //no need to close
  709. DWORD dwIndex=0;
  710. HCAINFO hCAInfo=NULL;
  711. LPWSTR *ppwszList=NULL;
  712. HCERTTYPE hCertType=NULL;
  713. HANDLE hToken=NULL;
  714. if((NULL == pwszCAName) || (NULL == pwszCertType))
  715. return E_INVALIDARG;
  716. //first of all, we need to revert to ourselves if
  717. //we are under impersonation and delegation is not
  718. //supported by default, thus we can not access the DS.
  719. //we are ganranteed to have a thread token under impersonation
  720. hThread=GetCurrentThread();
  721. if(NULL == hThread)
  722. return HRESULT_FROM_WIN32(GetLastError());
  723. if(OpenThreadToken(hThread,
  724. TOKEN_IMPERSONATE | TOKEN_QUERY,
  725. FALSE,
  726. &hToken))
  727. {
  728. if(hToken)
  729. {
  730. RevertToSelf();
  731. }
  732. }
  733. if(S_OK != (hr=CAFindCertTypeByName(pwszCertType,
  734. NULL,
  735. CT_ENUM_MACHINE_TYPES | CT_FLAG_NO_CACHE_LOOKUP | CT_FIND_LOCAL_SYSTEM,
  736. &hCertType)))
  737. goto error;
  738. //fSelf means we want to check with the impersonation token
  739. if(TRUE == fSelf)
  740. {
  741. if(S_OK != (hr=CACertTypeAccessCheck(hCertType, hToken)))
  742. goto error;
  743. }
  744. else
  745. {
  746. if(S_OK != (hr=CACertTypeAccessCheck(hCertType, NULL)))
  747. goto error;
  748. }
  749. if(S_OK != (hr=CAFindByName(
  750. pwszCAName,
  751. NULL,
  752. CA_FIND_LOCAL_SYSTEM,
  753. &hCAInfo)))
  754. goto error;
  755. if(S_OK != (hr= CAGetCAProperty(
  756. hCAInfo,
  757. CA_PROP_CERT_TYPES,
  758. &ppwszList)))
  759. goto error;
  760. if((NULL == ppwszList) || (NULL == ppwszList[0]))
  761. {
  762. hr=E_FAIL;
  763. goto error;
  764. }
  765. while(ppwszList[dwIndex])
  766. {
  767. if(0 == _wcsicmp(pwszCertType, ppwszList[dwIndex]))
  768. {
  769. break;
  770. }
  771. dwIndex++;
  772. }
  773. if(NULL == ppwszList[dwIndex])
  774. {
  775. hr=E_FAIL;
  776. goto error;
  777. }
  778. hr=S_OK;
  779. error:
  780. if(ppwszList)
  781. CAFreeCAProperty(hCAInfo, ppwszList);
  782. if(hCAInfo)
  783. CACloseCA(hCAInfo);
  784. if(hCertType)
  785. CACloseCertType(hCertType);
  786. if(hToken)
  787. {
  788. SetThreadToken(&hThread, hToken);
  789. CloseHandle(hToken);
  790. }
  791. return hr;
  792. }
  793. //-----------------------------------------------------------------------------------
  794. //
  795. // OperationDisplayAccessHTML
  796. //
  797. //------------------------------------------------------------------------------------
  798. BOOL WINAPI OperationDisplayAccessHTML(BYTE **ppbData, DWORD *pcbData)
  799. {
  800. return LoadIDToTemplate(IDS_ACCESS_DENIED,
  801. ppbData,
  802. pcbData);
  803. }
  804. //-----------------------------------------------------------------------------------
  805. //
  806. // OperationGetDisplayInfoForCEP
  807. //
  808. //------------------------------------------------------------------------------------
  809. BOOL WINAPI OperationGetDisplayInfoForCEP(LPWSTR pwszCAHash,
  810. HCRYPTPROV hProv,
  811. BOOL fPassword,
  812. BYTE **ppbData,
  813. DWORD *pcbData)
  814. {
  815. BOOL fResult=FALSE;
  816. HRESULT hr=E_FAIL;
  817. UINT idsMsg=IDS_TOO_MANY_PASSWORD;
  818. LPWSTR pwszPassword=NULL;
  819. LPWSTR pwszText=NULL;
  820. if(fPassword)
  821. {
  822. if(!CEPObtainPassword(hProv, &pwszPassword))
  823. {
  824. idsMsg=IDS_FAIL_TO_GET_PASSWORD;
  825. goto InfoWithLastErrorReturn;
  826. }
  827. if(!CEPAddPasswordToTable(pwszPassword))
  828. {
  829. if(CRYPT_E_NO_MATCH == GetLastError())
  830. {
  831. idsMsg=IDS_TOO_MANY_PASSWORD;
  832. goto InfoWithIDReturn;
  833. }
  834. else
  835. {
  836. idsMsg=IDS_FAIL_TO_ADD_PASSWORD;
  837. goto InfoWithLastErrorReturn;
  838. }
  839. }
  840. if(!FormatMessageUnicode(&pwszText, IDS_CEP_INFO_WITH_PASSWORD, pwszCAHash,
  841. pwszPassword, g_dwPasswordValidity))
  842. goto TraceErr;
  843. }
  844. else
  845. {
  846. if(!FormatMessageUnicode(&pwszText, IDS_CEP_INFO_NO_PASSWORD, pwszCAHash))
  847. goto TraceErr;
  848. }
  849. fResult=LoadWZToTemplate(pwszText, ppbData, pcbData);
  850. CommonReturn:
  851. if(pwszText)
  852. {
  853. SecureZeroMemory(pwszText, sizeof(WCHAR) * wcslen(pwszText));
  854. LocalFree((HLOCAL)pwszText);
  855. }
  856. if(pwszPassword)
  857. {
  858. SecureZeroMemory(pwszPassword, sizeof(WCHAR) * wcslen(pwszPassword));
  859. free(pwszPassword);
  860. }
  861. return fResult;
  862. InfoWithIDReturn:
  863. fResult=LoadIDToTemplate(idsMsg, ppbData, pcbData);
  864. goto CommonReturn;
  865. InfoWithLastErrorReturn:
  866. hr=HRESULT_FROM_WIN32(GetLastError());
  867. fResult=LoadIDAndHRToTempalte(idsMsg, hr, ppbData, pcbData);
  868. goto CommonReturn;
  869. ErrorReturn:
  870. fResult=FALSE;
  871. goto CommonReturn;
  872. TRACE_ERROR(TraceErr);
  873. }
  874. //-----------------------------------------------------------------------------------
  875. //
  876. // LoadIDToTemplate
  877. //
  878. //------------------------------------------------------------------------------------
  879. BOOL WINAPI LoadIDToTemplate(UINT idsMsg,
  880. BYTE **ppbData,
  881. DWORD *pcbData)
  882. {
  883. BOOL fResult=FALSE;
  884. WCHAR wsz[MAX_STRING_SIZE];
  885. if(!LoadStringU(g_hMSCEPModule, idsMsg, wsz, MAX_STRING_SIZE))
  886. return FALSE;
  887. return LoadWZToTemplate(wsz, ppbData, pcbData);
  888. }
  889. //-----------------------------------------------------------------------------------
  890. //
  891. // LoadIDToTemplate
  892. //
  893. //------------------------------------------------------------------------------------
  894. BOOL WINAPI LoadIDAndHRToTempalte(UINT idsMsg,
  895. HRESULT hr,
  896. BYTE **ppbData,
  897. DWORD *pcbData)
  898. {
  899. BOOL fResult=FALSE;
  900. WCHAR wszUnknownError[50];
  901. LPWSTR pwszErrorMsg=NULL;
  902. LPWSTR pwszText=NULL;
  903. if(!FAILED(hr))
  904. hr=E_FAIL;
  905. //using W version because this is a NT5 only function call
  906. if(FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  907. FORMAT_MESSAGE_FROM_SYSTEM |
  908. FORMAT_MESSAGE_IGNORE_INSERTS,
  909. NULL,
  910. hr,
  911. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  912. (LPWSTR) &pwszErrorMsg,
  913. 0,
  914. NULL))
  915. {
  916. if(!FormatMessageUnicode(&pwszText, idsMsg, pwszErrorMsg))
  917. goto TraceErr;
  918. }
  919. else
  920. {
  921. if(!LoadStringU(g_hMSCEPModule, IDS_ERROR_UNKONWN, wszUnknownError, 50))
  922. goto TraceErr;
  923. if(!FormatMessageUnicode(&pwszText, idsMsg, wszUnknownError))
  924. goto TraceErr;
  925. }
  926. fResult=LoadWZToTemplate(pwszText, ppbData, pcbData);
  927. CommonReturn:
  928. if(pwszText)
  929. LocalFree((HLOCAL)pwszText);
  930. if(pwszErrorMsg)
  931. LocalFree((HLOCAL)pwszErrorMsg);
  932. return fResult;
  933. ErrorReturn:
  934. fResult=FALSE;
  935. goto CommonReturn;
  936. TRACE_ERROR(TraceErr);
  937. }
  938. //-----------------------------------------------------------------------------------
  939. //
  940. // LoadWZToTemplate
  941. //
  942. //------------------------------------------------------------------------------------
  943. BOOL WINAPI LoadWZToTemplate(LPWSTR pwsz,
  944. BYTE **ppbData,
  945. DWORD *pcbData)
  946. {
  947. BOOL fResult=FALSE;
  948. LPWSTR pwszHTML=NULL;
  949. if(!FormatMessageUnicode(&pwszHTML, IDS_HTML_TEMPLATE, pwsz))
  950. goto TraceErr;
  951. fResult=CopyWZToBuffer(pwszHTML, ppbData, pcbData);
  952. CommonReturn:
  953. if(pwszHTML)
  954. LocalFree((HLOCAL)pwszHTML);
  955. return fResult;
  956. ErrorReturn:
  957. fResult=FALSE;
  958. goto CommonReturn;
  959. TRACE_ERROR(TraceErr);
  960. }
  961. //-----------------------------------------------------------------------------------
  962. //
  963. // CopyWZToBuffer
  964. //
  965. //------------------------------------------------------------------------------------
  966. BOOL WINAPI CopyWZToBuffer( LPWSTR pwszData,
  967. BYTE **ppbData,
  968. DWORD *pcbData)
  969. {
  970. BOOL fResult=FALSE;
  971. DWORD dwSize=0;
  972. *ppbData=NULL;
  973. *pcbData=0;
  974. dwSize=sizeof(WCHAR) * (wcslen(pwszData) + 1);
  975. *ppbData=(BYTE *)malloc(dwSize);
  976. if(NULL==ppbData)
  977. goto MemoryErr;
  978. memcpy(*ppbData, pwszData, dwSize);
  979. *pcbData=dwSize;
  980. fResult=TRUE;
  981. CommonReturn:
  982. return fResult;
  983. ErrorReturn:
  984. fResult=FALSE;
  985. goto CommonReturn;
  986. SET_ERROR(MemoryErr, E_OUTOFMEMORY);
  987. }
  988. //------------------------------------------------------------------------
  989. // Convert the byte to its Hex presentation.
  990. //
  991. // Precondition: byte is less than 15
  992. //
  993. //------------------------------------------------------------------------
  994. ULONG ByteToHex(BYTE byte, LPWSTR wszZero, LPWSTR wszA)
  995. {
  996. ULONG uValue=0;
  997. if(((ULONG)byte)<=9)
  998. {
  999. uValue=((ULONG)byte)+ULONG(*wszZero);
  1000. }
  1001. else
  1002. {
  1003. uValue=(ULONG)byte-10+ULONG(*wszA);
  1004. }
  1005. return uValue;
  1006. }
  1007. //--------------------------------------------------------------------------
  1008. //
  1009. // ConvertByteToWstr
  1010. //
  1011. // If fSpace is TRUE, we add a space every 2 bytes.
  1012. //--------------------------------------------------------------------------
  1013. BOOL WINAPI ConvertByteToWstr(BYTE *pbData,
  1014. DWORD cbData,
  1015. LPWSTR *ppwsz,
  1016. BOOL fSpace)
  1017. {
  1018. BOOL fResult=FALSE;
  1019. DWORD dwBufferSize=0;
  1020. DWORD dwBufferIndex=0;
  1021. DWORD dwEncodedIndex=0;
  1022. LPWSTR pwszSpace=L" ";
  1023. LPWSTR pwszZero=L"0";
  1024. LPWSTR pwszA=L"A";
  1025. if(!pbData || !ppwsz)
  1026. goto InvalidArgErr;
  1027. //calculate the memory needed, in bytes
  1028. //we need 3 wchars per byte, along with the NULL terminator
  1029. dwBufferSize=sizeof(WCHAR)*(cbData*3+1);
  1030. *ppwsz=(LPWSTR)malloc(dwBufferSize);
  1031. if(NULL==(*ppwsz))
  1032. goto MemoryErr;
  1033. dwBufferIndex=0;
  1034. //format the wchar buffer one byte at a time
  1035. for(dwEncodedIndex=0; dwEncodedIndex<cbData; dwEncodedIndex++)
  1036. {
  1037. //copy the space between every four bytes. Skip for the 1st byte
  1038. if(fSpace)
  1039. {
  1040. if((0!=dwEncodedIndex) && (0==(dwEncodedIndex % 4 )))
  1041. {
  1042. (*ppwsz)[dwBufferIndex]=pwszSpace[0];
  1043. dwBufferIndex++;
  1044. }
  1045. }
  1046. //format the higher 4 bits
  1047. (*ppwsz)[dwBufferIndex]=(WCHAR)ByteToHex(
  1048. (pbData[dwEncodedIndex]&UPPER_BITS)>>4,
  1049. pwszZero, pwszA);
  1050. dwBufferIndex++;
  1051. //format the lower 4 bits
  1052. (*ppwsz)[dwBufferIndex]=(WCHAR)ByteToHex(
  1053. pbData[dwEncodedIndex]&LOWER_BITS,
  1054. pwszZero, pwszA);
  1055. dwBufferIndex++;
  1056. }
  1057. //add the NULL terminator to the string
  1058. (*ppwsz)[dwBufferIndex]=L'\0';
  1059. fResult=TRUE;
  1060. CommonReturn:
  1061. return fResult;
  1062. ErrorReturn:
  1063. fResult=FALSE;
  1064. goto CommonReturn;
  1065. SET_ERROR(MemoryErr, E_OUTOFMEMORY);
  1066. SET_ERROR(InvalidArgErr, E_INVALIDARG);
  1067. }
  1068. //--------------------------------------------------------------------------
  1069. //
  1070. // FormatMessageUnicode
  1071. //
  1072. //--------------------------------------------------------------------------
  1073. BOOL WINAPI FormatMessageUnicode(LPWSTR *ppwszFormat,UINT ids,...)
  1074. {
  1075. // get format string from resources
  1076. WCHAR wszFormat[1000];
  1077. va_list argList;
  1078. DWORD cbMsg=0;
  1079. BOOL fResult=FALSE;
  1080. HRESULT hr=S_OK;
  1081. if(NULL == ppwszFormat)
  1082. goto InvalidArgErr;
  1083. if(!LoadStringU(g_hMSCEPModule, ids, wszFormat, 1000))
  1084. goto LoadStringError;
  1085. // format message into requested buffer
  1086. va_start(argList, ids);
  1087. cbMsg = FormatMessageU(
  1088. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  1089. wszFormat,
  1090. 0, // dwMessageId
  1091. 0, // dwLanguageId
  1092. (LPWSTR) (ppwszFormat),
  1093. 0, // minimum size to allocate
  1094. &argList);
  1095. va_end(argList);
  1096. if(!cbMsg)
  1097. goto FormatMessageError;
  1098. fResult=TRUE;
  1099. CommonReturn:
  1100. return fResult;
  1101. ErrorReturn:
  1102. fResult=FALSE;
  1103. goto CommonReturn;
  1104. TRACE_ERROR(LoadStringError);
  1105. TRACE_ERROR(FormatMessageError);
  1106. SET_ERROR(InvalidArgErr, E_INVALIDARG);
  1107. }
  1108. //--------------------------------------------------------------------------
  1109. // Name: LogSCEPEvent
  1110. //
  1111. // Description: This function registers an event in the event log of the
  1112. // local machine. Takes an optional argument list.
  1113. //
  1114. //--------------------------------------------------------------------------
  1115. void WINAPI LogSCEPEvent(IN DWORD dwLogLevel,
  1116. IN BOOL fError,
  1117. IN HRESULT hr,
  1118. IN DWORD dwEventId,
  1119. IN DWORD dwParamCount,
  1120. ...
  1121. )
  1122. {
  1123. WORD dwEventType = 0;
  1124. LPWSTR awszStrings[PENDING_ALLOC_SIZE + 2];
  1125. WORD cStrings = 0;
  1126. LPWSTR wszString = NULL;
  1127. WCHAR wszMsg[MAX_STRING_SIZE];
  1128. DWORD dwIndex=0;
  1129. LPWSTR wszHR=NULL;
  1130. va_list ArgList;
  1131. if(NULL == g_hEventSource)
  1132. return;
  1133. //copy the variable strings if present
  1134. va_start(ArgList, dwParamCount);
  1135. for(dwIndex=0; dwIndex < dwParamCount; dwIndex++)
  1136. {
  1137. wszString = va_arg(ArgList, LPWSTR);
  1138. if(wszString)
  1139. awszStrings[cStrings++] = wszString;
  1140. if(cStrings >= PENDING_ALLOC_SIZE)
  1141. {
  1142. break;
  1143. }
  1144. }
  1145. va_end(ArgList);
  1146. //copy the hr error code
  1147. if(fError)
  1148. {
  1149. if(S_OK == hr)
  1150. hr=E_FAIL;
  1151. wsprintfW(wszMsg, L"0x%lx", hr);
  1152. awszStrings[cStrings++] = wszMsg;
  1153. if(0 != FormatMessageW(
  1154. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  1155. NULL,
  1156. hr,
  1157. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1158. (WCHAR *)&wszHR,
  1159. 0,
  1160. NULL))
  1161. {
  1162. if(wszHR)
  1163. {
  1164. awszStrings[cStrings++] = wszHR;
  1165. }
  1166. else
  1167. {
  1168. awszStrings[cStrings++]=L" ";
  1169. }
  1170. }
  1171. else
  1172. {
  1173. awszStrings[cStrings++]=L" ";
  1174. }
  1175. }
  1176. switch(dwEventId >> 30)
  1177. {
  1178. case 0:
  1179. dwEventType = EVENTLOG_SUCCESS;
  1180. break;
  1181. case 1:
  1182. dwEventType = EVENTLOG_INFORMATION_TYPE;
  1183. break;
  1184. case 2:
  1185. dwEventType = EVENTLOG_WARNING_TYPE;
  1186. break;
  1187. case 3:
  1188. dwEventType = EVENTLOG_ERROR_TYPE;
  1189. break;
  1190. }
  1191. ReportEventW(g_hEventSource, // handle of event source
  1192. dwEventType, // event type
  1193. 0, // event category
  1194. dwEventId, // event ID
  1195. NULL, // current user's SID
  1196. cStrings, // strings in lpszStrings
  1197. 0, // no bytes of raw data
  1198. (LPCWSTR*)awszStrings, // array of error strings
  1199. NULL // no raw data
  1200. );
  1201. if(wszHR)
  1202. LocalFree(wszHR);
  1203. return;
  1204. }