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.

9983 lines
298 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 2000
  6. //
  7. // File: autoenro.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include <windows.h>
  11. #include <winuser.h>
  12. #include <wincrypt.h>
  13. #include <stdio.h>
  14. #include <cryptui.h>
  15. #include <lmcons.h>
  16. #include <lmapibuf.h>
  17. #include <dsgetdc.h>
  18. #include <oleauto.h>
  19. #define SECURITY_WIN32
  20. #include <rpc.h>
  21. #include <security.h>
  22. #include <winldap.h>
  23. #include <dsrole.h>
  24. #include <shobjidl.h>
  25. #include <shellapi.h>
  26. #include <commctrl.h>
  27. #include <winscard.h>
  28. #include <Rpcdce.h>
  29. #include <certca.h>
  30. #include <certsrv.h>
  31. #include <autoenr.h>
  32. #include <autoenro.h>
  33. #include <autolog.h>
  34. #include <resource.h>
  35. #include <xenroll.h>
  36. //*******************************************************************************
  37. //
  38. //
  39. // Global Defines and Data Structures
  40. //
  41. //
  42. //*******************************************************************************
  43. HINSTANCE g_hmodThisDll = NULL; // Handle to this DLL itself.
  44. #if DBG
  45. DWORD g_AutoenrollDebugLevel = AE_ERROR; //| AE_WARNING | AE_INFO | AE_TRACE;
  46. #endif
  47. //when we look at supersede relationship, we based on the following order
  48. DWORD g_rgdwSupersedeOrder[]={CERT_REQUEST_STATUS_OBTAINED,
  49. CERT_REQUEST_STATUS_ACTIVE,
  50. CERT_REQUEST_STATUS_PENDING,
  51. CERT_REQUEST_STATUS_SUPERSEDE_ACTIVE};
  52. DWORD g_dwSupersedeOrder=sizeof(g_rgdwSupersedeOrder)/sizeof(g_rgdwSupersedeOrder[0]);
  53. //the list of certificate store to update
  54. AE_STORE_INFO g_rgStoreInfo[]={
  55. L"ROOT", L"ldap:///CN=Certification Authorities,CN=Public Key Services,CN=Services,%s?cACertificate?one?objectCategory=certificationAuthority",
  56. L"NTAuth", L"ldap:///CN=Public Key Services,CN=Services,%s?cACertificate?one?cn=NTAuthCertificates",
  57. L"CA", L"ldap:///CN=AIA,CN=Public Key Services,CN=Services,%s?crossCertificatePair,cACertificate?one?objectCategory=certificationAuthority"
  58. };
  59. DWORD g_dwStoreInfo=sizeof(g_rgStoreInfo)/sizeof(g_rgStoreInfo[0]);
  60. typedef IEnroll4 * (WINAPI *PFNPIEnroll4GetNoCOM)();
  61. static WCHAR * s_wszLocation = L"CN=Public Key Services,CN=Services,";
  62. //*******************************************************************************
  63. //
  64. //
  65. // Implementation of IQueryContinue for use autoenrollment notification
  66. //
  67. //
  68. //*******************************************************************************
  69. //--------------------------------------------------------------------------
  70. // CQueryContinue
  71. //--------------------------------------------------------------------------
  72. CQueryContinue::CQueryContinue()
  73. {
  74. m_cRef=1;
  75. m_pIUserNotification=NULL;
  76. m_hTimer=NULL;
  77. }
  78. //--------------------------------------------------------------------------
  79. // ~CQueryContinue
  80. //--------------------------------------------------------------------------
  81. CQueryContinue::~CQueryContinue()
  82. {
  83. }
  84. //--------------------------------------------------------------------------
  85. // CQueryContinue
  86. //--------------------------------------------------------------------------
  87. HRESULT CQueryContinue::QueryInterface(REFIID riid, void **ppv)
  88. {
  89. if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IQueryContinue))
  90. {
  91. *ppv=(LPVOID)this;
  92. AddRef();
  93. return S_OK;
  94. }
  95. return E_NOINTERFACE;
  96. }
  97. //--------------------------------------------------------------------------
  98. // AddRef
  99. //--------------------------------------------------------------------------
  100. STDMETHODIMP_(ULONG) CQueryContinue::AddRef()
  101. {
  102. return InterlockedIncrement(&m_cRef);
  103. }
  104. //--------------------------------------------------------------------------
  105. // Release
  106. //--------------------------------------------------------------------------
  107. STDMETHODIMP_(ULONG) CQueryContinue::Release()
  108. {
  109. if (InterlockedDecrement(&m_cRef))
  110. return m_cRef;
  111. delete this;
  112. return 0;
  113. }
  114. //--------------------------------------------------------------------------
  115. // CQueryContinue
  116. //--------------------------------------------------------------------------
  117. HRESULT CQueryContinue::QueryContinue()
  118. {
  119. //disable the balloon
  120. if(m_pIUserNotification)
  121. m_pIUserNotification->SetBalloonInfo(NULL, NULL, NIIF_INFO);
  122. //wait for the timer to be activated
  123. if(m_hTimer)
  124. {
  125. if(WAIT_OBJECT_0 == WaitForSingleObject(m_hTimer, 0))
  126. return S_FALSE;
  127. }
  128. return S_OK;
  129. }
  130. //--------------------------------------------------------------------------
  131. // DoBalloon()
  132. //--------------------------------------------------------------------------
  133. HRESULT CQueryContinue::DoBalloon()
  134. {
  135. HRESULT hr=E_FAIL;
  136. WCHAR wszTitle[MAX_DN_SIZE];
  137. WCHAR wszText[MAX_DN_SIZE];
  138. HICON hIcon=NULL;
  139. LARGE_INTEGER DueTime;
  140. if(S_OK != (hr=CoCreateInstance(CLSID_UserNotification,
  141. NULL,
  142. CLSCTX_ALL,
  143. IID_IUserNotification,
  144. (void **)&m_pIUserNotification)))
  145. goto Ret;
  146. if(NULL==m_pIUserNotification)
  147. {
  148. hr=E_FAIL;
  149. goto Ret;
  150. }
  151. //create a waitable timer with default security setting
  152. m_hTimer=CreateWaitableTimer(NULL, TRUE, NULL);
  153. if(NULL==m_hTimer)
  154. {
  155. hr=E_FAIL;
  156. goto Ret;
  157. }
  158. //set the timer
  159. DueTime.QuadPart = Int32x32To64(-10000, AUTO_ENROLLMENT_BALLOON_LENGTH * 1000);
  160. if(!SetWaitableTimer(m_hTimer, &DueTime, 0, NULL, 0, FALSE))
  161. {
  162. hr=E_FAIL;
  163. goto Ret;
  164. }
  165. if(S_OK != (hr=m_pIUserNotification->SetBalloonRetry(AUTO_ENROLLMENT_SHOW_TIME * 1000,
  166. AUTO_ENROLLMENT_INTERVAL * 1000,
  167. AUTO_ENROLLMENT_RETRIAL)))
  168. goto Ret;
  169. if((!LoadStringW(g_hmodThisDll,IDS_ICON_TIP, wszText, MAX_DN_SIZE)) ||
  170. (NULL==(hIcon=LoadIcon(g_hmodThisDll, MAKEINTRESOURCE(IDI_AUTOENROLL_ICON)))))
  171. {
  172. hr=E_FAIL;
  173. goto Ret;
  174. }
  175. if(S_OK != (hr=m_pIUserNotification->SetIconInfo(hIcon, wszText)))
  176. goto Ret;
  177. if((!LoadStringW(g_hmodThisDll,IDS_BALLOON_TITLE, wszTitle, MAX_DN_SIZE)) ||
  178. (!LoadStringW(g_hmodThisDll,IDS_BALLOON_TEXT, wszText, MAX_DN_SIZE)))
  179. {
  180. hr=E_FAIL;
  181. goto Ret;
  182. }
  183. if(S_OK !=(hr=m_pIUserNotification->SetBalloonInfo(wszTitle, wszText, NIIF_INFO)))
  184. goto Ret;
  185. //user did not click on the icon or we time out
  186. hr= m_pIUserNotification->Show(this, AUTO_ENROLLMENT_QUERY_INTERVAL * 1000);
  187. Ret:
  188. if(m_hTimer)
  189. {
  190. CloseHandle(m_hTimer);
  191. m_hTimer=NULL;
  192. }
  193. if(m_pIUserNotification)
  194. {
  195. m_pIUserNotification->Release();
  196. m_pIUserNotification=NULL;
  197. }
  198. return hr;
  199. }
  200. //*******************************************************************************
  201. //
  202. //
  203. // Functions for autoenrollment
  204. //
  205. //
  206. //*******************************************************************************
  207. //--------------------------------------------------------------------------
  208. //
  209. // Name: FindCertificateInOtherStore
  210. //
  211. //--------------------------------------------------------------------------
  212. PCCERT_CONTEXT FindCertificateInOtherStore(
  213. IN HCERTSTORE hOtherStore,
  214. IN PCCERT_CONTEXT pCert
  215. )
  216. {
  217. BYTE rgbHash[SHA1_HASH_LENGTH];
  218. CRYPT_DATA_BLOB HashBlob;
  219. HashBlob.pbData = rgbHash;
  220. HashBlob.cbData = SHA1_HASH_LENGTH;
  221. if (!CertGetCertificateContextProperty(
  222. pCert,
  223. CERT_SHA1_HASH_PROP_ID,
  224. rgbHash,
  225. &HashBlob.cbData
  226. ) || SHA1_HASH_LENGTH != HashBlob.cbData)
  227. return NULL;
  228. return CertFindCertificateInStore(
  229. hOtherStore,
  230. ENCODING_TYPE, // dwCertEncodingType
  231. 0, // dwFindFlags
  232. CERT_FIND_SHA1_HASH,
  233. (const void *) &HashBlob,
  234. NULL //pPrevCertContext
  235. );
  236. }
  237. //--------------------------------------------------------------------------
  238. //
  239. // AEUpdateCertificateStore
  240. //
  241. // Description: This function enumerates all of the certificate in the DS based
  242. // LdapPath, and moves them into the corresponding local machine store.
  243. //
  244. //--------------------------------------------------------------------------
  245. HRESULT WINAPI AEUpdateCertificateStore(LDAP *pld,
  246. LPWSTR pwszConfig,
  247. LPWSTR pwszStoreName,
  248. LPWSTR pwszLdapPath)
  249. {
  250. HRESULT hr = S_OK;
  251. CERT_LDAP_STORE_OPENED_PARA CertOpenStoreParam;
  252. PCCERT_CONTEXT pContext = NULL,
  253. pOtherCert = NULL;
  254. LPWSTR pwszLdapStore = NULL;
  255. HCERTSTORE hEnterpriseStore = NULL,
  256. hLocalStore = NULL;
  257. if((NULL==pld) || (NULL==pwszConfig) || (NULL==pwszStoreName) || (NULL==pwszLdapPath))
  258. {
  259. hr = E_INVALIDARG;
  260. goto error;
  261. }
  262. pwszLdapStore = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(pwszConfig)+wcslen(pwszLdapPath)+1));
  263. if(pwszLdapStore == NULL)
  264. {
  265. hr = E_OUTOFMEMORY;
  266. goto error;
  267. }
  268. wsprintf(pwszLdapStore,
  269. pwszLdapPath,
  270. pwszConfig);
  271. hLocalStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  272. 0,
  273. 0,
  274. CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
  275. pwszStoreName);
  276. if(hLocalStore == NULL)
  277. {
  278. hr = HRESULT_FROM_WIN32(GetLastError());
  279. AE_DEBUG((AE_ERROR, L"Unable to open ROOT store (%lx)\n\r", hr));
  280. goto error;
  281. }
  282. memset(&CertOpenStoreParam, 0, sizeof(CertOpenStoreParam));
  283. CertOpenStoreParam.pvLdapSessionHandle=pld;
  284. CertOpenStoreParam.pwszLdapUrl=pwszLdapStore;
  285. hEnterpriseStore = CertOpenStore(CERT_STORE_PROV_LDAP,
  286. 0,
  287. 0,
  288. CERT_STORE_READONLY_FLAG | CERT_LDAP_STORE_SIGN_FLAG |
  289. CERT_LDAP_STORE_OPENED_FLAG,
  290. &CertOpenStoreParam);
  291. if(hEnterpriseStore == NULL)
  292. {
  293. DWORD err = GetLastError();
  294. if((err == ERROR_FILE_NOT_FOUND))
  295. {
  296. // There was no store, so there are no certs
  297. hr = S_OK;
  298. goto error;
  299. }
  300. hr = HRESULT_FROM_WIN32(err);
  301. AE_DEBUG((AE_ERROR, L"Unable to open ROOT store (%lx)\n\r", hr));
  302. goto error;
  303. }
  304. while(pContext = CertEnumCertificatesInStore(hEnterpriseStore, pContext))
  305. {
  306. if (pOtherCert = FindCertificateInOtherStore(hLocalStore, pContext)) {
  307. CertFreeCertificateContext(pOtherCert);
  308. }
  309. else
  310. {
  311. CertAddCertificateContextToStore(hLocalStore,
  312. pContext,
  313. CERT_STORE_ADD_ALWAYS,
  314. NULL);
  315. }
  316. }
  317. while(pContext = CertEnumCertificatesInStore(hLocalStore, pContext))
  318. {
  319. if (pOtherCert = FindCertificateInOtherStore(hEnterpriseStore, pContext)) {
  320. CertFreeCertificateContext(pOtherCert);
  321. }
  322. else
  323. {
  324. CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pContext));
  325. }
  326. }
  327. error:
  328. if(hr != S_OK)
  329. {
  330. AELogAutoEnrollmentEvent(
  331. STATUS_SEVERITY_ERROR, //this event will always be logged
  332. TRUE,
  333. hr,
  334. EVENT_FAIL_DOWNLOAD_CERT,
  335. TRUE,
  336. NULL,
  337. 2,
  338. pwszStoreName,
  339. pwszLdapStore);
  340. }
  341. if(pwszLdapStore)
  342. {
  343. LocalFree(pwszLdapStore);
  344. }
  345. if(hEnterpriseStore)
  346. {
  347. CertCloseStore(hEnterpriseStore,0);
  348. }
  349. if(hLocalStore)
  350. {
  351. CertCloseStore(hLocalStore,0);
  352. }
  353. return hr;
  354. }
  355. //--------------------------------------------------------------------------
  356. //
  357. // AENeedToUpdateDSCache
  358. //
  359. //--------------------------------------------------------------------------
  360. BOOL AENeedToUpdateDSCache(LDAP *pld, LPWSTR pwszDCInvocationID, LPWSTR pwszConfig, AE_DS_INFO *pAEDSInfo)
  361. {
  362. BOOL fNeedToUpdate=TRUE;
  363. DWORD dwRegObject=0;
  364. ULARGE_INTEGER maxRegUSN;
  365. ULARGE_INTEGER maxDsUSN;
  366. DWORD dwType=0;
  367. DWORD dwSize=0;
  368. DWORD dwDisp=0;
  369. struct l_timeval timeout;
  370. LPWSTR rgwszAttrs[] = {AUTO_ENROLLMENT_USN_ATTR, NULL};
  371. LDAPMessage *Entry=NULL;
  372. LPWSTR *awszValue = NULL;
  373. HKEY hDSKey=NULL;
  374. HKEY hDCKey=NULL;
  375. LDAPMessage *SearchResult = NULL;
  376. LPWSTR pwszContainer=NULL;
  377. if((NULL==pld) || (NULL==pwszDCInvocationID) || (NULL==pwszConfig) || (NULL==pAEDSInfo))
  378. goto error;
  379. //init
  380. memset(pAEDSInfo, 0, sizeof(AE_DS_INFO));
  381. //compute the # of objects and maxUSN from the directory
  382. pwszContainer=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (1 + wcslen(pwszConfig) + wcslen(s_wszLocation)));
  383. if(NULL == pwszContainer)
  384. goto error;
  385. wcscpy(pwszContainer, s_wszLocation);
  386. wcscat(pwszContainer, pwszConfig);
  387. timeout.tv_sec = 300;
  388. timeout.tv_usec = 0;
  389. if(LDAP_SUCCESS != ldap_search_stW(
  390. pld,
  391. pwszContainer,
  392. LDAP_SCOPE_SUBTREE,
  393. L"(objectCategory=certificationAuthority)",
  394. rgwszAttrs,
  395. 0,
  396. &timeout,
  397. &SearchResult))
  398. goto error;
  399. //get the # of objects
  400. pAEDSInfo->dwObjects = ldap_count_entries(pld, SearchResult);
  401. for(Entry = ldap_first_entry(pld, SearchResult); Entry != NULL; Entry = ldap_next_entry(pld, Entry))
  402. {
  403. awszValue = ldap_get_values(pld, Entry, AUTO_ENROLLMENT_USN_ATTR);
  404. if(NULL==awszValue)
  405. goto error;
  406. if(NULL==awszValue[0])
  407. goto error;
  408. maxDsUSN.QuadPart=0;
  409. maxDsUSN.QuadPart=_wtoi64(awszValue[0]);
  410. //if any error happens, maxDsUSN will be 0.
  411. if(0 == maxDsUSN.QuadPart)
  412. goto error;
  413. if((pAEDSInfo->maxUSN).QuadPart < maxDsUSN.QuadPart)
  414. (pAEDSInfo->maxUSN).QuadPart = maxDsUSN.QuadPart;
  415. ldap_value_free(awszValue);
  416. awszValue=NULL;
  417. }
  418. //signal that we have retrieved correct data from the directory
  419. pAEDSInfo->fValidData=TRUE;
  420. //find if we have cached any information about the DC of interest
  421. if(ERROR_SUCCESS != RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  422. AUTO_ENROLLMENT_DS_KEY,
  423. 0,
  424. TEXT(""),
  425. REG_OPTION_NON_VOLATILE,
  426. KEY_ALL_ACCESS,
  427. NULL,
  428. &hDSKey,
  429. &dwDisp))
  430. goto error;
  431. if(ERROR_SUCCESS != RegOpenKeyEx(
  432. hDSKey,
  433. pwszDCInvocationID,
  434. 0,
  435. KEY_ALL_ACCESS,
  436. &hDCKey))
  437. goto error;
  438. dwSize=sizeof(dwRegObject);
  439. if(ERROR_SUCCESS != RegQueryValueEx(
  440. hDCKey,
  441. AUTO_ENROLLMENT_DS_OBJECT,
  442. NULL,
  443. &dwType,
  444. (PBYTE)(&dwRegObject),
  445. &dwSize))
  446. goto error;
  447. if(REG_DWORD != dwType)
  448. goto error;
  449. dwSize=sizeof(maxRegUSN);
  450. if(ERROR_SUCCESS != RegQueryValueEx(
  451. hDCKey,
  452. AUTO_ENROLLMENT_DS_USN,
  453. NULL,
  454. &dwType,
  455. (PBYTE)(&(maxRegUSN)),
  456. &dwSize))
  457. goto error;
  458. if(REG_BINARY != dwType)
  459. goto error;
  460. //compare the registry data with the data from directory
  461. if(dwRegObject != (pAEDSInfo->dwObjects))
  462. goto error;
  463. if(maxRegUSN.QuadPart != ((pAEDSInfo->maxUSN).QuadPart))
  464. goto error;
  465. fNeedToUpdate=FALSE;
  466. error:
  467. if(awszValue)
  468. ldap_value_free(awszValue);
  469. if(pwszContainer)
  470. LocalFree(pwszContainer);
  471. if(hDCKey)
  472. RegCloseKey(hDCKey);
  473. if(hDSKey)
  474. RegCloseKey(hDSKey);
  475. if(SearchResult)
  476. ldap_msgfree(SearchResult);
  477. //remove the temporary data
  478. if(pAEDSInfo)
  479. {
  480. if(FALSE == fNeedToUpdate)
  481. memset(pAEDSInfo, 0, sizeof(AE_DS_INFO));
  482. }
  483. return fNeedToUpdate;
  484. }
  485. //--------------------------------------------------------------------------
  486. //
  487. // AEUpdateDSCache
  488. //
  489. //--------------------------------------------------------------------------
  490. BOOL AEUpdateDSCache(LPWSTR pwszDCInvocationID, AE_DS_INFO *pAEDSInfo)
  491. {
  492. BOOL fResult=FALSE;
  493. DWORD dwDisp=0;
  494. HKEY hDSKey=NULL;
  495. HKEY hDCKey=NULL;
  496. if((NULL==pwszDCInvocationID) || (NULL==pAEDSInfo))
  497. goto error;
  498. if(ERROR_SUCCESS != RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  499. AUTO_ENROLLMENT_DS_KEY,
  500. 0,
  501. TEXT(""),
  502. REG_OPTION_NON_VOLATILE,
  503. KEY_ALL_ACCESS,
  504. NULL,
  505. &hDSKey,
  506. &dwDisp))
  507. goto error;
  508. //create the key named by the DC
  509. if(ERROR_SUCCESS != RegCreateKeyEx(hDSKey,
  510. pwszDCInvocationID,
  511. 0,
  512. TEXT(""),
  513. REG_OPTION_NON_VOLATILE,
  514. KEY_ALL_ACCESS,
  515. NULL,
  516. &hDCKey,
  517. &dwDisp))
  518. goto error;
  519. //set the # of objects value
  520. if(ERROR_SUCCESS != RegSetValueEx(hDCKey,
  521. AUTO_ENROLLMENT_DS_OBJECT,
  522. NULL,
  523. REG_DWORD,
  524. (PBYTE)&(pAEDSInfo->dwObjects),
  525. sizeof(pAEDSInfo->dwObjects)))
  526. goto error;
  527. //set the max uSN value
  528. if(ERROR_SUCCESS != RegSetValueEx(hDCKey,
  529. AUTO_ENROLLMENT_DS_USN,
  530. NULL,
  531. REG_BINARY,
  532. (PBYTE)&(pAEDSInfo->maxUSN),
  533. sizeof(pAEDSInfo->maxUSN)))
  534. goto error;
  535. fResult=TRUE;
  536. error:
  537. if(hDCKey)
  538. RegCloseKey(hDCKey);
  539. if(hDSKey)
  540. RegCloseKey(hDSKey);
  541. return fResult;
  542. }
  543. //--------------------------------------------------------------------------
  544. //
  545. // AERetrieveInvocationID
  546. //
  547. //--------------------------------------------------------------------------
  548. BOOL AERetrieveInvocationID(LDAP *pld, LPWSTR *ppwszID)
  549. {
  550. BOOL fResult=FALSE;
  551. struct l_timeval timeout;
  552. LPWSTR rgwszDSAttrs[] = {L"dsServiceName", NULL};
  553. LPWSTR rgwszIDAttr[] = {L"invocationId", NULL};
  554. LDAPMessage *Entry=NULL;
  555. LPWSTR *awszValues = NULL;
  556. LDAPMessage *SearchResults = NULL;
  557. struct berval **apUUID = NULL;
  558. LDAPMessage *SearchIDResult = NULL;
  559. BYTE *pbUUID=NULL;
  560. if((NULL==pld) || (NULL==ppwszID))
  561. goto error;
  562. *ppwszID=NULL;
  563. //retrieve the dsSerivceName attribute
  564. timeout.tv_sec = 300;
  565. timeout.tv_usec = 0;
  566. if(LDAP_SUCCESS != ldap_search_stW(
  567. pld,
  568. NULL, //NULL DN for dsServiceName
  569. LDAP_SCOPE_BASE,
  570. L"(objectCategory=*)",
  571. rgwszDSAttrs,
  572. 0,
  573. &timeout,
  574. &SearchResults))
  575. goto error;
  576. Entry = ldap_first_entry(pld, SearchResults);
  577. if(NULL == Entry)
  578. goto error;
  579. awszValues = ldap_get_values(pld, Entry, rgwszDSAttrs[0]);
  580. if(NULL==awszValues)
  581. goto error;
  582. if(NULL==awszValues[0])
  583. goto error;
  584. //retrieve the invocationId attribute
  585. timeout.tv_sec = 300;
  586. timeout.tv_usec = 0;
  587. if(LDAP_SUCCESS != ldap_search_stW(
  588. pld,
  589. awszValues[0],
  590. LDAP_SCOPE_BASE,
  591. L"(objectCategory=*)",
  592. rgwszIDAttr,
  593. 0,
  594. &timeout,
  595. &SearchIDResult))
  596. goto error;
  597. Entry = ldap_first_entry(pld, SearchIDResult);
  598. if(NULL == Entry)
  599. goto error;
  600. apUUID = ldap_get_values_len(pld, Entry, rgwszIDAttr[0]);
  601. if(NULL == apUUID)
  602. goto error;
  603. if(NULL == (*apUUID))
  604. goto error;
  605. pbUUID = (BYTE *)LocalAlloc(LPTR, (*apUUID)->bv_len);
  606. if(NULL == (pbUUID))
  607. goto error;
  608. if(0 == ((*apUUID)->bv_len))
  609. goto error;
  610. if(NULL == ((*apUUID)->bv_val))
  611. goto error;
  612. memcpy(pbUUID, (*apUUID)->bv_val, (*apUUID)->bv_len);
  613. if(RPC_S_OK != UuidToStringW((UUID *)pbUUID, ppwszID))
  614. goto error;
  615. fResult=TRUE;
  616. error:
  617. if(pbUUID)
  618. LocalFree(pbUUID);
  619. if(apUUID)
  620. ldap_value_free_len(apUUID);
  621. if(SearchIDResult)
  622. ldap_msgfree(SearchIDResult);
  623. if(awszValues)
  624. ldap_value_free(awszValues);
  625. if(SearchResults)
  626. ldap_msgfree(SearchResults);
  627. return fResult;
  628. }
  629. //--------------------------------------------------------------------------
  630. //
  631. // AEDownloadStore
  632. //
  633. //--------------------------------------------------------------------------
  634. BOOL WINAPI AEDownloadStore(LDAP *pld)
  635. {
  636. BOOL fResult = TRUE;
  637. DWORD dwIndex = 0;
  638. AE_DS_INFO AEDSInfo;
  639. LPWSTR wszConfig = NULL;
  640. LPWSTR pwszDCInvocationID = NULL;
  641. memset(&AEDSInfo, 0, sizeof(AEDSInfo));
  642. if(S_OK != AEGetConfigDN(pld, &wszConfig))
  643. {
  644. fResult=FALSE;
  645. goto error;
  646. }
  647. //get the pwszDCInvocationID. NULL means AENeedToUpdateDSCache will return TRUE
  648. AERetrieveInvocationID(pld, &pwszDCInvocationID);
  649. if(AENeedToUpdateDSCache(pld, pwszDCInvocationID, wszConfig, &AEDSInfo))
  650. {
  651. for(dwIndex =0; dwIndex < g_dwStoreInfo; dwIndex++)
  652. {
  653. fResult = fResult && (S_OK == AEUpdateCertificateStore(
  654. pld,
  655. wszConfig,
  656. g_rgStoreInfo[dwIndex].pwszStoreName,
  657. g_rgStoreInfo[dwIndex].pwszLdapPath));
  658. }
  659. //only update the new DS cached information if we have a successful download
  660. if((fResult) && (TRUE == AEDSInfo.fValidData) && (pwszDCInvocationID))
  661. AEUpdateDSCache(pwszDCInvocationID, &AEDSInfo);
  662. }
  663. error:
  664. if(pwszDCInvocationID)
  665. RpcStringFreeW(&pwszDCInvocationID);
  666. if(wszConfig)
  667. {
  668. LocalFree(wszConfig);
  669. }
  670. return fResult;
  671. }
  672. //--------------------------------------------------------------------------
  673. //
  674. // AESetWakeUpFlag
  675. //
  676. // We set the flag to tell winlogon if autoenrollment should be waken up
  677. // during each policy check
  678. //
  679. //--------------------------------------------------------------------------
  680. BOOL WINAPI AESetWakeUpFlag(BOOL fMachine, BOOL fWakeUp)
  681. {
  682. BOOL fResult = FALSE;
  683. DWORD dwDisp = 0;
  684. DWORD dwFlags = 0;
  685. HKEY hAEKey = NULL;
  686. if(ERROR_SUCCESS != RegCreateKeyEx(
  687. fMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
  688. AUTO_ENROLLMENT_FLAG_KEY,
  689. 0,
  690. L"",
  691. REG_OPTION_NON_VOLATILE,
  692. KEY_ALL_ACCESS,
  693. NULL,
  694. &hAEKey,
  695. &dwDisp))
  696. goto Ret;
  697. if(fWakeUp)
  698. dwFlags = AUTO_ENROLLMENT_WAKE_UP_REQUIRED;
  699. if(ERROR_SUCCESS != RegSetValueEx(
  700. hAEKey,
  701. AUTO_ENROLLMENT_FLAG,
  702. 0,
  703. REG_DWORD,
  704. (PBYTE)&dwFlags,
  705. sizeof(dwFlags)))
  706. goto Ret;
  707. fResult=TRUE;
  708. Ret:
  709. if(hAEKey)
  710. RegCloseKey(hAEKey);
  711. return fResult;
  712. }
  713. //--------------------------------------------------------------------------
  714. //
  715. // AESetWakeUpTimer
  716. //
  717. // Set the timer to wake us up in 8 hrs
  718. //
  719. //--------------------------------------------------------------------------
  720. BOOL WINAPI AESetWakeUpTimer(BOOL fMachine, LARGE_INTEGER *pPreTime, LARGE_INTEGER *pPostTime)
  721. {
  722. HRESULT hr;
  723. HKEY hKey;
  724. HKEY hCurrent;
  725. DWORD dwType, dwSize, dwResult;
  726. LONG lTimeout;
  727. LARGE_INTEGER DueTime;
  728. WCHAR * wszTimerName;
  729. LARGE_INTEGER EnrollmentTime;
  730. // must be cleaned up
  731. HANDLE hTimer=NULL;
  732. // Build a timer event to ping us in about 8 hours if we don't get notified sooner.
  733. lTimeout=AE_DEFAULT_REFRESH_RATE;
  734. // Query for the refresh timer value
  735. if (ERROR_SUCCESS==RegOpenKeyEx((fMachine?HKEY_LOCAL_MACHINE:HKEY_CURRENT_USER), SYSTEM_POLICIES_KEY, 0, KEY_READ, &hKey)) {
  736. dwSize=sizeof(lTimeout);
  737. if(ERROR_SUCCESS != RegQueryValueEx(hKey, TEXT("AutoEnrollmentRefreshTime"), NULL, &dwType, (LPBYTE) &lTimeout, &dwSize))
  738. {
  739. lTimeout=AE_DEFAULT_REFRESH_RATE;
  740. }
  741. else
  742. {
  743. if(REG_DWORD != dwType)
  744. lTimeout=AE_DEFAULT_REFRESH_RATE;
  745. }
  746. RegCloseKey(hKey);
  747. }
  748. // Limit the timeout to once every 240 hours (10 days)
  749. if (lTimeout>=240) {
  750. lTimeout=240;
  751. } else if (lTimeout<0) {
  752. lTimeout=0;
  753. }
  754. // Convert hours to milliseconds
  755. lTimeout=lTimeout*60*60*1000;
  756. // Special case 0 milliseconds to be 7 seconds
  757. if (lTimeout==0) {
  758. lTimeout=7000;
  759. }
  760. // convert to 10^-7s. not yet negative values are relative
  761. DueTime.QuadPart=Int32x32To64(-10000, lTimeout);
  762. // if user has hold on the UI for too long and the cycle passed the 8 hours.
  763. // we set the time for 1 hour
  764. EnrollmentTime.QuadPart=pPostTime->QuadPart - pPreTime->QuadPart;
  765. if(EnrollmentTime.QuadPart > 0)
  766. {
  767. if((-(DueTime.QuadPart)) > EnrollmentTime.QuadPart)
  768. {
  769. DueTime.QuadPart = DueTime.QuadPart + EnrollmentTime.QuadPart;
  770. }
  771. else
  772. {
  773. // Convert hours to milliseconds
  774. lTimeout=AE_DEFAULT_POSTPONE*60*60*1000;
  775. DueTime.QuadPart = Int32x32To64(-10000, lTimeout);
  776. }
  777. }
  778. // find the timer
  779. if (fMachine) {
  780. wszTimerName=L"Global\\" MACHINE_AUTOENROLLMENT_TIMER_NAME;
  781. } else {
  782. wszTimerName=USER_AUTOENROLLMENT_TIMER_NAME;
  783. }
  784. hTimer=OpenWaitableTimer(TIMER_MODIFY_STATE, false, wszTimerName);
  785. if (NULL==hTimer) {
  786. hr=HRESULT_FROM_WIN32(GetLastError());
  787. AE_DEBUG((AE_ERROR, L"OpenWaitableTimer(%s) failed with 0x%08X.\n", wszTimerName, hr));
  788. goto error;
  789. }
  790. // set the timer
  791. if (!SetWaitableTimer (hTimer, &DueTime, 0, NULL, 0, FALSE)) {
  792. hr=HRESULT_FROM_WIN32(GetLastError());
  793. AE_DEBUG((AE_ERROR, L"SetWaitableTimer failed with 0x%08X.\n", hr));
  794. goto error;
  795. }
  796. AE_DEBUG((AE_INFO, L"Set wakeup timer.\n"));
  797. hr=S_OK;
  798. error:
  799. if (NULL!=hTimer) {
  800. CloseHandle(hTimer);
  801. }
  802. return (S_OK==hr);
  803. }
  804. //--------------------------------------------------------------------------
  805. //
  806. // AEGetPendingRequestProperty
  807. //
  808. //--------------------------------------------------------------------------
  809. BOOL AEGetPendingRequestProperty(IEnroll4 *pIEnroll4,
  810. DWORD dwIndex,
  811. DWORD dwProp,
  812. LPVOID pProp)
  813. {
  814. CRYPT_DATA_BLOB *pBlob=NULL;
  815. BOOL fResult=FALSE;
  816. if((NULL==pIEnroll4) || (NULL==pProp))
  817. return FALSE;
  818. switch(dwProp)
  819. {
  820. case XEPR_REQUESTID:
  821. case XEPR_DATE:
  822. case XEPR_VERSION:
  823. fResult = (S_OK == pIEnroll4->enumPendingRequestWStr(dwIndex, dwProp, pProp));
  824. break;
  825. case XEPR_CANAME:
  826. case XEPR_CAFRIENDLYNAME:
  827. case XEPR_CADNS:
  828. case XEPR_V1TEMPLATENAME:
  829. case XEPR_V2TEMPLATEOID:
  830. case XEPR_HASH:
  831. pBlob=(CRYPT_DATA_BLOB *)pProp;
  832. pBlob->cbData=0;
  833. pBlob->pbData=NULL;
  834. if(S_OK != pIEnroll4->enumPendingRequestWStr(dwIndex, dwProp, pProp))
  835. goto Ret;
  836. if(0 == pBlob->cbData)
  837. goto Ret;
  838. pBlob->pbData=(BYTE *)LocalAlloc(LPTR, pBlob->cbData);
  839. if(NULL == pBlob->pbData)
  840. goto Ret;
  841. fResult = (S_OK == pIEnroll4->enumPendingRequestWStr(dwIndex, dwProp, pProp));
  842. break;
  843. default:
  844. break;
  845. }
  846. Ret:
  847. if(FALSE==fResult)
  848. {
  849. if(pBlob)
  850. {
  851. if(pBlob->pbData)
  852. LocalFree(pBlob->pbData);
  853. memset(pBlob, 0, sizeof(CRYPT_DATA_BLOB));
  854. }
  855. }
  856. return fResult;
  857. }
  858. //--------------------------------------------------------------------------
  859. //
  860. // AERetrieveRequestProperty
  861. //
  862. //--------------------------------------------------------------------------
  863. BOOL AERetrieveRequestProperty(IEnroll4 *pIEnroll4,
  864. DWORD dwIndex,
  865. DWORD *pdwCount,
  866. DWORD *pdwMax,
  867. CRYPT_DATA_BLOB **prgblobHash)
  868. {
  869. BOOL fResult=FALSE;
  870. CRYPT_DATA_BLOB *pblobHash=NULL;
  871. if((NULL==pIEnroll4) || (NULL==pdwCount) || (NULL==pdwMax) || (NULL==prgblobHash) ||
  872. (NULL==*prgblobHash))
  873. goto Ret;
  874. //need to alloc more memory
  875. if((*pdwCount) >= (*pdwMax))
  876. {
  877. pblobHash=*prgblobHash;
  878. *prgblobHash=(CRYPT_DATA_BLOB *)LocalAlloc(LPTR,
  879. ((*pdwMax) + PENDING_ALLOC_SIZE) * sizeof(CRYPT_DATA_BLOB));
  880. if(NULL==(*prgblobHash))
  881. {
  882. *prgblobHash=pblobHash;
  883. pblobHash=NULL;
  884. goto Ret;
  885. }
  886. memset(*prgblobHash, 0, ((*pdwMax) + PENDING_ALLOC_SIZE) * sizeof(CRYPT_DATA_BLOB));
  887. //copy the old memmory
  888. memcpy(*prgblobHash, pblobHash, (*pdwMax) * sizeof(CRYPT_DATA_BLOB));
  889. *pdwMax=(*pdwMax) + PENDING_ALLOC_SIZE;
  890. }
  891. if(!AEGetPendingRequestProperty(pIEnroll4, dwIndex, XEPR_HASH,
  892. &((*prgblobHash)[*pdwCount])))
  893. goto Ret;
  894. (*pdwCount)=(*pdwCount) + 1;
  895. fResult=TRUE;
  896. Ret:
  897. if(pblobHash)
  898. LocalFree(pblobHash);
  899. return fResult;
  900. }
  901. //--------------------------------------------------------------------------
  902. //
  903. // AERemovePendingRequest
  904. //
  905. //--------------------------------------------------------------------------
  906. BOOL AERemovePendingRequest(IEnroll4 *pIEnroll4,
  907. DWORD dwCount,
  908. CRYPT_DATA_BLOB *rgblobHash)
  909. {
  910. DWORD dwIndex=0;
  911. BOOL fResult=TRUE;
  912. if((NULL==pIEnroll4) || (NULL==rgblobHash))
  913. return FALSE;
  914. for(dwIndex=0; dwIndex < dwCount; dwIndex++)
  915. {
  916. if(S_OK != (pIEnroll4->removePendingRequestWStr(rgblobHash[dwIndex])))
  917. fResult=FALSE;
  918. }
  919. return fResult;
  920. }
  921. //--------------------------------------------------------------------------
  922. //
  923. // AEFreePendingRequests
  924. //
  925. //--------------------------------------------------------------------------
  926. BOOL AEFreePendingRequests(DWORD dwCount, CRYPT_DATA_BLOB *rgblobHash)
  927. {
  928. DWORD dwIndex=0;
  929. if(rgblobHash)
  930. {
  931. for(dwIndex=0; dwIndex < dwCount; dwIndex++)
  932. {
  933. if(rgblobHash[dwIndex].pbData)
  934. LocalFree(rgblobHash[dwIndex].pbData);
  935. }
  936. LocalFree(rgblobHash);
  937. }
  938. return TRUE;
  939. }
  940. //--------------------------------------------------------------------------
  941. //
  942. // AEValidVersionCert
  943. //
  944. // Verify the certificate returned from CA has the latest version info.
  945. // If so, copy the certificate to the hIssuedStore for potentical publishing
  946. //
  947. //--------------------------------------------------------------------------
  948. BOOL AEValidVersionCert(AE_CERTTYPE_INFO *pCertType, IEnroll4 *pIEnroll4, CRYPT_DATA_BLOB *pBlobPKCS7)
  949. {
  950. BOOL fValid=FALSE;
  951. PCCERT_CONTEXT pCertContext=NULL;
  952. AE_TEMPLATE_INFO AETemplateInfo;
  953. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  954. if((NULL==pCertType) || (NULL==pIEnroll4) || (NULL==pBlobPKCS7))
  955. goto Ret;
  956. if(NULL==(pBlobPKCS7->pbData))
  957. goto Ret;
  958. if(S_OK != pIEnroll4->getCertContextFromResponseBlob(pBlobPKCS7, &pCertContext))
  959. goto Ret;
  960. if(!AERetrieveTemplateInfo(pCertContext, &AETemplateInfo))
  961. goto Ret;
  962. if(AETemplateInfo.pwszOid)
  963. {
  964. if(AETemplateInfo.dwVersion >= (pCertType->dwVersion))
  965. fValid=TRUE;
  966. }
  967. else
  968. {
  969. //V1 template
  970. if(NULL == AETemplateInfo.pwszName)
  971. goto Ret;
  972. fValid=TRUE;
  973. }
  974. if(pCertContext && (TRUE == fValid))
  975. {
  976. CertAddCertificateContextToStore(pCertType->hIssuedStore,
  977. pCertContext,
  978. CERT_STORE_ADD_USE_EXISTING,
  979. NULL);
  980. }
  981. Ret:
  982. if(pCertContext)
  983. CertFreeCertificateContext(pCertContext);
  984. AEFreeTemplateInfo(&AETemplateInfo);
  985. return fValid;
  986. }
  987. //--------------------------------------------------------------------------
  988. //
  989. // AECopyPendingBlob
  990. //
  991. // Copy the issued PKCS7 and request hash.
  992. //
  993. //--------------------------------------------------------------------------
  994. BOOL AECopyPendingBlob(CRYPT_DATA_BLOB *pBlobPKCS7,
  995. IEnroll4 *pIEnroll4,
  996. DWORD dwXenrollIndex,
  997. AE_CERTTYPE_INFO *pCertType)
  998. {
  999. BOOL fResult=FALSE;
  1000. DWORD dwIndex=0;
  1001. AE_PEND_INFO *pPendInfo=NULL;
  1002. if((NULL==pBlobPKCS7)||(NULL==pIEnroll4)||(NULL==pCertType))
  1003. goto Ret;
  1004. if(NULL==(pBlobPKCS7->pbData))
  1005. goto Ret;
  1006. dwIndex=pCertType->dwPendCount;
  1007. //increase the memory array
  1008. if(0 != dwIndex)
  1009. {
  1010. pPendInfo=pCertType->rgPendInfo;
  1011. pCertType->rgPendInfo=(AE_PEND_INFO *)LocalAlloc(LPTR,
  1012. (dwIndex + 1) * sizeof(AE_PEND_INFO));
  1013. if(NULL==(pCertType->rgPendInfo))
  1014. {
  1015. pCertType->rgPendInfo=pPendInfo;
  1016. pPendInfo=NULL;
  1017. goto Ret;
  1018. }
  1019. memset(pCertType->rgPendInfo, 0, (dwIndex + 1) * sizeof(AE_PEND_INFO));
  1020. //copy the old memmory
  1021. memcpy(pCertType->rgPendInfo, pPendInfo, (dwIndex) * sizeof(AE_PEND_INFO));
  1022. }
  1023. else
  1024. {
  1025. pCertType->rgPendInfo=(AE_PEND_INFO *)LocalAlloc(LPTR, sizeof(AE_PEND_INFO));
  1026. if(NULL==(pCertType->rgPendInfo))
  1027. goto Ret;
  1028. memset(pCertType->rgPendInfo, 0, sizeof(AE_PEND_INFO));
  1029. }
  1030. //copy the issued PKCS7 blob
  1031. (pCertType->rgPendInfo)[dwIndex].blobPKCS7.pbData=(BYTE *)LocalAlloc(
  1032. LPTR,
  1033. pBlobPKCS7->cbData);
  1034. if(NULL == ((pCertType->rgPendInfo)[dwIndex].blobPKCS7.pbData))
  1035. goto Ret;
  1036. memcpy((pCertType->rgPendInfo)[dwIndex].blobPKCS7.pbData,
  1037. pBlobPKCS7->pbData,
  1038. pBlobPKCS7->cbData);
  1039. (pCertType->rgPendInfo)[dwIndex].blobPKCS7.cbData=pBlobPKCS7->cbData;
  1040. //copy the hash of the request
  1041. if(!AEGetPendingRequestProperty(pIEnroll4, dwXenrollIndex, XEPR_HASH,
  1042. &((pCertType->rgPendInfo)[dwIndex].blobHash)))
  1043. {
  1044. LocalFree((pCertType->rgPendInfo)[dwIndex].blobPKCS7.pbData);
  1045. (pCertType->rgPendInfo)[dwIndex].blobPKCS7.pbData=NULL;
  1046. (pCertType->rgPendInfo)[dwIndex].blobPKCS7.cbData=0;
  1047. goto Ret;
  1048. }
  1049. (pCertType->dwPendCount)++;
  1050. fResult=TRUE;
  1051. Ret:
  1052. if(pPendInfo)
  1053. LocalFree(pPendInfo);
  1054. return fResult;
  1055. }
  1056. //--------------------------------------------------------------------------
  1057. //
  1058. // AEProcessUIPendingRequest
  1059. //
  1060. // In this function, we install the issued pending certificate request
  1061. // that will require UI.
  1062. //
  1063. //--------------------------------------------------------------------------
  1064. BOOL WINAPI AEProcessUIPendingRequest(AE_GENERAL_INFO *pAE_General_Info)
  1065. {
  1066. DWORD dwIndex=0;
  1067. DWORD dwPendIndex=0;
  1068. AE_CERTTYPE_INFO *pCertTypeInfo=pAE_General_Info->rgCertTypeInfo;
  1069. AE_CERTTYPE_INFO *pCertType=NULL;
  1070. BOOL fInit=FALSE;
  1071. PFNPIEnroll4GetNoCOM pfnPIEnroll4GetNoCOM=NULL;
  1072. HMODULE hXenroll=NULL;
  1073. HRESULT hr=E_FAIL;
  1074. IEnroll4 *pIEnroll4=NULL;
  1075. if(NULL==pAE_General_Info)
  1076. goto Ret;
  1077. //has to be in the UI mode
  1078. if(FALSE == pAE_General_Info->fUIProcess)
  1079. goto Ret;
  1080. if(NULL==pCertTypeInfo)
  1081. goto Ret;
  1082. hXenroll=pAE_General_Info->hXenroll;
  1083. if(NULL==hXenroll)
  1084. goto Ret;
  1085. if(NULL==(pfnPIEnroll4GetNoCOM=(PFNPIEnroll4GetNoCOM)GetProcAddress(
  1086. hXenroll,
  1087. "PIEnroll4GetNoCOM")))
  1088. goto Ret;
  1089. if(FAILED(CoInitialize(NULL)))
  1090. goto Ret;
  1091. fInit=TRUE;
  1092. if(NULL==(pIEnroll4=pfnPIEnroll4GetNoCOM()))
  1093. goto Ret;
  1094. //Set the request store flag based on fMachine
  1095. if(pAE_General_Info->fMachine)
  1096. {
  1097. if(S_OK != pIEnroll4->put_RequestStoreFlags(CERT_SYSTEM_STORE_LOCAL_MACHINE))
  1098. goto Ret;
  1099. }
  1100. else
  1101. {
  1102. if(S_OK != pIEnroll4->put_RequestStoreFlags(CERT_SYSTEM_STORE_CURRENT_USER))
  1103. goto Ret;
  1104. }
  1105. //initialize the enumerator
  1106. if(S_OK != pIEnroll4->enumPendingRequestWStr(XEPR_ENUM_FIRST, 0, NULL))
  1107. goto Ret;
  1108. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  1109. {
  1110. pCertType = &(pCertTypeInfo[dwIndex]);
  1111. if(pCertType->dwPendCount)
  1112. {
  1113. for(dwPendIndex=0; dwPendIndex < pCertType->dwPendCount; dwPendIndex++)
  1114. {
  1115. //check if cancel button is clicked
  1116. if(AECancelled(pAE_General_Info->hCancelEvent))
  1117. break;
  1118. //report the current enrollment action
  1119. AEUIProgressReport(TRUE, pCertType, pAE_General_Info->hwndDlg, pAE_General_Info->hCancelEvent);
  1120. //install the certificate
  1121. if(S_OK == (hr = pIEnroll4->acceptResponseBlob(
  1122. &((pCertType->rgPendInfo)[dwPendIndex].blobPKCS7))))
  1123. {
  1124. //mark the status to obtained if required
  1125. //this is a valid certificate
  1126. if(AEValidVersionCert(pCertType, pIEnroll4, &((pCertType->rgPendInfo)[dwPendIndex].blobPKCS7)))
  1127. pCertType->dwStatus = CERT_REQUEST_STATUS_OBTAINED;
  1128. //the certificate is successfully issued and installed
  1129. //remove the request from the request store
  1130. pIEnroll4->removePendingRequestWStr((pCertType->rgPendInfo)[dwPendIndex].blobHash);
  1131. AELogAutoEnrollmentEvent(
  1132. pAE_General_Info->dwLogLevel,
  1133. FALSE,
  1134. S_OK,
  1135. EVENT_PENDING_INSTALLED,
  1136. pAE_General_Info->fMachine,
  1137. pAE_General_Info->hToken,
  1138. 1,
  1139. pCertType->awszDisplay[0]);
  1140. }
  1141. else
  1142. {
  1143. //doing this for summary page
  1144. if((SCARD_E_CANCELLED != hr) && (SCARD_W_CANCELLED_BY_USER != hr))
  1145. pCertType->idsSummary=IDS_SUMMARY_INSTALL;
  1146. AELogAutoEnrollmentEvent(
  1147. pAE_General_Info->dwLogLevel,
  1148. TRUE,
  1149. hr,
  1150. EVENT_PENDING_FAILED,
  1151. pAE_General_Info->fMachine,
  1152. pAE_General_Info->hToken,
  1153. 1,
  1154. pCertType->awszDisplay[0]);
  1155. }
  1156. //advance progress
  1157. AEUIProgressAdvance(pAE_General_Info);
  1158. }
  1159. }
  1160. }
  1161. Ret:
  1162. if(pIEnroll4)
  1163. pIEnroll4->Release();
  1164. if(fInit)
  1165. CoUninitialize();
  1166. return TRUE;
  1167. }
  1168. //--------------------------------------------------------------------------
  1169. //
  1170. // AEProcessPendingRequest -- UIless call.
  1171. //
  1172. // In this function, we check each pending requests in the request store.
  1173. // We install the certificate is the request has been issued by the CA, and
  1174. // mark the certificate type status to obtained if the certificate is issued
  1175. // and of correct version
  1176. //
  1177. // We remove any requests that are stale based on the # of days defined
  1178. // in the registry. If no value is defined in the registry, use
  1179. // AE_PENDING_REQUEST_ACTIVE_PERIOD (60 days).
  1180. //
  1181. // Also, if there is no more pending requests active in the request store,
  1182. // we set the registry value to indicate that winlogon should not wake us up.
  1183. //
  1184. //--------------------------------------------------------------------------
  1185. BOOL WINAPI AEProcessPendingRequest(AE_GENERAL_INFO *pAE_General_Info)
  1186. {
  1187. DWORD dwRequestID=0;
  1188. LONG dwDisposition=0;
  1189. DWORD dwIndex=0;
  1190. DWORD dwCount=0;
  1191. DWORD dwMax=PENDING_ALLOC_SIZE;
  1192. AE_CERTTYPE_INFO *pCertType=NULL;
  1193. PFNPIEnroll4GetNoCOM pfnPIEnroll4GetNoCOM=NULL;
  1194. BOOL fInit=FALSE;
  1195. AE_TEMPLATE_INFO AETemplateInfo;
  1196. CRYPT_DATA_BLOB blobPKCS7;
  1197. HMODULE hXenroll=NULL;
  1198. VARIANT varCMC;
  1199. HRESULT hr=E_FAIL;
  1200. IEnroll4 *pIEnroll4=NULL;
  1201. ICertRequest2 *pICertRequest=NULL;
  1202. BSTR bstrCert=NULL;
  1203. LPWSTR pwszCAConfig=NULL;
  1204. BSTR bstrConfig=NULL;
  1205. CRYPT_DATA_BLOB *rgblobHash=NULL;
  1206. CRYPT_DATA_BLOB blobCAName;
  1207. CRYPT_DATA_BLOB blobCALocation;
  1208. CRYPT_DATA_BLOB blobName;
  1209. if(NULL==pAE_General_Info)
  1210. goto Ret;
  1211. //init the dwUIPendCount to 0
  1212. pAE_General_Info->dwUIPendCount=0;
  1213. //has to be in the UIless mode
  1214. if(TRUE == pAE_General_Info->fUIProcess)
  1215. goto Ret;
  1216. hXenroll=pAE_General_Info->hXenroll;
  1217. if(NULL==hXenroll)
  1218. goto Ret;
  1219. if(NULL==(pfnPIEnroll4GetNoCOM=(PFNPIEnroll4GetNoCOM)GetProcAddress(
  1220. hXenroll,
  1221. "PIEnroll4GetNoCOM")))
  1222. goto Ret;
  1223. if(FAILED(CoInitialize(NULL)))
  1224. goto Ret;
  1225. fInit=TRUE;
  1226. if(NULL==(pIEnroll4=pfnPIEnroll4GetNoCOM()))
  1227. goto Ret;
  1228. if(S_OK != CoCreateInstance(CLSID_CCertRequest,
  1229. NULL,
  1230. CLSCTX_INPROC_SERVER,
  1231. IID_ICertRequest2,
  1232. (void **)&pICertRequest))
  1233. goto Ret;
  1234. //Set the request store flag based on fMachine
  1235. if(pAE_General_Info->fMachine)
  1236. {
  1237. if(S_OK != pIEnroll4->put_RequestStoreFlags(CERT_SYSTEM_STORE_LOCAL_MACHINE))
  1238. goto Ret;
  1239. }
  1240. else
  1241. {
  1242. if(S_OK != pIEnroll4->put_RequestStoreFlags(CERT_SYSTEM_STORE_CURRENT_USER))
  1243. goto Ret;
  1244. }
  1245. memset(&blobCAName, 0, sizeof(blobCAName));
  1246. memset(&blobCALocation, 0, sizeof(blobCALocation));
  1247. memset(&blobName, 0, sizeof(blobName));
  1248. memset(&AETemplateInfo, 0, sizeof(AETemplateInfo));
  1249. rgblobHash=(CRYPT_DATA_BLOB *)LocalAlloc(LPTR, dwMax * sizeof(CRYPT_DATA_BLOB));
  1250. if(NULL==rgblobHash)
  1251. goto Ret;
  1252. memset(rgblobHash, 0, dwMax * sizeof(CRYPT_DATA_BLOB));
  1253. //initialize the enumerator
  1254. if(S_OK != pIEnroll4->enumPendingRequestWStr(XEPR_ENUM_FIRST, 0, NULL))
  1255. goto Ret;
  1256. //initlialize the variant
  1257. VariantInit(&varCMC);
  1258. while(AEGetPendingRequestProperty(
  1259. pIEnroll4,
  1260. dwIndex,
  1261. XEPR_REQUESTID,
  1262. &dwRequestID))
  1263. {
  1264. //query the status of the requests to the CA
  1265. if(!AEGetPendingRequestProperty(
  1266. pIEnroll4,
  1267. dwIndex,
  1268. XEPR_CANAME,
  1269. &blobCAName))
  1270. goto Next;
  1271. if(!AEGetPendingRequestProperty(
  1272. pIEnroll4,
  1273. dwIndex,
  1274. XEPR_CADNS,
  1275. &blobCALocation))
  1276. goto Next;
  1277. //build the config string
  1278. pwszCAConfig=(LPWSTR)LocalAlloc(LPTR,
  1279. sizeof(WCHAR) * (wcslen((LPWSTR)(blobCALocation.pbData)) + wcslen((LPWSTR)(blobCAName.pbData)) + wcslen(L"\\") + 1));
  1280. if(NULL==pwszCAConfig)
  1281. goto Next;
  1282. wcscpy(pwszCAConfig, (LPWSTR)(blobCALocation.pbData));
  1283. wcscat(pwszCAConfig, L"\\");
  1284. wcscat(pwszCAConfig, (LPWSTR)(blobCAName.pbData));
  1285. //conver to bstr
  1286. bstrConfig=SysAllocString(pwszCAConfig);
  1287. if(NULL==bstrConfig)
  1288. goto Next;
  1289. //find the template information
  1290. //get the version and the template name of the request
  1291. if(AEGetPendingRequestProperty(pIEnroll4, dwIndex, XEPR_V2TEMPLATEOID, &blobName))
  1292. {
  1293. AETemplateInfo.pwszOid=(LPWSTR)blobName.pbData;
  1294. }
  1295. else
  1296. {
  1297. if(!AEGetPendingRequestProperty(pIEnroll4, dwIndex, XEPR_V1TEMPLATENAME, &blobName))
  1298. goto Next;
  1299. AETemplateInfo.pwszName=(LPWSTR)blobName.pbData;
  1300. }
  1301. //find the template
  1302. if(NULL==(pCertType=AEFindTemplateInRequestTree(
  1303. &AETemplateInfo, pAE_General_Info)))
  1304. goto Next;
  1305. if(S_OK != pICertRequest->RetrievePending(
  1306. dwRequestID,
  1307. bstrConfig,
  1308. &dwDisposition))
  1309. goto Next;
  1310. switch(dwDisposition)
  1311. {
  1312. case CR_DISP_ISSUED:
  1313. if(S_OK != pICertRequest->GetFullResponseProperty(
  1314. FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BINARY,
  1315. &varCMC))
  1316. {
  1317. goto Next;
  1318. }
  1319. // Check to make sure we've gotten a BSTR back:
  1320. if (VT_BSTR != varCMC.vt)
  1321. {
  1322. goto Next;
  1323. }
  1324. bstrCert = varCMC.bstrVal;
  1325. // Marshal the cert into a CRYPT_DATA_BLOB:
  1326. blobPKCS7.cbData = (DWORD)SysStringByteLen(bstrCert);
  1327. blobPKCS7.pbData = (BYTE *)bstrCert;
  1328. // we will keep the PKCS7 blob for installation
  1329. if(CT_FLAG_USER_INTERACTION_REQUIRED & (pCertType->dwEnrollmentFlag))
  1330. {
  1331. //signal that we should pop up the UI balloon
  1332. (pAE_General_Info->dwUIPendCount)++;
  1333. //copy the PKCS7 blob from the cert server
  1334. AECopyPendingBlob(&blobPKCS7,
  1335. pIEnroll4,
  1336. dwIndex,
  1337. pCertType);
  1338. }
  1339. else
  1340. {
  1341. //install the certificate
  1342. if(S_OK != (hr = pIEnroll4->acceptResponseBlob(&blobPKCS7)))
  1343. {
  1344. AELogAutoEnrollmentEvent(
  1345. pAE_General_Info->dwLogLevel,
  1346. TRUE,
  1347. hr,
  1348. EVENT_PENDING_FAILED,
  1349. pAE_General_Info->fMachine,
  1350. pAE_General_Info->hToken,
  1351. 1,
  1352. pCertType->awszDisplay[0]);
  1353. goto Next;
  1354. }
  1355. //mark the status to obtained if required
  1356. //this is a valid certificate
  1357. if(AEValidVersionCert(pCertType, pIEnroll4, &blobPKCS7))
  1358. pCertType->dwStatus = CERT_REQUEST_STATUS_OBTAINED;
  1359. //the certificate is successfully issued and installed
  1360. //remove the request from the request store
  1361. AERetrieveRequestProperty(pIEnroll4, dwIndex, &dwCount, &dwMax, &rgblobHash);
  1362. }
  1363. AELogAutoEnrollmentEvent(
  1364. pAE_General_Info->dwLogLevel,
  1365. FALSE,
  1366. S_OK,
  1367. EVENT_PENDING_ISSUED,
  1368. pAE_General_Info->fMachine,
  1369. pAE_General_Info->hToken,
  1370. 2,
  1371. pCertType->awszDisplay[0],
  1372. pwszCAConfig);
  1373. break;
  1374. case CR_DISP_UNDER_SUBMISSION:
  1375. AELogAutoEnrollmentEvent(
  1376. pAE_General_Info->dwLogLevel,
  1377. FALSE,
  1378. S_OK,
  1379. EVENT_PENDING_PEND,
  1380. pAE_General_Info->fMachine,
  1381. pAE_General_Info->hToken,
  1382. 2,
  1383. pCertType->awszDisplay[0],
  1384. pwszCAConfig);
  1385. break;
  1386. case CR_DISP_INCOMPLETE:
  1387. case CR_DISP_ERROR:
  1388. case CR_DISP_DENIED:
  1389. case CR_DISP_ISSUED_OUT_OF_BAND: //we consider it a failure in this case
  1390. case CR_DISP_REVOKED:
  1391. default:
  1392. //requests failed. remove the request from the request store
  1393. AERetrieveRequestProperty(pIEnroll4, dwIndex, &dwCount, &dwMax, &rgblobHash);
  1394. if(S_OK == pICertRequest->GetLastStatus(&hr))
  1395. {
  1396. AELogAutoEnrollmentEvent(
  1397. pAE_General_Info->dwLogLevel,
  1398. TRUE,
  1399. hr,
  1400. EVENT_PENDING_DENIED,
  1401. pAE_General_Info->fMachine,
  1402. pAE_General_Info->hToken,
  1403. 2,
  1404. pwszCAConfig,
  1405. pCertType->awszDisplay[0]);
  1406. }
  1407. break;
  1408. }
  1409. Next:
  1410. if(pwszCAConfig)
  1411. LocalFree(pwszCAConfig);
  1412. pwszCAConfig=NULL;
  1413. if(bstrConfig)
  1414. SysFreeString(bstrConfig);
  1415. bstrConfig=NULL;
  1416. if(bstrCert)
  1417. SysFreeString(bstrCert);
  1418. bstrCert=NULL;
  1419. if(blobCAName.pbData)
  1420. LocalFree(blobCAName.pbData);
  1421. memset(&blobCAName, 0, sizeof(blobCAName));
  1422. if(blobCALocation.pbData)
  1423. LocalFree(blobCALocation.pbData);
  1424. memset(&blobCALocation, 0, sizeof(blobCALocation));
  1425. if(blobName.pbData)
  1426. LocalFree(blobName.pbData);
  1427. memset(&blobName, 0, sizeof(blobName));
  1428. memset(&AETemplateInfo, 0, sizeof(AETemplateInfo));
  1429. VariantInit(&varCMC);
  1430. dwIndex++;
  1431. }
  1432. //remove the requests based the hash
  1433. AERemovePendingRequest(pIEnroll4, dwCount, rgblobHash);
  1434. Ret:
  1435. AEFreePendingRequests(dwCount, rgblobHash);
  1436. if(pICertRequest)
  1437. pICertRequest->Release();
  1438. if(pIEnroll4)
  1439. pIEnroll4->Release();
  1440. if(fInit)
  1441. CoUninitialize();
  1442. return TRUE;
  1443. }
  1444. //--------------------------------------------------------------------------
  1445. //
  1446. // AEIsLocalSystem
  1447. //
  1448. //--------------------------------------------------------------------------
  1449. BOOL
  1450. AEIsLocalSystem(BOOL *pfIsLocalSystem)
  1451. {
  1452. HANDLE hToken = 0;
  1453. SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
  1454. BOOL fRet = FALSE;
  1455. BOOL fRevertToSelf = FALSE;
  1456. PSID psidLocalSystem = NULL;
  1457. *pfIsLocalSystem = FALSE;
  1458. if (!OpenThreadToken(
  1459. GetCurrentThread(),
  1460. TOKEN_QUERY,
  1461. TRUE,
  1462. &hToken))
  1463. {
  1464. if (ERROR_NO_TOKEN != GetLastError())
  1465. goto Ret;
  1466. //we need to impersonateself and get the thread token again
  1467. if(!ImpersonateSelf(SecurityImpersonation))
  1468. goto Ret;
  1469. fRevertToSelf = TRUE;
  1470. if (!OpenThreadToken(
  1471. GetCurrentThread(),
  1472. TOKEN_QUERY,
  1473. TRUE,
  1474. &hToken))
  1475. goto Ret;
  1476. }
  1477. //build the well known local system SID (s-1-5-18)
  1478. if (!AllocateAndInitializeSid(
  1479. &siaNtAuthority,
  1480. 1,
  1481. SECURITY_LOCAL_SYSTEM_RID,
  1482. 0, 0, 0, 0, 0, 0, 0,
  1483. &psidLocalSystem
  1484. ))
  1485. goto Ret;
  1486. fRet = CheckTokenMembership(
  1487. hToken,
  1488. psidLocalSystem,
  1489. pfIsLocalSystem);
  1490. Ret:
  1491. if(fRevertToSelf)
  1492. RevertToSelf();
  1493. if(psidLocalSystem)
  1494. FreeSid(psidLocalSystem);
  1495. if (hToken)
  1496. CloseHandle(hToken);
  1497. return fRet;
  1498. }
  1499. //--------------------------------------------------------------------------
  1500. //
  1501. // AEInSafeBoot
  1502. //
  1503. // copied from the service controller code
  1504. //--------------------------------------------------------------------------
  1505. BOOL WINAPI AEInSafeBoot()
  1506. {
  1507. DWORD dwSafeBoot = 0;
  1508. DWORD cbSafeBoot = sizeof(dwSafeBoot);
  1509. DWORD dwType = 0;
  1510. HKEY hKeySafeBoot = NULL;
  1511. if(ERROR_SUCCESS == RegOpenKeyW(
  1512. HKEY_LOCAL_MACHINE,
  1513. L"system\\currentcontrolset\\control\\safeboot\\option",
  1514. &hKeySafeBoot))
  1515. {
  1516. // we did in fact boot under safeboot control
  1517. if(ERROR_SUCCESS != RegQueryValueExW(
  1518. hKeySafeBoot,
  1519. L"OptionValue",
  1520. NULL,
  1521. &dwType,
  1522. (LPBYTE)&dwSafeBoot,
  1523. &cbSafeBoot))
  1524. {
  1525. dwSafeBoot = 0;
  1526. }
  1527. if(hKeySafeBoot)
  1528. RegCloseKey(hKeySafeBoot);
  1529. }
  1530. return (0 != dwSafeBoot);
  1531. }
  1532. //--------------------------------------------------------------------------
  1533. //
  1534. // AEIsDomainMember
  1535. //
  1536. //--------------------------------------------------------------------------
  1537. BOOL WINAPI AEIsDomainMember()
  1538. {
  1539. DWORD dwErr;
  1540. BOOL bIsDomainMember=FALSE;
  1541. // must be cleaned up
  1542. DSROLE_PRIMARY_DOMAIN_INFO_BASIC * pDomInfo=NULL;
  1543. dwErr=DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (BYTE **)&pDomInfo);
  1544. if (ERROR_SUCCESS==dwErr)
  1545. {
  1546. if (DsRole_RoleStandaloneWorkstation!=pDomInfo->MachineRole
  1547. && DsRole_RoleStandaloneServer!=pDomInfo->MachineRole)
  1548. {
  1549. //no autoenrollment on NT4
  1550. if(NULL != (pDomInfo->DomainNameDns))
  1551. {
  1552. bIsDomainMember=TRUE;
  1553. }
  1554. }
  1555. }
  1556. if (NULL!=pDomInfo)
  1557. {
  1558. DsRoleFreeMemory(pDomInfo);
  1559. }
  1560. return bIsDomainMember;
  1561. }
  1562. //-----------------------------------------------------------------------
  1563. //
  1564. // AEGetPolicyFlag
  1565. //
  1566. //-----------------------------------------------------------------------
  1567. BOOL AEGetPolicyFlag(BOOL fMachine, DWORD *pdwPolicy)
  1568. {
  1569. DWORD dwPolicy = 0;
  1570. DWORD cbPolicy = sizeof(dwPolicy);
  1571. DWORD dwType = 0;
  1572. HKEY hKey = NULL;
  1573. if(ERROR_SUCCESS == RegOpenKeyW(
  1574. fMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
  1575. AUTO_ENROLLMENT_KEY,
  1576. &hKey))
  1577. {
  1578. if(ERROR_SUCCESS != RegQueryValueExW(
  1579. hKey,
  1580. AUTO_ENROLLMENT_POLICY,
  1581. NULL,
  1582. &dwType,
  1583. (LPBYTE)&dwPolicy,
  1584. &cbPolicy))
  1585. {
  1586. dwPolicy = 0;
  1587. }
  1588. else
  1589. {
  1590. if(REG_DWORD != dwType)
  1591. dwPolicy=0;
  1592. }
  1593. if(hKey)
  1594. RegCloseKey(hKey);
  1595. }
  1596. *pdwPolicy=dwPolicy;
  1597. return TRUE;
  1598. }
  1599. //-----------------------------------------------------------------------
  1600. //
  1601. // AERetrieveLogLevel
  1602. //
  1603. //-----------------------------------------------------------------------
  1604. BOOL AERetrieveLogLevel(BOOL fMachine, DWORD *pdwLogLevel)
  1605. {
  1606. DWORD dwLogLevel = STATUS_SEVERITY_ERROR; //we default to highest logging level
  1607. DWORD cbLogLevel = sizeof(dwLogLevel);
  1608. DWORD dwType = 0;
  1609. HKEY hKey = NULL;
  1610. if(ERROR_SUCCESS == RegOpenKeyW(
  1611. fMachine ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
  1612. AUTO_ENROLLMENT_EVENT_LEVEL_KEY,
  1613. &hKey))
  1614. {
  1615. if(ERROR_SUCCESS != RegQueryValueExW(
  1616. hKey,
  1617. AUTO_ENROLLMENT_EVENT_LEVEL,
  1618. NULL,
  1619. &dwType,
  1620. (LPBYTE)&dwLogLevel,
  1621. &cbLogLevel))
  1622. {
  1623. dwLogLevel = STATUS_SEVERITY_ERROR;
  1624. }
  1625. else
  1626. {
  1627. if(REG_DWORD != dwType)
  1628. dwLogLevel = STATUS_SEVERITY_ERROR;
  1629. }
  1630. if(hKey)
  1631. RegCloseKey(hKey);
  1632. }
  1633. *pdwLogLevel=dwLogLevel;
  1634. return TRUE;
  1635. }
  1636. //-----------------------------------------------------------------------
  1637. //
  1638. // AERetrieveTemplateInfo
  1639. //
  1640. //-----------------------------------------------------------------------
  1641. BOOL AERetrieveTemplateInfo(PCCERT_CONTEXT pCertCurrent,
  1642. AE_TEMPLATE_INFO *pTemplateInfo)
  1643. {
  1644. BOOL fResult = FALSE;
  1645. PCERT_EXTENSION pExt = NULL;
  1646. DWORD cbData=0;
  1647. CERT_NAME_VALUE *pbName = NULL;
  1648. CERT_TEMPLATE_EXT *pbTemplate = NULL;
  1649. if((NULL==pCertCurrent) || (NULL==pTemplateInfo))
  1650. goto Ret;
  1651. memset(pTemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  1652. //try to find V2 template extension first
  1653. if(pExt = CertFindExtension(szOID_CERTIFICATE_TEMPLATE,
  1654. pCertCurrent->pCertInfo->cExtension,
  1655. pCertCurrent->pCertInfo->rgExtension))
  1656. {
  1657. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1658. szOID_CERTIFICATE_TEMPLATE,
  1659. pExt->Value.pbData,
  1660. pExt->Value.cbData,
  1661. 0,
  1662. NULL,
  1663. &cbData))
  1664. goto Ret;
  1665. pbTemplate = (CERT_TEMPLATE_EXT *)LocalAlloc(LPTR, cbData);
  1666. if(NULL==pbTemplate)
  1667. goto Ret;
  1668. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1669. szOID_CERTIFICATE_TEMPLATE,
  1670. pExt->Value.pbData,
  1671. pExt->Value.cbData,
  1672. 0,
  1673. pbTemplate,
  1674. &cbData))
  1675. goto Ret;
  1676. //copy the version
  1677. pTemplateInfo->dwVersion=pbTemplate->dwMajorVersion;
  1678. //copy the extension oid
  1679. if(NULL==pbTemplate->pszObjId)
  1680. goto Ret;
  1681. if(0 == (cbData = MultiByteToWideChar(CP_ACP,
  1682. 0,
  1683. pbTemplate->pszObjId,
  1684. -1,
  1685. NULL,
  1686. 0)))
  1687. goto Ret;
  1688. if(NULL==(pTemplateInfo->pwszOid=(LPWSTR)LocalAlloc(LPTR, cbData * sizeof(WCHAR))))
  1689. goto Ret;
  1690. if(0 == MultiByteToWideChar(CP_ACP,
  1691. 0,
  1692. pbTemplate->pszObjId,
  1693. -1,
  1694. pTemplateInfo->pwszOid,
  1695. cbData))
  1696. goto Ret;
  1697. }
  1698. else
  1699. {
  1700. //try V1 template extension
  1701. if(NULL == (pExt = CertFindExtension(
  1702. szOID_ENROLL_CERTTYPE_EXTENSION,
  1703. pCertCurrent->pCertInfo->cExtension,
  1704. pCertCurrent->pCertInfo->rgExtension)))
  1705. goto Ret;
  1706. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1707. X509_UNICODE_ANY_STRING,
  1708. pExt->Value.pbData,
  1709. pExt->Value.cbData,
  1710. 0,
  1711. NULL,
  1712. &cbData))
  1713. goto Ret;
  1714. pbName = (CERT_NAME_VALUE *)LocalAlloc(LPTR, cbData);
  1715. if(NULL==pbName)
  1716. goto Ret;
  1717. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1718. X509_UNICODE_ANY_STRING,
  1719. pExt->Value.pbData,
  1720. pExt->Value.cbData,
  1721. 0,
  1722. pbName,
  1723. &cbData))
  1724. goto Ret;
  1725. if(!AEAllocAndCopy((LPWSTR)(pbName->Value.pbData),
  1726. &(pTemplateInfo->pwszName)))
  1727. goto Ret;
  1728. }
  1729. fResult = TRUE;
  1730. Ret:
  1731. if(pbTemplate)
  1732. LocalFree(pbTemplate);
  1733. if(pbName)
  1734. LocalFree(pbName);
  1735. return fResult;
  1736. }
  1737. //-----------------------------------------------------------------------
  1738. //
  1739. // AEFreeTemplateInfo
  1740. //
  1741. //-----------------------------------------------------------------------
  1742. BOOL AEFreeTemplateInfo(AE_TEMPLATE_INFO *pAETemplateInfo)
  1743. {
  1744. if(pAETemplateInfo->pwszName)
  1745. LocalFree(pAETemplateInfo->pwszName);
  1746. if(pAETemplateInfo->pwszOid)
  1747. LocalFree(pAETemplateInfo->pwszOid);
  1748. memset(pAETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  1749. return TRUE;
  1750. }
  1751. //-----------------------------------------------------------------------
  1752. //
  1753. // AEFindTemplateInRequestTree
  1754. //
  1755. //-----------------------------------------------------------------------
  1756. AE_CERTTYPE_INFO *AEFindTemplateInRequestTree(AE_TEMPLATE_INFO *pTemplateInfo,
  1757. AE_GENERAL_INFO *pAE_General_Info)
  1758. {
  1759. DWORD dwIndex = 0;
  1760. AE_CERTTYPE_INFO *rgCertTypeInfo=NULL;
  1761. AE_CERTTYPE_INFO *pCertType=NULL;
  1762. if(NULL == (rgCertTypeInfo=pAE_General_Info->rgCertTypeInfo))
  1763. return NULL;
  1764. if( (NULL == pTemplateInfo->pwszName) && (NULL == pTemplateInfo->pwszOid))
  1765. return NULL;
  1766. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  1767. {
  1768. if(pTemplateInfo->pwszOid)
  1769. {
  1770. //we are guaranteed to have an OID if the schema is greater than or equal to 2
  1771. if(rgCertTypeInfo[dwIndex].dwSchemaVersion >= CERTTYPE_SCHEMA_VERSION_2)
  1772. {
  1773. if(0 == wcscmp(pTemplateInfo->pwszOid, (rgCertTypeInfo[dwIndex].awszOID)[0]))
  1774. {
  1775. pCertType = &(rgCertTypeInfo[dwIndex]);
  1776. break;
  1777. }
  1778. }
  1779. }
  1780. else
  1781. {
  1782. //we are guaranteed to have a name
  1783. if(0 == wcscmp(pTemplateInfo->pwszName, (rgCertTypeInfo[dwIndex].awszName)[0]))
  1784. {
  1785. pCertType = &(rgCertTypeInfo[dwIndex]);
  1786. break;
  1787. }
  1788. }
  1789. }
  1790. return pCertType;
  1791. }
  1792. //-----------------------------------------------------------------------
  1793. //
  1794. // AEGetDNSNameFromCertificate
  1795. //
  1796. //-----------------------------------------------------------------------
  1797. BOOL AEGetDNSNameFromCertificate(PCCERT_CONTEXT pCertContext,
  1798. LPWSTR *ppwszDnsName)
  1799. {
  1800. BOOL fResult=FALSE;
  1801. PCERT_EXTENSION pExt=NULL;
  1802. DWORD cbData=0;
  1803. DWORD iAltName=0;
  1804. DWORD dwSize=0;
  1805. PCERT_ALT_NAME_INFO pAltName=NULL;
  1806. if((NULL==pCertContext) || (NULL==ppwszDnsName))
  1807. goto Ret;
  1808. *ppwszDnsName=NULL;
  1809. if(NULL == (pExt = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
  1810. pCertContext->pCertInfo->cExtension,
  1811. pCertContext->pCertInfo->rgExtension)))
  1812. goto Ret;
  1813. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1814. szOID_SUBJECT_ALT_NAME2,
  1815. pExt->Value.pbData,
  1816. pExt->Value.cbData,
  1817. 0,
  1818. NULL,
  1819. &cbData))
  1820. goto Ret;
  1821. pAltName=(PCERT_ALT_NAME_INFO)LocalAlloc(LPTR, cbData);
  1822. if(NULL == pAltName)
  1823. goto Ret;
  1824. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1825. szOID_SUBJECT_ALT_NAME2,
  1826. pExt->Value.pbData,
  1827. pExt->Value.cbData,
  1828. 0,
  1829. pAltName,
  1830. &cbData))
  1831. goto Ret;
  1832. //compare the data in the certificate with what is returned from GetComputerNameEx
  1833. for(iAltName=0; iAltName < pAltName->cAltEntry; iAltName++)
  1834. {
  1835. if(CERT_ALT_NAME_DNS_NAME == ((pAltName->rgAltEntry)[iAltName].dwAltNameChoice))
  1836. {
  1837. if(pAltName->rgAltEntry[iAltName].pwszDNSName)
  1838. {
  1839. dwSize=wcslen(pAltName->rgAltEntry[iAltName].pwszDNSName);
  1840. if(0 == dwSize)
  1841. goto Ret;
  1842. *ppwszDnsName=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (dwSize + 1));
  1843. if(NULL == (*ppwszDnsName))
  1844. goto Ret;
  1845. wcscpy(*ppwszDnsName, pAltName->rgAltEntry[iAltName].pwszDNSName);
  1846. fResult=TRUE;
  1847. break;
  1848. }
  1849. }
  1850. }
  1851. Ret:
  1852. if(pAltName)
  1853. LocalFree(pAltName);
  1854. return fResult;
  1855. }
  1856. //-----------------------------------------------------------------------
  1857. //
  1858. // AEIsSameDNS
  1859. //
  1860. //-----------------------------------------------------------------------
  1861. BOOL AEIsSameDNS(PCCERT_CONTEXT pFirstCert, PCCERT_CONTEXT pSecondCert)
  1862. {
  1863. BOOL fSame=FALSE;
  1864. LPWSTR pwszFirst=NULL;
  1865. LPWSTR pwszSecond=NULL;
  1866. AEGetDNSNameFromCertificate(pFirstCert, &pwszFirst);
  1867. AEGetDNSNameFromCertificate(pSecondCert, &pwszSecond);
  1868. if(NULL == pwszFirst)
  1869. {
  1870. if(NULL == pwszSecond)
  1871. {
  1872. fSame=TRUE;
  1873. }
  1874. }
  1875. else
  1876. {
  1877. if(NULL != pwszSecond)
  1878. {
  1879. if(0 == _wcsicmp(pwszFirst, pwszSecond))
  1880. {
  1881. fSame=TRUE;
  1882. }
  1883. }
  1884. }
  1885. if(pwszFirst)
  1886. LocalFree(pwszFirst);
  1887. if(pwszSecond)
  1888. LocalFree(pwszSecond);
  1889. return fSame;
  1890. }
  1891. //-----------------------------------------------------------------------
  1892. //
  1893. // AEGetRetryProperty
  1894. //
  1895. //-----------------------------------------------------------------------
  1896. BOOL AEGetRetryProperty(PCCERT_CONTEXT pCertContext,
  1897. AE_RETRY_INFO **ppAE_Retry_Info)
  1898. {
  1899. BOOL fResult=FALSE;
  1900. DWORD cbData=0;
  1901. AE_RETRY_INFO *pRetry_Info=NULL;
  1902. if((NULL==pCertContext) || (NULL==ppAE_Retry_Info))
  1903. goto Ret;
  1904. *ppAE_Retry_Info=NULL;
  1905. if(!CertGetCertificateContextProperty(
  1906. pCertContext,
  1907. CERT_AUTO_ENROLL_RETRY_PROP_ID,
  1908. NULL,
  1909. &cbData))
  1910. goto Ret;
  1911. pRetry_Info=(AE_RETRY_INFO *)LocalAlloc(LPTR, cbData);
  1912. if(NULL == pRetry_Info)
  1913. goto Ret;
  1914. if(!CertGetCertificateContextProperty(
  1915. pCertContext,
  1916. CERT_AUTO_ENROLL_RETRY_PROP_ID,
  1917. pRetry_Info,
  1918. &cbData))
  1919. goto Ret;
  1920. //verify the integrity of the property on the certificate
  1921. if(cbData < sizeof(AE_RETRY_INFO))
  1922. goto Ret;
  1923. if((pRetry_Info->cbSize) < sizeof(AE_RETRY_INFO))
  1924. goto Ret;
  1925. *ppAE_Retry_Info=pRetry_Info;
  1926. pRetry_Info=NULL;
  1927. fResult=TRUE;
  1928. Ret:
  1929. if(pRetry_Info)
  1930. LocalFree(pRetry_Info);
  1931. return fResult;
  1932. }
  1933. //-----------------------------------------------------------------------
  1934. //
  1935. // AEFasterRetrialSchedule
  1936. //
  1937. // Determine if the 1st certificate context has a faster retrial schedule
  1938. // than the second certifcate based on the CERT_AUTO_ENROLL_RETRY_PROP_ID property
  1939. //
  1940. //-----------------------------------------------------------------------
  1941. BOOL AEFasterRetrialSchedule(PCCERT_CONTEXT pFirstContext,
  1942. PCCERT_CONTEXT pSecondContext)
  1943. {
  1944. BOOL fFaster=FALSE;
  1945. AE_RETRY_INFO *pFirst_Retry=NULL;
  1946. AE_RETRY_INFO *pSecond_Retry=NULL;
  1947. //if the property does not exist, it is always the immediate retrial
  1948. if(!AEGetRetryProperty(pFirstContext, &pFirst_Retry))
  1949. {
  1950. fFaster=TRUE;
  1951. goto Ret;
  1952. }
  1953. //if the property exists on the 1st certificate, but not on the
  1954. //second certificate, the second is always faster
  1955. if(!AEGetRetryProperty(pSecondContext, &pSecond_Retry))
  1956. {
  1957. fFaster=FALSE;
  1958. goto Ret;
  1959. }
  1960. //now both has the property
  1961. //if the second has exceeded the limit, the first is always faster
  1962. if(AE_RETRY_LIMIT < pSecond_Retry->dwRetry)
  1963. {
  1964. fFaster=TRUE;
  1965. goto Ret;
  1966. }
  1967. //the second has not exceeded the limit, while the first has exceeded the limit;
  1968. //the second is faster
  1969. if(AE_RETRY_LIMIT < pFirst_Retry->dwRetry)
  1970. {
  1971. fFaster=FALSE;
  1972. goto Ret;
  1973. }
  1974. //neither has exceeded the limit
  1975. if(pFirst_Retry->dwRetry <= pSecond_Retry->dwRetry)
  1976. {
  1977. fFaster=TRUE;
  1978. }
  1979. else
  1980. {
  1981. fFaster=FALSE;
  1982. }
  1983. Ret:
  1984. if(pFirst_Retry)
  1985. LocalFree(pFirst_Retry);
  1986. if(pSecond_Retry)
  1987. LocalFree(pSecond_Retry);
  1988. return fFaster;
  1989. }
  1990. //-----------------------------------------------------------------------
  1991. //
  1992. // AEUpdateRetryProperty
  1993. //
  1994. // The newly aquired certificate has the same DNS name of the old
  1995. // certificate, and the DNS Name is not the same as the local machine.
  1996. //
  1997. // Update the CERT_AUTO_ENROLL_RETRY_PROP_ID property
  1998. //
  1999. //-----------------------------------------------------------------------
  2000. BOOL AEUpdateRetryProperty(AE_GENERAL_INFO *pAE_General_Info,
  2001. LPWSTR pwszTemplateDisplay,
  2002. PCCERT_CONTEXT pNewContext,
  2003. PCCERT_CONTEXT pOldContext)
  2004. {
  2005. BOOL fResult=FALSE;
  2006. ULARGE_INTEGER ftTime;
  2007. ULONG lSecond=0;
  2008. CRYPT_DATA_BLOB blobProp;
  2009. WCHAR wsz[SHA1_HASH_LENGTH];
  2010. AE_RETRY_INFO *pAE_Retry_Info=NULL;
  2011. if((NULL == pAE_General_Info) || (NULL == pNewContext) || (NULL == pOldContext))
  2012. goto Ret;
  2013. if(!AEGetRetryProperty(pOldContext, &pAE_Retry_Info))
  2014. {
  2015. //make up a default one
  2016. pAE_Retry_Info=(AE_RETRY_INFO *)LocalAlloc(LPTR, sizeof(AE_RETRY_INFO));
  2017. if(NULL == pAE_Retry_Info)
  2018. goto Ret;
  2019. memset(pAE_Retry_Info, 0, sizeof(AE_RETRY_INFO));
  2020. pAE_Retry_Info->cbSize=sizeof(AE_RETRY_INFO);
  2021. pAE_Retry_Info->dwRetry=0; //first attempt
  2022. }
  2023. //increment the count and set the next update date
  2024. if(pAE_Retry_Info->dwRetry <= AE_RETRY_LIMIT)
  2025. {
  2026. (pAE_Retry_Info->dwRetry)++;
  2027. //get the current time
  2028. GetSystemTimeAsFileTime((LPFILETIME)&ftTime);
  2029. // Convert 24 hours to seconds
  2030. lSecond=(pAE_Retry_Info->dwRetry)*24*60*60;
  2031. //lSecond=(pAE_Retry_Info->dwRetry)*2*60;
  2032. ftTime.QuadPart += UInt32x32To64(FILETIME_TICKS_PER_SECOND, lSecond);
  2033. (pAE_Retry_Info->dueTime).QuadPart = ftTime.QuadPart;
  2034. }
  2035. //copy the property on the certificate
  2036. memset(&blobProp, 0, sizeof(CRYPT_DATA_BLOB));
  2037. blobProp.cbData=sizeof(AE_RETRY_INFO);
  2038. blobProp.pbData=(BYTE *)pAE_Retry_Info;
  2039. if(!CertSetCertificateContextProperty(
  2040. pNewContext,
  2041. CERT_AUTO_ENROLL_RETRY_PROP_ID,
  2042. 0,
  2043. &blobProp))
  2044. goto Ret;
  2045. //log the event
  2046. if(pAE_Retry_Info->dwRetry <= AE_RETRY_LIMIT)
  2047. {
  2048. _itow(((pAE_Retry_Info->dwRetry) * 24), wsz, 10);
  2049. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_MISMATCH_DNS_RETRY,
  2050. pAE_General_Info->fMachine, pAE_General_Info->hToken, 2, pwszTemplateDisplay, wsz);
  2051. }
  2052. else
  2053. {
  2054. _itow(AE_RETRY_LIMIT, wsz, 10);
  2055. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_MISMATCH_DNS,
  2056. pAE_General_Info->fMachine, pAE_General_Info->hToken, 2, pwszTemplateDisplay, wsz);
  2057. }
  2058. fResult=TRUE;
  2059. Ret:
  2060. if(pAE_Retry_Info)
  2061. LocalFree(pAE_Retry_Info);
  2062. return fResult;
  2063. }
  2064. //-----------------------------------------------------------------------
  2065. //
  2066. // AEVerifyDNSName
  2067. //
  2068. // Verify the DNS name in the certificate match what is returned
  2069. // from GetComputerNameEx, either ComputerNameDnsFullyQualified or
  2070. // ComputerNameNetBIOS. For V2 template, perform the verification
  2071. // only when the template specify so.
  2072. //
  2073. // By default, we assume the DNS will match. The function will only
  2074. // signal an error if it successfully obtained DNS name from GetComputerNameEx
  2075. // and from the certificate and they do not match.
  2076. //
  2077. //-----------------------------------------------------------------------
  2078. BOOL AEVerifyDNSName(AE_GENERAL_INFO *pAE_General_Info,
  2079. PCCERT_CONTEXT pCertCurrent)
  2080. {
  2081. BOOL fDNSMatch=TRUE;
  2082. AE_CERTTYPE_INFO *pCertType=NULL;
  2083. DWORD dwValue=0;
  2084. BOOL fDnsName=TRUE;
  2085. BOOL fNetBIOS=TRUE;
  2086. LPWSTR pwszDnsName=NULL;
  2087. AE_TEMPLATE_INFO AETemplateInfo;
  2088. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  2089. //find the template that the certificate belongs to
  2090. if(!AERetrieveTemplateInfo(pCertCurrent, &AETemplateInfo))
  2091. goto Ret;
  2092. pCertType=AEFindTemplateInRequestTree(&AETemplateInfo, pAE_General_Info);
  2093. if(NULL==pCertType)
  2094. goto Ret;
  2095. if(S_OK != CAGetCertTypeFlagsEx(
  2096. pCertType->hCertType,
  2097. CERTTYPE_SUBJECT_NAME_FLAG,
  2098. &dwValue))
  2099. goto Ret;
  2100. if((CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT & dwValue) ||
  2101. (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME & dwValue))
  2102. goto Ret;
  2103. //no need to verify non-template certificates or non-DNS specified template
  2104. if(AETemplateInfo.pwszOid)
  2105. {
  2106. if( 0 == (CT_FLAG_SUBJECT_ALT_REQUIRE_DNS & dwValue))
  2107. goto Ret;
  2108. }
  2109. //get the DNS entry from the certificate
  2110. if(!AEGetDNSNameFromCertificate(pCertCurrent, &pwszDnsName))
  2111. {
  2112. fDNSMatch=FALSE;
  2113. goto Ret;
  2114. }
  2115. //compare the data in the certificate with what is returned from GetComputerNameEx
  2116. if(pAE_General_Info->pwszDns)
  2117. {
  2118. if(0 != _wcsicmp(pwszDnsName, pAE_General_Info->pwszDns))
  2119. {
  2120. fDnsName=FALSE;
  2121. }
  2122. }
  2123. if(pAE_General_Info->pwszNetBIOS)
  2124. {
  2125. if(0 != _wcsicmp(pwszDnsName, pAE_General_Info->pwszNetBIOS))
  2126. {
  2127. fNetBIOS=FALSE;
  2128. }
  2129. }
  2130. //either DNS or NetBIOS name should match
  2131. if((FALSE == fDnsName) && (FALSE == fNetBIOS))
  2132. {
  2133. fDNSMatch=FALSE;
  2134. }
  2135. Ret:
  2136. if(pwszDnsName)
  2137. LocalFree(pwszDnsName);
  2138. AEFreeTemplateInfo(&AETemplateInfo);
  2139. return fDNSMatch;
  2140. }
  2141. //-----------------------------------------------------------------------
  2142. //
  2143. // AEVerifyDNSNameWithRetry
  2144. ////
  2145. //-----------------------------------------------------------------------
  2146. BOOL AEVerifyDNSNameWithRetry(AE_GENERAL_INFO *pAE_General_Info,
  2147. PCCERT_CONTEXT pCertCurrent)
  2148. {
  2149. BOOL fResult=FALSE;
  2150. ULARGE_INTEGER ftTime;
  2151. AE_RETRY_INFO *pAE_Retry_Info=NULL;
  2152. //detect if DNS name in the certificate matches the local machine
  2153. //Success means no need to re-enroll
  2154. if(TRUE == AEVerifyDNSName(pAE_General_Info, pCertCurrent))
  2155. {
  2156. fResult=TRUE;
  2157. goto Ret;
  2158. }
  2159. //now that the DNS name does not match, check the CERT_AUTO_ENROLL_RETRY_PROP_ID
  2160. //property on the pCertCurrent to determine the correct action
  2161. //property does not exit. Allow for re-enrollment by marking a failure
  2162. if(!AEGetRetryProperty(pCertCurrent, &pAE_Retry_Info))
  2163. {
  2164. fResult=FALSE;
  2165. goto Ret;
  2166. }
  2167. //property exit
  2168. //the Maximum # of trial has reached. Disallow for re-enrollment by returning a success
  2169. if(AE_RETRY_LIMIT < pAE_Retry_Info->dwRetry)
  2170. {
  2171. fResult=TRUE;
  2172. goto Ret;
  2173. }
  2174. //get the current time
  2175. GetSystemTimeAsFileTime((LPFILETIME)&ftTime);
  2176. //the time limit has not reached. Disallow for re-enrollment by returning a success
  2177. if(ftTime.QuadPart < (pAE_Retry_Info->dueTime).QuadPart)
  2178. {
  2179. fResult=TRUE;
  2180. goto Ret;
  2181. }
  2182. //the rest should be re-enrolled by returning a failure
  2183. fResult=FALSE;
  2184. Ret:
  2185. if(pAE_Retry_Info)
  2186. LocalFree(pAE_Retry_Info);
  2187. return fResult;
  2188. }
  2189. //-----------------------------------------------------------------------
  2190. //
  2191. // AEIsLogonDCCertificate
  2192. //
  2193. //
  2194. //-----------------------------------------------------------------------
  2195. BOOL AEIsLogonDCCertificate(PCCERT_CONTEXT pCertContext)
  2196. {
  2197. BOOL fDCCert=FALSE;
  2198. PCERT_EXTENSION pExt = NULL;
  2199. DWORD cbData = 0;
  2200. DWORD dwIndex = 0;
  2201. BOOL fFound = FALSE;
  2202. CERT_ENHKEY_USAGE *pbKeyUsage=NULL;
  2203. AE_TEMPLATE_INFO AETemplateInfo;
  2204. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  2205. if(NULL==pCertContext)
  2206. return FALSE;
  2207. if(!AERetrieveTemplateInfo(pCertContext, &AETemplateInfo))
  2208. goto Ret;
  2209. if(AETemplateInfo.pwszName)
  2210. {
  2211. //this is a V1 template. Search for the hard coded DC template name
  2212. if(0 == _wcsicmp(wszCERTTYPE_DC, AETemplateInfo.pwszName))
  2213. fDCCert=TRUE;
  2214. }
  2215. else
  2216. {
  2217. //this is a V2 template. Search for the smart card logon OID
  2218. if(NULL==(pExt=CertFindExtension(szOID_ENHANCED_KEY_USAGE,
  2219. pCertContext->pCertInfo->cExtension,
  2220. pCertContext->pCertInfo->rgExtension)))
  2221. goto Ret;
  2222. if(!CryptDecodeObject(X509_ASN_ENCODING,
  2223. szOID_ENHANCED_KEY_USAGE,
  2224. pExt->Value.pbData,
  2225. pExt->Value.cbData,
  2226. 0,
  2227. NULL,
  2228. &cbData))
  2229. goto Ret;
  2230. pbKeyUsage=(CERT_ENHKEY_USAGE *)LocalAlloc(LPTR, cbData);
  2231. if(NULL==pbKeyUsage)
  2232. goto Ret;
  2233. if(!CryptDecodeObject(X509_ASN_ENCODING,
  2234. szOID_ENHANCED_KEY_USAGE,
  2235. pExt->Value.pbData,
  2236. pExt->Value.cbData,
  2237. 0,
  2238. pbKeyUsage,
  2239. &cbData))
  2240. goto Ret;
  2241. for(dwIndex=0; dwIndex < pbKeyUsage->cUsageIdentifier; dwIndex++)
  2242. {
  2243. if(0==_stricmp(szOID_KP_SMARTCARD_LOGON,(pbKeyUsage->rgpszUsageIdentifier)[dwIndex]))
  2244. {
  2245. fDCCert=TRUE;
  2246. break;
  2247. }
  2248. }
  2249. }
  2250. Ret:
  2251. if(pbKeyUsage)
  2252. LocalFree(pbKeyUsage);
  2253. AEFreeTemplateInfo(&AETemplateInfo);
  2254. return fDCCert;
  2255. }
  2256. //-----------------------------------------------------------------------
  2257. //
  2258. // AEValidateCertificateInfo
  2259. //
  2260. // This function verifies if the certificate needs to be renewed or
  2261. // re-enrolled based on:
  2262. //
  2263. // 1. Presence of the private key
  2264. // 2. Chaining of the certificate
  2265. // 3. If the certificate is close to expiration
  2266. //
  2267. //-----------------------------------------------------------------------
  2268. BOOL AEValidateCertificateInfo(AE_GENERAL_INFO *pAE_General_Info,
  2269. AE_CERTTYPE_INFO *pCertType,
  2270. BOOL fCheckForPrivateKey,
  2271. PCCERT_CONTEXT pCertCurrent,
  2272. AE_CERT_INFO *pAECertInfo)
  2273. {
  2274. BOOL fResult = TRUE;
  2275. DWORD cbData = 0;
  2276. CERT_CHAIN_PARA ChainParams;
  2277. CERT_CHAIN_POLICY_PARA ChainPolicy;
  2278. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  2279. LARGE_INTEGER ftTime;
  2280. HRESULT hrChainStatus = S_OK;
  2281. LARGE_INTEGER ftHalfLife;
  2282. BOOL fReset=FALSE;
  2283. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  2284. if((NULL==pCertCurrent) || (NULL==pAECertInfo) || (NULL==pAE_General_Info))
  2285. {
  2286. SetLastError(E_INVALIDARG);
  2287. fResult = FALSE;
  2288. goto Ret;
  2289. }
  2290. //assume the certificate is bad
  2291. pAECertInfo->fValid = FALSE;
  2292. pAECertInfo->fRenewal = FALSE;
  2293. //////////////////////////////////////////////////
  2294. //
  2295. //check for the private key information
  2296. //
  2297. //////////////////////////////////////////////////
  2298. if(fCheckForPrivateKey)
  2299. {
  2300. if(!CertGetCertificateContextProperty(
  2301. pCertCurrent,
  2302. CERT_KEY_PROV_INFO_PROP_ID,
  2303. NULL,
  2304. &cbData))
  2305. {
  2306. fReset=TRUE;
  2307. goto Ret;
  2308. }
  2309. }
  2310. /////////////////////////////////////////////////////////
  2311. //
  2312. //check for chaining, revoke status and expiration of the certificate
  2313. //
  2314. /////////////////////////////////////////////////////////
  2315. memset(&ChainParams, 0, sizeof(ChainParams));
  2316. ChainParams.cbSize = sizeof(ChainParams);
  2317. ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  2318. ChainParams.RequestedUsage.Usage.cUsageIdentifier = 0;
  2319. ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
  2320. // Build a small time skew into the chain building in order to deal
  2321. // with servers that may skew slightly fast.
  2322. GetSystemTimeAsFileTime((LPFILETIME)&ftTime);
  2323. ftTime.QuadPart += Int32x32To64(FILETIME_TICKS_PER_SECOND, AE_DEFAULT_SKEW);
  2324. // Build a cert chain for the current status of the cert..
  2325. if(!CertGetCertificateChain(pAE_General_Info->fMachine?HCCE_LOCAL_MACHINE:HCCE_CURRENT_USER,
  2326. pCertCurrent,
  2327. (LPFILETIME)&ftTime,
  2328. NULL,
  2329. &ChainParams,
  2330. CERT_CHAIN_REVOCATION_CHECK_CHAIN,
  2331. NULL,
  2332. &pChainContext))
  2333. {
  2334. AE_DEBUG((AE_WARNING, L"Could not build certificate chain (%lx)\n\r", GetLastError()));
  2335. goto Ret;
  2336. }
  2337. //validate the certificate chain
  2338. //special case for domain controller certificate.
  2339. //it should not have any revocation error, even for status unknown case
  2340. //check against the base policy
  2341. memset(&ChainPolicy, 0, sizeof(ChainPolicy));
  2342. ChainPolicy.cbSize = sizeof(ChainPolicy);
  2343. ChainPolicy.dwFlags = 0; // ignore nothing
  2344. ChainPolicy.pvExtraPolicyPara = NULL;
  2345. memset(&PolicyStatus, 0, sizeof(PolicyStatus));
  2346. PolicyStatus.cbSize = sizeof(PolicyStatus);
  2347. PolicyStatus.dwError = 0;
  2348. PolicyStatus.lChainIndex = -1;
  2349. PolicyStatus.lElementIndex = -1;
  2350. PolicyStatus.pvExtraPolicyStatus = NULL;
  2351. if(!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
  2352. pChainContext,
  2353. &ChainPolicy,
  2354. &PolicyStatus))
  2355. {
  2356. AE_DEBUG((AE_WARNING, L"Base Chain Policy failed (%lx) - must get new cert\n\r", GetLastError()));
  2357. goto Ret;
  2358. }
  2359. hrChainStatus = PolicyStatus.dwError;
  2360. if((S_OK == hrChainStatus) ||
  2361. (CRYPT_E_NO_REVOCATION_CHECK == hrChainStatus) ||
  2362. (CRYPT_E_REVOCATION_OFFLINE == hrChainStatus))
  2363. {
  2364. // The cert is still currently acceptable by trust standards, so we can renew it
  2365. pAECertInfo->fRenewal = TRUE;
  2366. }
  2367. else
  2368. {
  2369. fReset=TRUE;
  2370. goto Ret;
  2371. }
  2372. if(pChainContext)
  2373. {
  2374. CertFreeCertificateChain(pChainContext);
  2375. pChainContext = NULL;
  2376. }
  2377. /////////////////////////////////////////////////////////
  2378. //
  2379. //check the DNS name in the machine certificate. It has
  2380. //to match with the computer's DNS name
  2381. //
  2382. /////////////////////////////////////////////////////////
  2383. if(pAE_General_Info->fMachine)
  2384. {
  2385. if(!AEVerifyDNSNameWithRetry(pAE_General_Info, pCertCurrent))
  2386. {
  2387. pAECertInfo->fRenewal = FALSE;
  2388. goto Ret;
  2389. }
  2390. }
  2391. /////////////////////////////////////////////////////////
  2392. //
  2393. // Check if the certificate is close to expire
  2394. //
  2395. ///////////////////////////////////////////////////////////////////////
  2396. if(NULL==pCertType)
  2397. goto Ret;
  2398. // Nudge the evaluation of the cert chain by the expiration
  2399. // offset so we know if is expired by that time in the future.
  2400. GetSystemTimeAsFileTime((LPFILETIME)&ftTime);
  2401. // Build the certificate chain for trust operations
  2402. memset(&ChainParams, 0, sizeof(ChainParams));
  2403. ChainParams.cbSize = sizeof(ChainParams);
  2404. ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  2405. ChainParams.RequestedUsage.Usage.cUsageIdentifier = 0;
  2406. ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
  2407. //get the 80% lifetime of the certificate
  2408. ftHalfLife.QuadPart = ((((LARGE_INTEGER UNALIGNED *)&(pCertCurrent->pCertInfo->NotAfter))->QuadPart -
  2409. ((LARGE_INTEGER UNALIGNED *)&(pCertCurrent->pCertInfo->NotBefore))->QuadPart)/10) * 8;
  2410. //check if the old cert is time nesting invalid
  2411. if(ftHalfLife.QuadPart < 0)
  2412. goto Ret;
  2413. //check if the offset was specified in a relative value
  2414. if(pCertType->ftExpirationOffset.QuadPart < 0)
  2415. {
  2416. if(ftHalfLife.QuadPart > (- pCertType->ftExpirationOffset.QuadPart))
  2417. {
  2418. ftTime.QuadPart -= pCertType->ftExpirationOffset.QuadPart;
  2419. }
  2420. else
  2421. {
  2422. ftTime.QuadPart += ftHalfLife.QuadPart;
  2423. }
  2424. }
  2425. else
  2426. {
  2427. //the offset was specified in an absolute value
  2428. if(0 < pCertType->ftExpirationOffset.QuadPart)
  2429. ftTime = pCertType->ftExpirationOffset;
  2430. else
  2431. //use the half time mark if the offset is 0
  2432. ftTime.QuadPart += ftHalfLife.QuadPart;
  2433. }
  2434. //check the certificate chain at a future time
  2435. if(!CertGetCertificateChain(pAE_General_Info->fMachine?HCCE_LOCAL_MACHINE:HCCE_CURRENT_USER,
  2436. pCertCurrent,
  2437. (LPFILETIME)&ftTime,
  2438. NULL, //no additional store
  2439. &ChainParams,
  2440. 0, //no revocation check
  2441. NULL, //Reserved
  2442. &pChainContext))
  2443. {
  2444. AE_DEBUG((AE_WARNING, L"Could not build certificate chain (%lx)\n\r", GetLastError()));
  2445. goto Ret;
  2446. }
  2447. // Verify expiration of the certificate
  2448. memset(&ChainPolicy, 0, sizeof(ChainPolicy));
  2449. ChainPolicy.cbSize = sizeof(ChainPolicy);
  2450. ChainPolicy.dwFlags = 0; // ignore nothing
  2451. ChainPolicy.pvExtraPolicyPara = NULL;
  2452. memset(&PolicyStatus, 0, sizeof(PolicyStatus));
  2453. PolicyStatus.cbSize = sizeof(PolicyStatus);
  2454. PolicyStatus.dwError = 0;
  2455. PolicyStatus.lChainIndex = -1;
  2456. PolicyStatus.lElementIndex = -1;
  2457. PolicyStatus.pvExtraPolicyStatus = NULL;
  2458. if(!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
  2459. pChainContext,
  2460. &ChainPolicy,
  2461. &PolicyStatus))
  2462. {
  2463. AE_DEBUG((AE_WARNING, L"Base Chain Policy failed (%lx) - must get new cert\n\r", GetLastError()));
  2464. goto Ret;
  2465. }
  2466. hrChainStatus = PolicyStatus.dwError;
  2467. if((S_OK != hrChainStatus) &&
  2468. (CRYPT_E_NO_REVOCATION_CHECK != hrChainStatus) &&
  2469. (CRYPT_E_REVOCATION_OFFLINE != hrChainStatus))
  2470. {
  2471. // The cert is close to expire. we must re-renewal
  2472. goto Ret;
  2473. }
  2474. //the certificate is good
  2475. pAECertInfo->fValid = TRUE;
  2476. fResult = TRUE;
  2477. Ret:
  2478. if(pAE_General_Info->fMachine)
  2479. {
  2480. if(TRUE == fReset)
  2481. {
  2482. //clear out the retry logic
  2483. CertSetCertificateContextProperty(
  2484. pCertCurrent,
  2485. CERT_AUTO_ENROLL_RETRY_PROP_ID,
  2486. 0,
  2487. NULL);
  2488. }
  2489. }
  2490. if(pChainContext)
  2491. CertFreeCertificateChain(pChainContext);
  2492. return fResult;
  2493. }
  2494. //-----------------------------------------------------------------------
  2495. //
  2496. // AESameOID
  2497. //
  2498. // Check if the two OIDs are the same
  2499. //-----------------------------------------------------------------------
  2500. BOOL AESameOID(LPWSTR pwszOID, LPSTR pszOID)
  2501. {
  2502. DWORD cbChar=0;
  2503. BOOL fSame=FALSE;
  2504. LPSTR pszNewOID=NULL;
  2505. if((NULL==pwszOID) || (NULL==pszOID))
  2506. return FALSE;
  2507. cbChar= WideCharToMultiByte(
  2508. CP_ACP, // codepage
  2509. 0, // dwFlags
  2510. pwszOID,
  2511. -1,
  2512. NULL,
  2513. 0,
  2514. NULL,
  2515. NULL);
  2516. if(0 == cbChar)
  2517. goto Ret;
  2518. if(NULL==(pszNewOID=(LPSTR)LocalAlloc(LPTR, cbChar)))
  2519. goto Ret;
  2520. cbChar= WideCharToMultiByte(
  2521. CP_ACP, // codepage
  2522. 0, // dwFlags
  2523. pwszOID,
  2524. -1,
  2525. pszNewOID,
  2526. cbChar,
  2527. NULL,
  2528. NULL);
  2529. if(0 == cbChar)
  2530. goto Ret;
  2531. if(0 == _stricmp(pszNewOID, pszOID))
  2532. fSame=TRUE;
  2533. Ret:
  2534. if(pszNewOID)
  2535. LocalFree(pszNewOID);
  2536. return fSame;
  2537. }
  2538. //-----------------------------------------------------------------------
  2539. //
  2540. // AEValidRAPolicyWithProperty
  2541. //
  2542. // Check if the certificate matches the RA signature requirement
  2543. // of the certificate type
  2544. //-----------------------------------------------------------------------
  2545. BOOL AEValidRAPolicyWithProperty(PCCERT_CONTEXT pCertContext,
  2546. LPWSTR *rgwszPolicy,
  2547. LPWSTR *rgwszAppPolicy)
  2548. {
  2549. PCERT_EXTENSION pExt = NULL;
  2550. DWORD cbData = 0;
  2551. DWORD dwIndex = 0;
  2552. DWORD dwFindIndex=0;
  2553. BOOL fFound = FALSE;
  2554. BOOL fValid = FALSE;
  2555. CERT_ENHKEY_USAGE *pbKeyUsage=NULL;
  2556. CERT_POLICIES_INFO *pbAppPolicy=NULL;
  2557. CERT_POLICIES_INFO *pbPolicy=NULL;
  2558. //find the EKUs
  2559. if(pExt=CertFindExtension(szOID_ENHANCED_KEY_USAGE,
  2560. pCertContext->pCertInfo->cExtension,
  2561. pCertContext->pCertInfo->rgExtension))
  2562. {
  2563. cbData=0;
  2564. if(!CryptDecodeObject(X509_ASN_ENCODING,
  2565. szOID_ENHANCED_KEY_USAGE,
  2566. pExt->Value.pbData,
  2567. pExt->Value.cbData,
  2568. 0,
  2569. NULL,
  2570. &cbData))
  2571. goto Ret;
  2572. pbKeyUsage=(CERT_ENHKEY_USAGE *)LocalAlloc(LPTR, cbData);
  2573. if(NULL==pbKeyUsage)
  2574. goto Ret;
  2575. if(!CryptDecodeObject(X509_ASN_ENCODING,
  2576. szOID_ENHANCED_KEY_USAGE,
  2577. pExt->Value.pbData,
  2578. pExt->Value.cbData,
  2579. 0,
  2580. pbKeyUsage,
  2581. &cbData))
  2582. goto Ret;
  2583. }
  2584. //get the cert issurance policy
  2585. if(pExt=CertFindExtension(szOID_CERT_POLICIES,
  2586. pCertContext->pCertInfo->cExtension,
  2587. pCertContext->pCertInfo->rgExtension))
  2588. {
  2589. cbData=0;
  2590. if(!CryptDecodeObject(X509_ASN_ENCODING,
  2591. szOID_CERT_POLICIES,
  2592. pExt->Value.pbData,
  2593. pExt->Value.cbData,
  2594. 0,
  2595. NULL,
  2596. &cbData))
  2597. goto Ret;
  2598. pbPolicy=(CERT_POLICIES_INFO *)LocalAlloc(LPTR, cbData);
  2599. if(NULL==pbPolicy)
  2600. goto Ret;
  2601. if(!CryptDecodeObject(X509_ASN_ENCODING,
  2602. szOID_CERT_POLICIES,
  2603. pExt->Value.pbData,
  2604. pExt->Value.cbData,
  2605. 0,
  2606. pbPolicy,
  2607. &cbData))
  2608. goto Ret;
  2609. }
  2610. //get the cert application policy
  2611. if(pExt=CertFindExtension(szOID_APPLICATION_CERT_POLICIES,
  2612. pCertContext->pCertInfo->cExtension,
  2613. pCertContext->pCertInfo->rgExtension))
  2614. {
  2615. cbData=0;
  2616. if(!CryptDecodeObject(X509_ASN_ENCODING,
  2617. szOID_CERT_POLICIES,
  2618. pExt->Value.pbData,
  2619. pExt->Value.cbData,
  2620. 0,
  2621. NULL,
  2622. &cbData))
  2623. goto Ret;
  2624. pbAppPolicy=(CERT_POLICIES_INFO *)LocalAlloc(LPTR, cbData);
  2625. if(NULL==pbAppPolicy)
  2626. goto Ret;
  2627. if(!CryptDecodeObject(X509_ASN_ENCODING,
  2628. szOID_CERT_POLICIES,
  2629. pExt->Value.pbData,
  2630. pExt->Value.cbData,
  2631. 0,
  2632. pbAppPolicy,
  2633. &cbData))
  2634. goto Ret;
  2635. }
  2636. if(rgwszPolicy)
  2637. {
  2638. if(rgwszPolicy[0])
  2639. {
  2640. if(NULL==pbPolicy)
  2641. goto Ret;
  2642. dwIndex=0;
  2643. while(rgwszPolicy[dwIndex])
  2644. {
  2645. fFound=FALSE;
  2646. for(dwFindIndex=0; dwFindIndex < pbPolicy->cPolicyInfo; dwFindIndex++)
  2647. {
  2648. if(AESameOID(rgwszPolicy[dwIndex], (pbPolicy->rgPolicyInfo)[dwFindIndex].pszPolicyIdentifier))
  2649. {
  2650. fFound=TRUE;
  2651. break;
  2652. }
  2653. }
  2654. if(FALSE == fFound)
  2655. goto Ret;
  2656. dwIndex++;
  2657. }
  2658. }
  2659. }
  2660. if(rgwszAppPolicy)
  2661. {
  2662. if(rgwszAppPolicy[0])
  2663. {
  2664. if((NULL==pbAppPolicy) && (NULL==pbKeyUsage))
  2665. goto Ret;
  2666. dwIndex=0;
  2667. while(rgwszAppPolicy[dwIndex])
  2668. {
  2669. fFound=FALSE;
  2670. if(pbAppPolicy)
  2671. {
  2672. for(dwFindIndex=0; dwFindIndex < pbAppPolicy->cPolicyInfo; dwFindIndex++)
  2673. {
  2674. if(AESameOID(rgwszAppPolicy[dwIndex], (pbAppPolicy->rgPolicyInfo)[dwFindIndex].pszPolicyIdentifier))
  2675. {
  2676. fFound=TRUE;
  2677. break;
  2678. }
  2679. }
  2680. }
  2681. if((FALSE == fFound) && (pbKeyUsage))
  2682. {
  2683. for(dwFindIndex=0; dwFindIndex < pbKeyUsage->cUsageIdentifier; dwFindIndex++)
  2684. {
  2685. if(AESameOID(rgwszAppPolicy[dwIndex],(pbKeyUsage->rgpszUsageIdentifier)[dwFindIndex]))
  2686. {
  2687. fFound=TRUE;
  2688. break;
  2689. }
  2690. }
  2691. }
  2692. if(FALSE == fFound)
  2693. goto Ret;
  2694. dwIndex++;
  2695. }
  2696. }
  2697. }
  2698. fValid=TRUE;
  2699. Ret:
  2700. if(pbKeyUsage)
  2701. LocalFree(pbKeyUsage);
  2702. if(pbPolicy)
  2703. LocalFree(pbPolicy);
  2704. if(pbAppPolicy)
  2705. LocalFree(pbAppPolicy);
  2706. return fValid;
  2707. }
  2708. //-----------------------------------------------------------------------
  2709. //
  2710. // AEValidRAPolicy
  2711. //
  2712. // Check if the certificate matches the RA signature requirement
  2713. // of the certificate type
  2714. //-----------------------------------------------------------------------
  2715. BOOL AEValidRAPolicy(PCCERT_CONTEXT pCertContext, AE_CERTTYPE_INFO *pCertType)
  2716. {
  2717. BOOL fValid=FALSE;
  2718. LPWSTR *rgwszPolicy=NULL;
  2719. LPWSTR *rgwszAppPolicy=NULL;
  2720. if((NULL==pCertType) || (NULL==pCertContext))
  2721. return FALSE;
  2722. //get the certificate type properties
  2723. CAGetCertTypePropertyEx(pCertType->hCertType,
  2724. CERTTYPE_PROP_RA_POLICY,
  2725. &rgwszPolicy);
  2726. CAGetCertTypePropertyEx(pCertType->hCertType,
  2727. CERTTYPE_PROP_RA_APPLICATION_POLICY,
  2728. &rgwszAppPolicy);
  2729. fValid = AEValidRAPolicyWithProperty(pCertContext, rgwszPolicy, rgwszAppPolicy);
  2730. if(rgwszPolicy)
  2731. CAFreeCertTypeProperty(pCertType->hCertType, rgwszPolicy);
  2732. if(rgwszAppPolicy)
  2733. CAFreeCertTypeProperty(pCertType->hCertType, rgwszAppPolicy);
  2734. return fValid;
  2735. }
  2736. //-----------------------------------------------------------------------
  2737. //
  2738. // AESomeCSPSupported
  2739. //
  2740. //-----------------------------------------------------------------------
  2741. BOOL AESomeCSPSupported(HCERTTYPE hCertType)
  2742. {
  2743. BOOL fResult=FALSE;
  2744. DWORD dwIndex=0;
  2745. DWORD dwCSPIndex=0;
  2746. DWORD dwProviderType=0;
  2747. DWORD cbSize=0;
  2748. LPWSTR *awszCSP=NULL;
  2749. LPWSTR pwszProviderName=NULL;
  2750. HCRYPTPROV hProv=NULL;
  2751. if(NULL==hCertType)
  2752. goto Ret;
  2753. //no CSPs means all CSPs are fine
  2754. if((S_OK != CAGetCertTypePropertyEx(
  2755. hCertType,
  2756. CERTTYPE_PROP_CSP_LIST,
  2757. &awszCSP)) || (NULL == awszCSP))
  2758. {
  2759. fResult=TRUE;
  2760. goto Ret;
  2761. }
  2762. //no CSP means all CSPs are fine
  2763. if(NULL == awszCSP[0])
  2764. {
  2765. fResult=TRUE;
  2766. goto Ret;
  2767. }
  2768. for(dwIndex=0; NULL != awszCSP[dwIndex]; dwIndex++)
  2769. {
  2770. for (dwCSPIndex = 0;
  2771. CryptEnumProvidersW(dwCSPIndex, 0, 0, &dwProviderType, NULL, &cbSize);
  2772. dwCSPIndex++)
  2773. {
  2774. pwszProviderName = (LPWSTR)LocalAlloc(LPTR, cbSize);
  2775. if(NULL == pwszProviderName)
  2776. goto Ret;
  2777. //get the provider name and type
  2778. if(!CryptEnumProvidersW(dwCSPIndex,
  2779. 0,
  2780. 0,
  2781. &dwProviderType,
  2782. pwszProviderName,
  2783. &cbSize))
  2784. goto Ret;
  2785. if(0 == _wcsicmp(pwszProviderName, awszCSP[dwIndex]))
  2786. {
  2787. //find the CSP. See if it is present in the box
  2788. if(CryptAcquireContextW(
  2789. &hProv,
  2790. NULL,
  2791. awszCSP[dwIndex],
  2792. dwProviderType,
  2793. CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
  2794. {
  2795. CryptReleaseContext(hProv, 0);
  2796. hProv=NULL;
  2797. fResult=TRUE;
  2798. break;
  2799. }
  2800. }
  2801. //keep the CSP enumeration
  2802. if(pwszProviderName)
  2803. LocalFree(pwszProviderName);
  2804. pwszProviderName=NULL;
  2805. cbSize=0;
  2806. dwProviderType=0;
  2807. }
  2808. //detect if a valid CSP if found
  2809. if(TRUE == fResult)
  2810. {
  2811. break;
  2812. }
  2813. cbSize=0;
  2814. dwProviderType=0;
  2815. }
  2816. Ret:
  2817. if(pwszProviderName)
  2818. LocalFree(pwszProviderName);
  2819. if(hProv)
  2820. CryptReleaseContext(hProv, 0);
  2821. if(awszCSP)
  2822. CAFreeCertTypeProperty(hCertType, awszCSP);
  2823. return fResult;
  2824. }
  2825. //-----------------------------------------------------------------------
  2826. //
  2827. // AEFindCSPType
  2828. //
  2829. //-----------------------------------------------------------------------
  2830. BOOL AEFindCSPType(LPWSTR pwszCSP, DWORD *pdwType)
  2831. {
  2832. BOOL fResult=FALSE;
  2833. DWORD dwIndex=0;
  2834. DWORD dwProviderType=0;
  2835. DWORD cbSize=0;
  2836. LPWSTR pwszCSPName=NULL;
  2837. if((NULL==pwszCSP) || (NULL==pdwType))
  2838. goto Ret;
  2839. *pdwType=0;
  2840. //enum all the providers on the system
  2841. while(CryptEnumProviders(
  2842. dwIndex,
  2843. 0,
  2844. 0,
  2845. &dwProviderType,
  2846. NULL,
  2847. &cbSize))
  2848. {
  2849. pwszCSPName=(LPWSTR)LocalAlloc(LPTR, cbSize);
  2850. if(NULL==pwszCSPName)
  2851. goto Ret;
  2852. //get the CSP name and the type
  2853. if(!CryptEnumProviders(
  2854. dwIndex,
  2855. 0,
  2856. 0,
  2857. &dwProviderType,
  2858. pwszCSPName,
  2859. &cbSize))
  2860. goto Ret;
  2861. if(0 == _wcsicmp(pwszCSPName, pwszCSP))
  2862. {
  2863. //find the CSP
  2864. *pdwType=dwProviderType;
  2865. fResult=TRUE;
  2866. goto Ret;
  2867. }
  2868. dwIndex++;
  2869. dwProviderType=0;
  2870. cbSize=0;
  2871. if(pwszCSPName)
  2872. {
  2873. LocalFree(pwszCSPName);
  2874. pwszCSPName=NULL;
  2875. }
  2876. }
  2877. Ret:
  2878. if(pwszCSPName)
  2879. LocalFree(pwszCSPName);
  2880. return fResult;
  2881. }
  2882. //-----------------------------------------------------------------------
  2883. //
  2884. // AESmartcardOnlyTemplate
  2885. //
  2886. //-----------------------------------------------------------------------
  2887. BOOL AESmartcardOnlyTemplate(HCERTTYPE hCertType)
  2888. {
  2889. BOOL fResult=FALSE;
  2890. DWORD dwIndex=0;
  2891. DWORD dwImpType=0;
  2892. DWORD cbData=0;
  2893. DWORD dwSCCount=0;
  2894. DWORD dwCSPType=0;
  2895. LPWSTR *awszCSP=NULL;
  2896. HCRYPTPROV hProv = NULL;
  2897. if(NULL==hCertType)
  2898. goto Ret;
  2899. if(S_OK != CAGetCertTypePropertyEx(
  2900. hCertType,
  2901. CERTTYPE_PROP_CSP_LIST,
  2902. &awszCSP))
  2903. goto Ret;
  2904. if(NULL==awszCSP)
  2905. goto Ret;
  2906. for(dwIndex=0; NULL != awszCSP[dwIndex]; dwIndex++)
  2907. {
  2908. dwImpType=0;
  2909. dwCSPType=0;
  2910. //find the CSP type based on the CSP name
  2911. if(AEFindCSPType(awszCSP[dwIndex], &dwCSPType))
  2912. {
  2913. if(CryptAcquireContextW(
  2914. &hProv,
  2915. NULL,
  2916. awszCSP[dwIndex],
  2917. dwCSPType,
  2918. CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
  2919. {
  2920. cbData = sizeof(dwImpType);
  2921. if(CryptGetProvParam(hProv,
  2922. PP_IMPTYPE,
  2923. (BYTE *)(&dwImpType),
  2924. &cbData,
  2925. 0))
  2926. {
  2927. if((CRYPT_IMPL_REMOVABLE & dwImpType) && (CRYPT_IMPL_MIXED & dwImpType))
  2928. dwSCCount++;
  2929. }
  2930. CryptReleaseContext(hProv, 0);
  2931. hProv=NULL;
  2932. }
  2933. else
  2934. {
  2935. //not supported CSP. Count it as part of the SmartCard CSP count since this
  2936. //CSP will not work when the smart card subsystem is not present
  2937. dwSCCount++;
  2938. }
  2939. }
  2940. else
  2941. {
  2942. //not supported CSP. Count it as part of the SmartCard CSP count since this
  2943. //CSP will not work when the smart card subsystem is not present
  2944. dwSCCount++;
  2945. }
  2946. }
  2947. //smart card CSP only if all CSPs are for smart card only
  2948. if((0 != dwIndex) && (dwIndex==dwSCCount))
  2949. fResult=TRUE;
  2950. Ret:
  2951. if(hProv)
  2952. CryptReleaseContext(hProv, 0);
  2953. if(awszCSP)
  2954. CAFreeCertTypeProperty(hCertType, awszCSP);
  2955. return fResult;
  2956. }
  2957. //-----------------------------------------------------------------------
  2958. //
  2959. // AEUserProtectionForTemplate
  2960. //
  2961. //-----------------------------------------------------------------------
  2962. BOOL AEUserProtectionForTemplate(AE_GENERAL_INFO *pAE_General_Info, PCERT_CONTEXT pCertContext)
  2963. {
  2964. BOOL fUserProtection=FALSE;
  2965. AE_CERTTYPE_INFO *pCertType=NULL;
  2966. AE_TEMPLATE_INFO AETemplateInfo;
  2967. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  2968. if((NULL == pAE_General_Info) || (NULL == pCertContext))
  2969. goto Ret;
  2970. //get the template information for the certificate
  2971. if(!AERetrieveTemplateInfo(pCertContext, &AETemplateInfo))
  2972. goto Ret;
  2973. pCertType=AEFindTemplateInRequestTree(&AETemplateInfo, pAE_General_Info);
  2974. if(NULL==pCertType)
  2975. goto Ret;
  2976. if(CT_FLAG_STRONG_KEY_PROTECTION_REQUIRED & (pCertType->dwPrivateKeyFlag))
  2977. fUserProtection=TRUE;
  2978. Ret:
  2979. AEFreeTemplateInfo(&AETemplateInfo);
  2980. return fUserProtection;
  2981. }
  2982. //-----------------------------------------------------------------------
  2983. //
  2984. // AEUISetForTemplate
  2985. //
  2986. //-----------------------------------------------------------------------
  2987. BOOL AEUISetForTemplate(AE_GENERAL_INFO *pAE_General_Info, PCERT_CONTEXT pCertContext)
  2988. {
  2989. BOOL fUI=FALSE;
  2990. AE_CERTTYPE_INFO *pCertType=NULL;
  2991. AE_TEMPLATE_INFO AETemplateInfo;
  2992. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  2993. if((NULL == pAE_General_Info) || (NULL == pCertContext))
  2994. goto Ret;
  2995. //get the template information for the certificate
  2996. if(!AERetrieveTemplateInfo(pCertContext, &AETemplateInfo))
  2997. goto Ret;
  2998. pCertType=AEFindTemplateInRequestTree(&AETemplateInfo, pAE_General_Info);
  2999. if(NULL==pCertType)
  3000. goto Ret;
  3001. if(CT_FLAG_USER_INTERACTION_REQUIRED & (pCertType->dwEnrollmentFlag))
  3002. fUI=TRUE;
  3003. Ret:
  3004. AEFreeTemplateInfo(&AETemplateInfo);
  3005. return fUI;
  3006. }
  3007. //-----------------------------------------------------------------------
  3008. //
  3009. // AECanEnrollCertType
  3010. //
  3011. //-----------------------------------------------------------------------
  3012. BOOL AECanEnrollCertType(HANDLE hToken, AE_CERTTYPE_INFO *pCertType, AE_GENERAL_INFO *pAE_General_Info, BOOL *pfUserProtection)
  3013. {
  3014. DWORD dwValue = 0;
  3015. PCCERT_CONTEXT pCertCurrent=NULL;
  3016. AE_CERT_INFO AECertInfo;
  3017. memset(&AECertInfo, 0, sizeof(AE_CERT_INFO));
  3018. *pfUserProtection=FALSE;
  3019. //check enrollment ACL
  3020. if(S_OK != CACertTypeAccessCheckEx(
  3021. pCertType->hCertType,
  3022. hToken,
  3023. CERTTYPE_ACCESS_CHECK_ENROLL | CERTTYPE_ACCESS_CHECK_NO_MAPPING))
  3024. return FALSE;
  3025. //check the subject requirements
  3026. if(S_OK != CAGetCertTypeFlagsEx(
  3027. pCertType->hCertType,
  3028. CERTTYPE_SUBJECT_NAME_FLAG,
  3029. &dwValue))
  3030. return FALSE;
  3031. if((CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT & dwValue) ||
  3032. (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME & dwValue))
  3033. return FALSE;
  3034. //check if we are doing smart card CSPs and there is no reader installed
  3035. if(FALSE == (pAE_General_Info->fSmartcardSystem))
  3036. {
  3037. if(AESmartcardOnlyTemplate(pCertType->hCertType))
  3038. return FALSE;
  3039. }
  3040. //check if all CSPs on the template is not supported
  3041. {
  3042. if(!AESomeCSPSupported(pCertType->hCertType))
  3043. return FALSE;
  3044. }
  3045. //we might not get the RA property for V1 template
  3046. dwValue = 0;
  3047. //check the RA support
  3048. if(S_OK != CAGetCertTypePropertyEx(
  3049. pCertType->hCertType,
  3050. CERTTYPE_PROP_RA_SIGNATURE,
  3051. &dwValue))
  3052. return TRUE;
  3053. if(0==dwValue)
  3054. return TRUE;
  3055. //self-template RA
  3056. if((CT_FLAG_PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT & (pCertType->dwEnrollmentFlag)) &&
  3057. ((pCertType->fRenewal) && (pCertType->pOldCert))
  3058. )
  3059. {
  3060. //the request has to be RAed
  3061. pCertType->fNeedRA=TRUE;
  3062. return TRUE;
  3063. }
  3064. //autoenrollment only deal with one RA signature.
  3065. //it is sufficient for autoenrollment RA scenarios
  3066. if(1!=dwValue)
  3067. return FALSE;
  3068. //the certificate template requires one and only one RA signature
  3069. //cross-template RA
  3070. //enumerate all certificate in store
  3071. while(pCertCurrent = CertEnumCertificatesInStore(pAE_General_Info->hMyStore, pCertCurrent))
  3072. {
  3073. //check if we need to enroll/renewal for the certificate
  3074. AEValidateCertificateInfo(pAE_General_Info,
  3075. NULL,
  3076. TRUE, //valid private key
  3077. pCertCurrent,
  3078. &AECertInfo);
  3079. //the certificate is good enough for RA signature purpose
  3080. if(AECertInfo.fRenewal)
  3081. {
  3082. if(AEValidRAPolicy(pCertCurrent, pCertType))
  3083. {
  3084. if(AEUserProtectionForTemplate(pAE_General_Info, (PCERT_CONTEXT)pCertCurrent))
  3085. {
  3086. if(pAE_General_Info->fMachine)
  3087. {
  3088. *pfUserProtection=TRUE;
  3089. continue;
  3090. }
  3091. else
  3092. {
  3093. if(0==(CT_FLAG_USER_INTERACTION_REQUIRED & (pCertType->dwEnrollmentFlag)))
  3094. {
  3095. *pfUserProtection=TRUE;
  3096. continue;
  3097. }
  3098. }
  3099. }
  3100. pCertType->fRenewal=TRUE;
  3101. if(pCertType->pOldCert)
  3102. {
  3103. CertFreeCertificateContext(pCertType->pOldCert);
  3104. pCertType->pOldCert=NULL;
  3105. }
  3106. //we will free the certificate context later
  3107. pCertType->pOldCert=(PCERT_CONTEXT)pCertCurrent;
  3108. //we mark UI required if the RAing certificate template requires UI
  3109. if(AEUISetForTemplate(pAE_General_Info, pCertType->pOldCert))
  3110. pCertType->fUIActive=TRUE;
  3111. //we mark the requests has to be RAed.
  3112. pCertType->fNeedRA=TRUE;
  3113. //we mark that we are doing cross RAing.
  3114. pCertType->fCrossRA=TRUE;
  3115. *pfUserProtection=FALSE;
  3116. return TRUE;
  3117. }
  3118. }
  3119. memset(&AECertInfo, 0, sizeof(AE_CERT_INFO));
  3120. }
  3121. return FALSE;
  3122. }
  3123. //-----------------------------------------------------------------------
  3124. //
  3125. // AEMarkAutoenrollment
  3126. //
  3127. //-----------------------------------------------------------------------
  3128. BOOL AEMarkAutoenrollment(AE_GENERAL_INFO *pAE_General_Info)
  3129. {
  3130. DWORD dwIndex = 0;
  3131. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  3132. {
  3133. if(CT_FLAG_AUTO_ENROLLMENT & ((pAE_General_Info->rgCertTypeInfo)[dwIndex].dwEnrollmentFlag))
  3134. {
  3135. //check the autoenrollment ACL
  3136. if(S_OK != CACertTypeAccessCheckEx(
  3137. (pAE_General_Info->rgCertTypeInfo)[dwIndex].hCertType,
  3138. pAE_General_Info->hToken,
  3139. CERTTYPE_ACCESS_CHECK_AUTO_ENROLL | CERTTYPE_ACCESS_CHECK_NO_MAPPING))
  3140. continue;
  3141. //mark the template nees to be auto-enrolled
  3142. (pAE_General_Info->rgCertTypeInfo)[dwIndex].dwStatus=CERT_REQUEST_STATUS_ACTIVE;
  3143. (pAE_General_Info->rgCertTypeInfo)[dwIndex].fCheckMyStore=TRUE;
  3144. }
  3145. }
  3146. return TRUE;
  3147. }
  3148. //-----------------------------------------------------------------------
  3149. //
  3150. // IsACRSStoreEmpty
  3151. //
  3152. //
  3153. //-----------------------------------------------------------------------
  3154. BOOL IsACRSStoreEmpty(BOOL fMachine)
  3155. {
  3156. DWORD dwOpenStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG;
  3157. LPSTR pszCTLUsageOID = NULL;
  3158. BOOL fEmpty = TRUE;
  3159. CERT_PHYSICAL_STORE_INFO PhysicalStoreInfo;
  3160. CTL_FIND_USAGE_PARA CTLFindUsage;
  3161. PCCTL_CONTEXT pCTLContext = NULL;
  3162. HCERTSTORE hStoreACRS=NULL;
  3163. memset(&PhysicalStoreInfo, 0, sizeof(PhysicalStoreInfo));
  3164. memset(&CTLFindUsage, 0, sizeof(CTLFindUsage));
  3165. // if the auto enrollment is for a user then we need to shut off inheritance
  3166. // from the local machine store so that we don't try and enroll for certs
  3167. // which are meant to be for the machine
  3168. if (FALSE == fMachine)
  3169. {
  3170. dwOpenStoreFlags = CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG;
  3171. PhysicalStoreInfo.cbSize = sizeof(PhysicalStoreInfo);
  3172. PhysicalStoreInfo.dwFlags = CERT_PHYSICAL_STORE_OPEN_DISABLE_FLAG;
  3173. if (!CertRegisterPhysicalStore(ACRS_STORE,
  3174. CERT_SYSTEM_STORE_CURRENT_USER,
  3175. CERT_PHYSICAL_STORE_LOCAL_MACHINE_NAME,
  3176. &PhysicalStoreInfo,
  3177. NULL))
  3178. {
  3179. AE_DEBUG((AE_ERROR, L"Could not register ACRS store: (%lx)\n\r", GetLastError()));
  3180. goto Ret;
  3181. }
  3182. }
  3183. // open the ACRS store and fine the CTL based on the auto enrollment usage
  3184. if (NULL == (hStoreACRS = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
  3185. ENCODING_TYPE,
  3186. NULL,
  3187. dwOpenStoreFlags,
  3188. ACRS_STORE)))
  3189. {
  3190. AE_DEBUG((AE_ERROR, L"Could not open ACRS store: (%lx)\n\r", GetLastError()));
  3191. goto Ret;
  3192. }
  3193. //find the template name specified in the CTLContext
  3194. CTLFindUsage.cbSize = sizeof(CTLFindUsage);
  3195. CTLFindUsage.SubjectUsage.cUsageIdentifier = 1;
  3196. pszCTLUsageOID = szOID_AUTO_ENROLL_CTL_USAGE;
  3197. CTLFindUsage.SubjectUsage.rgpszUsageIdentifier = &pszCTLUsageOID;
  3198. while(pCTLContext = CertFindCTLInStore(hStoreACRS,
  3199. X509_ASN_ENCODING,
  3200. CTL_FIND_SAME_USAGE_FLAG,
  3201. CTL_FIND_USAGE,
  3202. &CTLFindUsage,
  3203. pCTLContext))
  3204. {
  3205. fEmpty=FALSE;
  3206. break;
  3207. }
  3208. Ret:
  3209. if(pCTLContext)
  3210. CertFreeCTLContext(pCTLContext);
  3211. if(hStoreACRS)
  3212. CertCloseStore(hStoreACRS, 0);
  3213. return fEmpty;
  3214. }
  3215. //-----------------------------------------------------------------------
  3216. //
  3217. // AEMarkAEObject
  3218. //
  3219. // Mark the active status based on ACRS store
  3220. //
  3221. // INFORMATION:
  3222. // we do not honor the CA specified in the autoenrollment object anymore. All CAs
  3223. // in the enterprise should be treated equal; and once the CA is renewed, it certificate
  3224. // will be changed anyway.
  3225. //-----------------------------------------------------------------------
  3226. BOOL AEMarkAEObject(AE_GENERAL_INFO *pAE_General_Info)
  3227. {
  3228. DWORD dwOpenStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG;
  3229. PCCTL_CONTEXT pCTLContext = NULL;
  3230. LPSTR pszCTLUsageOID = NULL;
  3231. LPWSTR wszCertTypeName = NULL;
  3232. AE_CERTTYPE_INFO *pCertType=NULL;
  3233. CERT_PHYSICAL_STORE_INFO PhysicalStoreInfo;
  3234. CTL_FIND_USAGE_PARA CTLFindUsage;
  3235. AE_TEMPLATE_INFO AETemplateInfo;
  3236. HCERTSTORE hStoreACRS=NULL;
  3237. memset(&PhysicalStoreInfo, 0, sizeof(PhysicalStoreInfo));
  3238. memset(&CTLFindUsage, 0, sizeof(CTLFindUsage));
  3239. memset(&AETemplateInfo, 0, sizeof(AETemplateInfo));
  3240. // if the auto enrollment is for a user then we need to shut off inheritance
  3241. // from the local machine store so that we don't try and enroll for certs
  3242. // which are meant to be for the machine
  3243. if (FALSE == (pAE_General_Info->fMachine))
  3244. {
  3245. dwOpenStoreFlags = CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG;
  3246. PhysicalStoreInfo.cbSize = sizeof(PhysicalStoreInfo);
  3247. PhysicalStoreInfo.dwFlags = CERT_PHYSICAL_STORE_OPEN_DISABLE_FLAG;
  3248. if (!CertRegisterPhysicalStore(ACRS_STORE,
  3249. CERT_SYSTEM_STORE_CURRENT_USER,
  3250. CERT_PHYSICAL_STORE_LOCAL_MACHINE_NAME,
  3251. &PhysicalStoreInfo,
  3252. NULL))
  3253. {
  3254. AE_DEBUG((AE_ERROR, L"Could not register ACRS store: (%lx)\n\r", GetLastError()));
  3255. goto Ret;
  3256. }
  3257. }
  3258. // open the ACRS store and fine the CTL based on the auto enrollment usage
  3259. if (NULL == (hStoreACRS = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
  3260. ENCODING_TYPE,
  3261. NULL,
  3262. dwOpenStoreFlags,
  3263. ACRS_STORE)))
  3264. {
  3265. AE_DEBUG((AE_ERROR, L"Could not open ACRS store: (%lx)\n\r", GetLastError()));
  3266. goto Ret;
  3267. }
  3268. //find the template name specified in the CTLContext
  3269. CTLFindUsage.cbSize = sizeof(CTLFindUsage);
  3270. CTLFindUsage.SubjectUsage.cUsageIdentifier = 1;
  3271. pszCTLUsageOID = szOID_AUTO_ENROLL_CTL_USAGE;
  3272. CTLFindUsage.SubjectUsage.rgpszUsageIdentifier = &pszCTLUsageOID;
  3273. while(pCTLContext = CertFindCTLInStore(hStoreACRS,
  3274. X509_ASN_ENCODING,
  3275. CTL_FIND_SAME_USAGE_FLAG,
  3276. CTL_FIND_USAGE,
  3277. &CTLFindUsage,
  3278. pCTLContext))
  3279. {
  3280. if(NULL== (pCTLContext->pCtlInfo->ListIdentifier.pbData))
  3281. continue;
  3282. wszCertTypeName = wcschr((LPWSTR)pCTLContext->pCtlInfo->ListIdentifier.pbData, L'|');
  3283. if(wszCertTypeName)
  3284. {
  3285. wszCertTypeName++;
  3286. }
  3287. else
  3288. {
  3289. wszCertTypeName = (LPWSTR)pCTLContext->pCtlInfo->ListIdentifier.pbData;
  3290. }
  3291. AETemplateInfo.pwszName = wszCertTypeName;
  3292. if(pCertType=AEFindTemplateInRequestTree(&AETemplateInfo, pAE_General_Info))
  3293. {
  3294. if(0 == pCertType->dwStatus)
  3295. {
  3296. //mark the template needs to be auto-enrolled
  3297. pCertType->dwStatus=CERT_REQUEST_STATUS_ACTIVE;
  3298. pCertType->fCheckMyStore=TRUE;
  3299. }
  3300. }
  3301. else
  3302. {
  3303. //log that the template is invalid
  3304. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_INVALID_ACRS_OBJECT,
  3305. pAE_General_Info->fMachine, pAE_General_Info->hToken, 1, wszCertTypeName);
  3306. }
  3307. }
  3308. Ret:
  3309. if(hStoreACRS)
  3310. CertCloseStore(hStoreACRS, 0);
  3311. return TRUE;
  3312. }
  3313. //-----------------------------------------------------------------------
  3314. //
  3315. // AEManageAndMarkMyStore
  3316. //
  3317. //-----------------------------------------------------------------------
  3318. BOOL AEManageAndMarkMyStore(AE_GENERAL_INFO *pAE_General_Info)
  3319. {
  3320. AE_CERT_INFO AECertInfo;
  3321. AE_CERTTYPE_INFO *pCertType=NULL;
  3322. BOOL fNeedToValidate=TRUE;
  3323. PCCERT_CONTEXT pCertCurrent = NULL;
  3324. DWORD cbData=0;
  3325. AE_TEMPLATE_INFO AETemplateInfo;
  3326. memset(&AECertInfo, 0, sizeof(AE_CERT_INFO));
  3327. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  3328. //enumerate all certificate in store
  3329. while(pCertCurrent = CertEnumCertificatesInStore(pAE_General_Info->hMyStore, pCertCurrent))
  3330. {
  3331. //only interested in certificate with template information
  3332. if(AERetrieveTemplateInfo(pCertCurrent, &AETemplateInfo))
  3333. {
  3334. if(pCertType=AEFindTemplateInRequestTree(
  3335. &AETemplateInfo, pAE_General_Info))
  3336. {
  3337. //if we are not supposed to check for my store, only search
  3338. //for template with ACTIVE status
  3339. if(0 == (AUTO_ENROLLMENT_ENABLE_MY_STORE_MANAGEMENT & (pAE_General_Info->dwPolicy)))
  3340. {
  3341. if(!(pCertType->fCheckMyStore))
  3342. goto Next;
  3343. }
  3344. //make sure the version of the certificate template is up to date
  3345. //we do not have version for V1 template
  3346. if(AETemplateInfo.pwszOid)
  3347. {
  3348. if(AETemplateInfo.dwVersion < pCertType->dwVersion)
  3349. {
  3350. AECertInfo.fValid=FALSE;
  3351. AECertInfo.fRenewal = FALSE;
  3352. //self-RA renewal
  3353. if(CT_FLAG_PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT & pCertType->dwEnrollmentFlag)
  3354. {
  3355. if(CertGetCertificateContextProperty(
  3356. pCertCurrent,
  3357. CERT_KEY_PROV_INFO_PROP_ID,
  3358. NULL,
  3359. &cbData))
  3360. AECertInfo.fRenewal = TRUE;
  3361. }
  3362. fNeedToValidate=FALSE;
  3363. }
  3364. }
  3365. if(fNeedToValidate)
  3366. {
  3367. //check if we need to enroll/renewal for the certificate
  3368. AEValidateCertificateInfo(pAE_General_Info,
  3369. pCertType,
  3370. TRUE, //valid private key
  3371. pCertCurrent,
  3372. &AECertInfo);
  3373. }
  3374. if(AECertInfo.fValid)
  3375. {
  3376. //if the certificate is valid, mark as obtained. And copy the
  3377. //certificate to the obtained store. Keep the archive store.
  3378. pCertType->dwStatus = CERT_REQUEST_STATUS_OBTAINED;
  3379. CertAddCertificateContextToStore(
  3380. pCertType->hObtainedStore,
  3381. pCertCurrent,
  3382. CERT_STORE_ADD_ALWAYS,
  3383. NULL);
  3384. }
  3385. else
  3386. {
  3387. //the certificate is not valid
  3388. //mark the status to active if it is not obtained
  3389. if(CERT_REQUEST_STATUS_OBTAINED != pCertType->dwStatus)
  3390. {
  3391. pCertType->dwStatus = CERT_REQUEST_STATUS_ACTIVE;
  3392. if(AECertInfo.fRenewal)
  3393. {
  3394. //we only need to copy renewal information once
  3395. if(!pCertType->fRenewal)
  3396. {
  3397. pCertType->fRenewal=TRUE;
  3398. pCertType->pOldCert=(PCERT_CONTEXT)CertDuplicateCertificateContext(pCertCurrent);
  3399. }
  3400. }
  3401. }
  3402. //copy the certificate to the Archive certificate store
  3403. CertAddCertificateContextToStore(
  3404. pCertType->hArchiveStore,
  3405. pCertCurrent,
  3406. CERT_STORE_ADD_ALWAYS,
  3407. NULL);
  3408. }
  3409. }
  3410. else
  3411. {
  3412. //log that the template is invalid
  3413. AELogAutoEnrollmentEvent(
  3414. pAE_General_Info->dwLogLevel,
  3415. FALSE,
  3416. S_OK,
  3417. EVENT_INVALID_TEMPLATE_MY_STORE,
  3418. pAE_General_Info->fMachine,
  3419. pAE_General_Info->hToken,
  3420. 1,
  3421. AETemplateInfo.pwszName ? AETemplateInfo.pwszName : AETemplateInfo.pwszOid);
  3422. }
  3423. }
  3424. Next:
  3425. memset(&AECertInfo, 0, sizeof(AE_CERT_INFO));
  3426. AEFreeTemplateInfo(&AETemplateInfo);
  3427. fNeedToValidate=TRUE;
  3428. cbData=0;
  3429. }
  3430. return TRUE;
  3431. }
  3432. //-----------------------------------------------------------------------
  3433. //
  3434. // AEOpenUserDSStore
  3435. //
  3436. // INFORMATION: We could just open the "UserDS" store as if it is "My"
  3437. //
  3438. //-----------------------------------------------------------------------
  3439. HCERTSTORE AEOpenUserDSStore(AE_GENERAL_INFO *pAE_General_Info, DWORD dwOpenFlag)
  3440. {
  3441. LPWSTR pwszPath=L"ldap:///%s?userCertificate?base?objectCategory=user";
  3442. DWORD dwSize=0;
  3443. WCHAR wszDN[MAX_DN_SIZE];
  3444. LPWSTR pwszDN=NULL;
  3445. LPWSTR pwszStore=NULL;
  3446. HCERTSTORE hStore=NULL;
  3447. dwSize=MAX_DN_SIZE;
  3448. if(!GetUserNameExW(NameFullyQualifiedDN, wszDN, &dwSize))
  3449. {
  3450. if(dwSize > MAX_DN_SIZE)
  3451. {
  3452. pwszDN=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * dwSize);
  3453. if(NULL==pwszDN)
  3454. goto Ret;
  3455. if(!GetUserNameExW(NameFullyQualifiedDN, pwszDN, &dwSize))
  3456. goto Ret;
  3457. }
  3458. else
  3459. goto Ret;
  3460. }
  3461. pwszStore = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(pwszDN ? pwszDN : wszDN)+wcslen(pwszPath)+1));
  3462. if(pwszStore == NULL)
  3463. goto Ret;
  3464. wsprintf(pwszStore,
  3465. pwszPath,
  3466. pwszDN ? pwszDN : wszDN);
  3467. hStore = CertOpenStore(CERT_STORE_PROV_LDAP,
  3468. ENCODING_TYPE,
  3469. NULL,
  3470. dwOpenFlag | CERT_LDAP_STORE_SIGN_FLAG,
  3471. pwszStore);
  3472. Ret:
  3473. if(pwszStore)
  3474. LocalFree(pwszStore);
  3475. if(pwszDN)
  3476. LocalFree(pwszDN);
  3477. return hStore;
  3478. }
  3479. //-----------------------------------------------------------------------
  3480. //
  3481. // AECheckUserDSStore
  3482. //
  3483. //-----------------------------------------------------------------------
  3484. BOOL AECheckUserDSStore(AE_GENERAL_INFO *pAE_General_Info)
  3485. {
  3486. PCCERT_CONTEXT pCertCurrent = NULL;
  3487. AE_CERTTYPE_INFO *pCertType=NULL;
  3488. BOOL fNeedToValidate=TRUE;
  3489. AE_CERT_INFO AECertInfo;
  3490. HCERTSTORE hUserDS = NULL;
  3491. AE_TEMPLATE_INFO AETemplateInfo;
  3492. memset(&AECertInfo, 0, sizeof(AE_CERT_INFO));
  3493. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  3494. pCertType=pAE_General_Info->rgCertTypeInfo;
  3495. if(NULL==pCertType)
  3496. goto Ret;
  3497. if(NULL== (hUserDS = AEOpenUserDSStore(pAE_General_Info, CERT_STORE_READONLY_FLAG)))
  3498. goto Ret;
  3499. pCertType = NULL;
  3500. while(pCertCurrent = CertEnumCertificatesInStore(hUserDS, pCertCurrent))
  3501. {
  3502. //only interested in certificate with template information
  3503. if(AERetrieveTemplateInfo(pCertCurrent, &AETemplateInfo))
  3504. {
  3505. if(pCertType=AEFindTemplateInRequestTree(
  3506. &AETemplateInfo, pAE_General_Info))
  3507. {
  3508. //if we are not supposed to check for UserDS store, only search
  3509. //for template with ACTIVE status
  3510. if(0 == (AUTO_ENROLLMENT_ENABLE_MY_STORE_MANAGEMENT & (pAE_General_Info->dwPolicy)))
  3511. {
  3512. if(!(pCertType->fCheckMyStore))
  3513. goto Next;
  3514. }
  3515. //make sure the version of the certificate template is up to date
  3516. //we do not have version for V1 template
  3517. if(AETemplateInfo.pwszOid)
  3518. {
  3519. if(AETemplateInfo.dwVersion < pCertType->dwVersion)
  3520. {
  3521. AECertInfo.fValid=FALSE;
  3522. AECertInfo.fRenewal=FALSE;
  3523. fNeedToValidate=FALSE;
  3524. }
  3525. }
  3526. if(fNeedToValidate)
  3527. {
  3528. //check if we need to enroll/renewal for the certificate
  3529. AEValidateCertificateInfo(pAE_General_Info,
  3530. pCertType,
  3531. FALSE, //does not valid private key
  3532. pCertCurrent,
  3533. &AECertInfo);
  3534. }
  3535. //we only interested in any valid certificate
  3536. if(AECertInfo.fValid)
  3537. {
  3538. if((CT_FLAG_AUTO_ENROLLMENT_CHECK_USER_DS_CERTIFICATE & (pCertType->dwEnrollmentFlag)) &&
  3539. (CERT_REQUEST_STATUS_OBTAINED != pCertType->dwStatus))
  3540. {
  3541. //mark the status as obtained.
  3542. pCertType->dwStatus = CERT_REQUEST_STATUS_OBTAINED;
  3543. }
  3544. CertAddCertificateContextToStore(
  3545. pCertType->hObtainedStore,
  3546. pCertCurrent,
  3547. CERT_STORE_ADD_USE_EXISTING,
  3548. NULL);
  3549. }
  3550. else
  3551. {
  3552. //copy the certificate to the Archive certificate store
  3553. CertAddCertificateContextToStore(
  3554. pCertType->hArchiveStore,
  3555. pCertCurrent,
  3556. CERT_STORE_ADD_USE_EXISTING,
  3557. NULL);
  3558. }
  3559. }
  3560. }
  3561. Next:
  3562. memset(&AECertInfo, 0, sizeof(AE_CERT_INFO));
  3563. AEFreeTemplateInfo(&AETemplateInfo);
  3564. fNeedToValidate=TRUE;
  3565. }
  3566. Ret:
  3567. if(hUserDS)
  3568. CertCloseStore(hUserDS, 0);
  3569. return TRUE;
  3570. }
  3571. //-----------------------------------------------------------------------
  3572. //
  3573. // AECheckPendingRequests
  3574. //
  3575. // If we have pending update-to-date certificate requests, no need
  3576. // to enroll/renew for duplicates.
  3577. //-----------------------------------------------------------------------
  3578. BOOL AECheckPendingRequests(AE_GENERAL_INFO *pAE_General_Info)
  3579. {
  3580. DWORD dwIndex=0;
  3581. DWORD dwVersion=0;
  3582. AE_CERTTYPE_INFO *pCertType=NULL;
  3583. BOOL fValid=FALSE;
  3584. DWORD dwCount=0;
  3585. DWORD dwMax=PENDING_ALLOC_SIZE;
  3586. PFNPIEnroll4GetNoCOM pfnPIEnroll4GetNoCOM=NULL;
  3587. FILETIME ftTime;
  3588. LARGE_INTEGER ftRequestTime;
  3589. AE_TEMPLATE_INFO AETemplateInfo;
  3590. IEnroll4 *pIEnroll4=NULL;
  3591. CRYPT_DATA_BLOB *rgblobHash=NULL;
  3592. CRYPT_DATA_BLOB blobName;
  3593. //init before any goto Ret
  3594. memset(&blobName, 0, sizeof(blobName));
  3595. memset(&AETemplateInfo, 0, sizeof(AETemplateInfo));
  3596. if(NULL==pAE_General_Info->hXenroll)
  3597. goto Ret;
  3598. if(NULL==(pfnPIEnroll4GetNoCOM=(PFNPIEnroll4GetNoCOM)GetProcAddress(
  3599. pAE_General_Info->hXenroll,
  3600. "PIEnroll4GetNoCOM")))
  3601. goto Ret;
  3602. if(NULL==(pIEnroll4=pfnPIEnroll4GetNoCOM()))
  3603. goto Ret;
  3604. GetSystemTimeAsFileTime(&ftTime);
  3605. if(pAE_General_Info->fMachine)
  3606. {
  3607. if(S_OK != pIEnroll4->put_RequestStoreFlags(CERT_SYSTEM_STORE_LOCAL_MACHINE))
  3608. goto Ret;
  3609. }
  3610. else
  3611. {
  3612. if(S_OK != pIEnroll4->put_RequestStoreFlags(CERT_SYSTEM_STORE_CURRENT_USER))
  3613. goto Ret;
  3614. }
  3615. //enumerate all the pending requests
  3616. rgblobHash=(CRYPT_DATA_BLOB *)LocalAlloc(LPTR, dwMax * sizeof(CRYPT_DATA_BLOB));
  3617. if(NULL==rgblobHash)
  3618. goto Ret;
  3619. memset(rgblobHash, 0, dwMax * sizeof(CRYPT_DATA_BLOB));
  3620. //initialize the enumerator
  3621. if(S_OK != pIEnroll4->enumPendingRequestWStr(XEPR_ENUM_FIRST, 0, NULL))
  3622. goto Ret;
  3623. while(AEGetPendingRequestProperty(
  3624. pIEnroll4,
  3625. dwIndex,
  3626. XEPR_DATE,
  3627. &ftRequestTime))
  3628. {
  3629. ftRequestTime.QuadPart += Int32x32To64(FILETIME_TICKS_PER_SECOND,
  3630. AE_PENDING_REQUEST_ACTIVE_PERIOD * 24 * 3600);
  3631. //remove the request if out of date
  3632. if(0 <= CompareFileTime(&ftTime, (LPFILETIME)&ftRequestTime))
  3633. {
  3634. AERetrieveRequestProperty(pIEnroll4, dwIndex, &dwCount, &dwMax, &rgblobHash);
  3635. }
  3636. else
  3637. {
  3638. //get the version and the template name of the request
  3639. if(AEGetPendingRequestProperty(pIEnroll4, dwIndex, XEPR_V2TEMPLATEOID, &blobName))
  3640. {
  3641. //this is a V2 template
  3642. if(!AEGetPendingRequestProperty(pIEnroll4, dwIndex, XEPR_VERSION, &dwVersion))
  3643. goto Next;
  3644. AETemplateInfo.pwszOid=(LPWSTR)blobName.pbData;
  3645. }
  3646. else
  3647. {
  3648. if(!AEGetPendingRequestProperty(pIEnroll4, dwIndex, XEPR_V1TEMPLATENAME, &blobName))
  3649. goto Next;
  3650. AETemplateInfo.pwszName=(LPWSTR)blobName.pbData;
  3651. }
  3652. //find the template
  3653. if(NULL==(pCertType=AEFindTemplateInRequestTree(
  3654. &AETemplateInfo, pAE_General_Info)))
  3655. goto Next;
  3656. if(AETemplateInfo.pwszName)
  3657. fValid=TRUE;
  3658. else
  3659. {
  3660. if(dwVersion >= pCertType->dwVersion)
  3661. fValid=TRUE;
  3662. }
  3663. if(fValid)
  3664. {
  3665. //this is a valid pending request
  3666. if(CERT_REQUEST_STATUS_OBTAINED != pCertType->dwStatus)
  3667. pCertType->dwStatus=CERT_REQUEST_STATUS_PENDING;
  3668. }
  3669. else
  3670. {
  3671. if(CERT_REQUEST_STATUS_OBTAINED == pCertType->dwStatus)
  3672. AERetrieveRequestProperty(pIEnroll4, dwIndex, &dwCount, &dwMax, &rgblobHash);
  3673. }
  3674. }
  3675. Next:
  3676. if(blobName.pbData)
  3677. LocalFree(blobName.pbData);
  3678. memset(&blobName, 0, sizeof(blobName));
  3679. memset(&AETemplateInfo, 0, sizeof(AETemplateInfo));
  3680. fValid=FALSE;
  3681. dwVersion=0;
  3682. dwIndex++;
  3683. }
  3684. //remove the requests based the hash
  3685. if(dwCount)
  3686. {
  3687. AERemovePendingRequest(pIEnroll4, dwCount, rgblobHash);
  3688. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_PENDING_INVALID, pAE_General_Info->fMachine, pAE_General_Info->hToken, 0);
  3689. }
  3690. Ret:
  3691. AEFreePendingRequests(dwCount, rgblobHash);
  3692. if(blobName.pbData)
  3693. LocalFree(blobName.pbData);
  3694. if(pIEnroll4)
  3695. pIEnroll4->Release();
  3696. return TRUE;
  3697. }
  3698. //-----------------------------------------------------------------------
  3699. //
  3700. // AECheckSupersedeRequest
  3701. //
  3702. //-----------------------------------------------------------------------
  3703. BOOL AECheckSupersedeRequest(DWORD dwCurIndex,
  3704. AE_CERTTYPE_INFO *pCurCertType,
  3705. AE_CERTTYPE_INFO *pSupersedingCertType,
  3706. AE_GENERAL_INFO *pAE_General_Info)
  3707. {
  3708. BOOL fFound=FALSE;
  3709. LPWSTR *awszSuperseding=NULL;
  3710. if(S_OK == CAGetCertTypePropertyEx(
  3711. pSupersedingCertType->hCertType,
  3712. CERTTYPE_PROP_SUPERSEDE,
  3713. &(awszSuperseding)))
  3714. {
  3715. if(awszSuperseding && awszSuperseding[0])
  3716. {
  3717. if(AEIfSupersede(pCurCertType->awszName[0], awszSuperseding, pAE_General_Info))
  3718. {
  3719. switch(pCurCertType->dwStatus)
  3720. {
  3721. case CERT_REQUEST_STATUS_ACTIVE:
  3722. case CERT_REQUEST_STATUS_SUPERSEDE_ACTIVE:
  3723. //remove the active status if it is superseded by an obtained certificate
  3724. if(CERT_REQUEST_STATUS_OBTAINED != pSupersedingCertType->dwStatus)
  3725. {
  3726. pCurCertType->dwStatus = CERT_REQUEST_STATUS_SUPERSEDE_ACTIVE;
  3727. pSupersedingCertType->prgActive[pSupersedingCertType->dwActive]=dwCurIndex;
  3728. (pSupersedingCertType->dwActive)++;
  3729. }
  3730. else
  3731. {
  3732. pCurCertType->dwStatus = 0;
  3733. }
  3734. case CERT_REQUEST_STATUS_PENDING:
  3735. AECopyCertStore(pCurCertType->hArchiveStore,
  3736. pSupersedingCertType->hArchiveStore);
  3737. break;
  3738. case CERT_REQUEST_STATUS_OBTAINED:
  3739. AECopyCertStore(pCurCertType->hObtainedStore,
  3740. pSupersedingCertType->hArchiveStore);
  3741. break;
  3742. default:
  3743. AECopyCertStore(pCurCertType->hArchiveStore,
  3744. pSupersedingCertType->hArchiveStore);
  3745. break;
  3746. }
  3747. //we consider that we find a valid superseding template only if the status
  3748. //is obtained. If the status is anyting else, we need to keep searching since
  3749. //enrollment/renewal requests might not be granted
  3750. if(CERT_REQUEST_STATUS_OBTAINED == pSupersedingCertType->dwStatus)
  3751. fFound=TRUE;
  3752. }
  3753. //clear the visited flag in AE_General_Info
  3754. AEClearVistedFlag(pAE_General_Info);
  3755. }
  3756. //free the property
  3757. if(awszSuperseding)
  3758. CAFreeCertTypeProperty(
  3759. pSupersedingCertType->hCertType,
  3760. awszSuperseding);
  3761. awszSuperseding=NULL;
  3762. }
  3763. return fFound;
  3764. }
  3765. //-----------------------------------------------------------------------
  3766. //
  3767. // AEIsCALonger
  3768. //
  3769. // For renewal, the CA's certificate has to live longer than the
  3770. // renewing certificate
  3771. //
  3772. //-----------------------------------------------------------------------
  3773. BOOL AEIsCALonger(HCAINFO hCAInfo, PCERT_CONTEXT pOldCert)
  3774. {
  3775. BOOL fCALonger=TRUE;
  3776. PCCERT_CONTEXT pCACert=NULL;
  3777. //we assume the CA is good unless we found something wrong
  3778. if((NULL == hCAInfo) || (NULL == pOldCert))
  3779. goto Ret;
  3780. if(S_OK != CAGetCACertificate(hCAInfo, &pCACert))
  3781. goto Ret;
  3782. if(NULL == pCACert)
  3783. goto Ret;
  3784. //CA cert's NotAfter should be longer than the issued certificate' NotAfger
  3785. if(1 == CompareFileTime(&(pCACert->pCertInfo->NotAfter), &(pOldCert->pCertInfo->NotAfter)))
  3786. goto Ret;
  3787. fCALonger=FALSE;
  3788. Ret:
  3789. if(pCACert)
  3790. CertFreeCertificateContext(pCACert);
  3791. return fCALonger;
  3792. }
  3793. //-----------------------------------------------------------------------
  3794. //
  3795. // AECanFindCAForCertType
  3796. //
  3797. // Check if there exists a CA that can issue the specified certificate
  3798. // template.
  3799. //
  3800. //-----------------------------------------------------------------------
  3801. BOOL AECanFindCAForCertType(AE_GENERAL_INFO *pAE_General_Info, AE_CERTTYPE_INFO *pCertType)
  3802. {
  3803. DWORD dwIndex=0;
  3804. BOOL fFound=FALSE;
  3805. AE_CA_INFO *prgCAInfo=pAE_General_Info->rgCAInfo;
  3806. BOOL fRenewal=FALSE;
  3807. //detect if we are performing an enrollment or renewal
  3808. if((pCertType->fRenewal) && (pCertType->pOldCert))
  3809. {
  3810. if((pCertType->fNeedRA) && (pCertType->fCrossRA))
  3811. fRenewal=FALSE;
  3812. else
  3813. fRenewal=TRUE;
  3814. }
  3815. else
  3816. fRenewal=FALSE;
  3817. if(prgCAInfo)
  3818. {
  3819. for(dwIndex=0; dwIndex < pAE_General_Info->dwCA; dwIndex++)
  3820. {
  3821. //make sure the CA supports the specific template
  3822. if(AEIsAnElement((pCertType->awszName)[0],
  3823. (prgCAInfo[dwIndex]).awszCertificateTemplate))
  3824. {
  3825. if(FALSE == fRenewal)
  3826. {
  3827. fFound=TRUE;
  3828. break;
  3829. }
  3830. else
  3831. {
  3832. if(AEIsCALonger(prgCAInfo[dwIndex].hCAInfo, pCertType->pOldCert))
  3833. {
  3834. fFound=TRUE;
  3835. break;
  3836. }
  3837. }
  3838. }
  3839. }
  3840. }
  3841. return fFound;
  3842. }
  3843. //-----------------------------------------------------------------------
  3844. //
  3845. // AEManageActiveTemplates
  3846. //
  3847. // We make sure that for all active templates, we can in deed enroll
  3848. // for it.
  3849. //
  3850. //-----------------------------------------------------------------------
  3851. BOOL AEManageActiveTemplates(AE_GENERAL_INFO *pAE_General_Info)
  3852. {
  3853. DWORD dwIndex=0;
  3854. AE_CERTTYPE_INFO *pCertTypeInfo=pAE_General_Info->rgCertTypeInfo;
  3855. AE_CERTTYPE_INFO *pCurCertType=NULL;
  3856. BOOL fCanEnrollCertType=FALSE;
  3857. BOOL fUserProtection=FALSE;
  3858. DWORD dwEventID=0;
  3859. if(pCertTypeInfo)
  3860. {
  3861. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  3862. {
  3863. pCurCertType = &(pCertTypeInfo[dwIndex]);
  3864. fCanEnrollCertType=FALSE;
  3865. fUserProtection=FALSE;
  3866. if(CERT_REQUEST_STATUS_PENDING == pCurCertType->dwStatus)
  3867. {
  3868. //check if UI is required
  3869. if(CT_FLAG_USER_INTERACTION_REQUIRED & (pCurCertType->dwEnrollmentFlag))
  3870. {
  3871. pCurCertType->fUIActive=TRUE;
  3872. if(pAE_General_Info->fMachine)
  3873. {
  3874. pCurCertType->dwStatus = 0;
  3875. //log that user does not have access right to the template
  3876. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_NO_ACCESS_ACRS_OBJECT,
  3877. pAE_General_Info->fMachine, pAE_General_Info->hToken, 1, (pCurCertType->awszDisplay)[0]);
  3878. }
  3879. }
  3880. continue;
  3881. }
  3882. if(CERT_REQUEST_STATUS_ACTIVE != pCurCertType->dwStatus)
  3883. continue;
  3884. //check for V1 smart card User or smart card logon certificate template
  3885. if((0 == _wcsicmp(wszCERTTYPE_SMARTCARD_USER, (pCurCertType->awszName)[0])) ||
  3886. (0 == _wcsicmp(wszCERTTYPE_USER_SMARTCARD_LOGON,(pCurCertType->awszName)[0]))
  3887. )
  3888. {
  3889. pCurCertType->dwStatus = 0;
  3890. //log that user does not have access right to the template
  3891. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_NO_V1_SCARD,
  3892. pAE_General_Info->fMachine, pAE_General_Info->hToken, 1, (pCurCertType->awszDisplay)[0]);
  3893. continue;
  3894. }
  3895. //check if CRYPT_USER_PROTECTED is used for machine certificate template
  3896. if(CT_FLAG_STRONG_KEY_PROTECTION_REQUIRED & pCurCertType->dwPrivateKeyFlag)
  3897. {
  3898. if(pAE_General_Info->fMachine)
  3899. {
  3900. pCurCertType->dwStatus = 0;
  3901. //log that machine template should not require user password
  3902. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_NO_USER_PROTECTION_FOR_MACHINE,
  3903. pAE_General_Info->fMachine, pAE_General_Info->hToken, 1, (pCurCertType->awszDisplay)[0]);
  3904. continue;
  3905. }
  3906. else
  3907. {
  3908. if(0 == (CT_FLAG_USER_INTERACTION_REQUIRED & (pCurCertType->dwEnrollmentFlag)))
  3909. {
  3910. pCurCertType->dwStatus = 0;
  3911. //log that user interaction is not set
  3912. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_NO_USER_INTERACTION,
  3913. pAE_General_Info->fMachine, pAE_General_Info->hToken, 1, (pCurCertType->awszDisplay)[0]);
  3914. continue;
  3915. }
  3916. }
  3917. }
  3918. fCanEnrollCertType=AECanEnrollCertType(pAE_General_Info->hToken, pCurCertType, pAE_General_Info, &fUserProtection);
  3919. if((!fCanEnrollCertType) ||
  3920. (!AECanFindCAForCertType(pAE_General_Info, pCurCertType))
  3921. )
  3922. {
  3923. pCurCertType->dwStatus = 0;
  3924. //log that user does not have access right to the template
  3925. if(FALSE == fUserProtection)
  3926. {
  3927. dwEventID=EVENT_NO_ACCESS_ACRS_OBJECT;
  3928. }
  3929. else
  3930. {
  3931. if(pAE_General_Info->fMachine)
  3932. dwEventID=EVENT_NO_USER_PROTECTION_FOR_MACHINE_RA;
  3933. else
  3934. dwEventID=EVENT_NO_USER_INTERACTION_RA;
  3935. }
  3936. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, dwEventID,
  3937. pAE_General_Info->fMachine, pAE_General_Info->hToken, 1, (pCurCertType->awszDisplay)[0]);
  3938. }
  3939. else
  3940. {
  3941. //check if UI is required
  3942. if(CT_FLAG_USER_INTERACTION_REQUIRED & (pCurCertType->dwEnrollmentFlag))
  3943. {
  3944. pCurCertType->fUIActive=TRUE;
  3945. if(pAE_General_Info->fMachine)
  3946. {
  3947. pCurCertType->dwStatus = 0;
  3948. //log that user does not have access right to the template
  3949. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_NO_ACCESS_ACRS_OBJECT,
  3950. pAE_General_Info->fMachine, pAE_General_Info->hToken, 1, (pCurCertType->awszDisplay)[0]);
  3951. }
  3952. }
  3953. }
  3954. }
  3955. }
  3956. return TRUE;
  3957. }
  3958. //-----------------------------------------------------------------------
  3959. //
  3960. // AEManageSupersedeRequests
  3961. // remove duplicated requests based on "Supersede" relationship
  3962. //
  3963. //
  3964. //-----------------------------------------------------------------------
  3965. BOOL AEManageSupersedeRequests(AE_GENERAL_INFO *pAE_General_Info)
  3966. {
  3967. DWORD dwIndex=0;
  3968. DWORD dwSuperseding=0;
  3969. DWORD dwOrder=0;
  3970. AE_CERTTYPE_INFO *pCertTypeInfo=pAE_General_Info->rgCertTypeInfo;
  3971. AE_CERTTYPE_INFO *pCurCertType=NULL;
  3972. AE_CERTTYPE_INFO *pSupersedingCertType=NULL;
  3973. BOOL fFound=FALSE;
  3974. if(pCertTypeInfo)
  3975. {
  3976. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  3977. {
  3978. pCurCertType = &(pCertTypeInfo[dwIndex]);
  3979. //we only consider templates with valid status
  3980. if((0 == pCurCertType->dwStatus) && (TRUE == AEIsEmptyStore(pCurCertType->hArchiveStore)))
  3981. continue;
  3982. fFound=FALSE;
  3983. for(dwOrder=0; dwOrder < g_dwSupersedeOrder; dwOrder++)
  3984. {
  3985. for(dwSuperseding=0; dwSuperseding < pAE_General_Info->dwCertType; dwSuperseding++)
  3986. {
  3987. //one can not be superseded by itself
  3988. if(dwIndex == dwSuperseding)
  3989. continue;
  3990. pSupersedingCertType = &(pCertTypeInfo[dwSuperseding]);
  3991. //we consider templates with obtained status first
  3992. if(g_rgdwSupersedeOrder[dwOrder] != pSupersedingCertType->dwStatus)
  3993. continue;
  3994. fFound = AECheckSupersedeRequest(dwIndex, pCurCertType, pSupersedingCertType, pAE_General_Info);
  3995. //we find a valid superseding template
  3996. if(fFound)
  3997. break;
  3998. }
  3999. //we find a valid superseding template
  4000. if(fFound)
  4001. break;
  4002. }
  4003. }
  4004. }
  4005. return TRUE;
  4006. }
  4007. //-----------------------------------------------------------------------
  4008. //
  4009. // AEDoOneEnrollment
  4010. //
  4011. //-----------------------------------------------------------------------
  4012. /*BOOL AEDoOneEnrollment(HWND hwndParent,
  4013. BOOL fUIProcess,
  4014. BOOL fMachine,
  4015. LPWSTR pwszMachineName,
  4016. AE_CERTTYPE_INFO *pCertType,
  4017. AE_CA_INFO *pCAInfo,
  4018. DWORD *pdwStatus)
  4019. {
  4020. BOOL fResult = FALSE;
  4021. CRYPTUI_WIZ_CERT_REQUEST_INFO CertRequestInfo;
  4022. CRYPTUI_WIZ_CERT_TYPE CertWizType;
  4023. CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW CertPvkNew;
  4024. CRYPT_KEY_PROV_INFO KeyProvInfo;
  4025. memset(&CertRequestInfo, 0, sizeof(CRYPTUI_WIZ_CERT_REQUEST_INFO));
  4026. memset(&CertWizType, 0, sizeof(CRYPTUI_WIZ_CERT_TYPE));
  4027. memset(&CertPvkNew, 0, sizeof(CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW));
  4028. memset(&KeyProvInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
  4029. CertRequestInfo.dwSize = sizeof(CRYPTUI_WIZ_CERT_REQUEST_INFO);
  4030. //enroll or renewal
  4031. if((pCertType->fRenewal) && (pCertType->pOldCert))
  4032. {
  4033. CertRequestInfo.dwPurpose = CRYPTUI_WIZ_CERT_RENEW;
  4034. CertRequestInfo.pRenewCertContext = pCertType->pOldCert;
  4035. }
  4036. else
  4037. CertRequestInfo.dwPurpose = CRYPTUI_WIZ_CERT_ENROLL;
  4038. //machine name
  4039. if(fMachine)
  4040. {
  4041. CertRequestInfo.pwszMachineName = pwszMachineName;
  4042. }
  4043. //private key information
  4044. CertRequestInfo.dwPvkChoice = CRYPTUI_WIZ_CERT_REQUEST_PVK_CHOICE_NEW;
  4045. CertRequestInfo.pPvkNew = &CertPvkNew;
  4046. CertPvkNew.dwSize = sizeof(CertPvkNew);
  4047. CertPvkNew.pKeyProvInfo = &KeyProvInfo;
  4048. CertPvkNew.dwGenKeyFlags = 0; //no need to specify the exportable flags
  4049. //SILENT is always set for machine
  4050. if(fMachine)
  4051. KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET | CRYPT_SILENT;
  4052. else
  4053. {
  4054. if(fUIProcess)
  4055. KeyProvInfo.dwFlags = 0;
  4056. else
  4057. KeyProvInfo.dwFlags = CRYPT_SILENT;
  4058. }
  4059. //CA information
  4060. CertRequestInfo.pwszCALocation = pCAInfo->awszCADNS[0];
  4061. CertRequestInfo.pwszCAName = pCAInfo->awszCAName[0];
  4062. //enroll for the template
  4063. CertRequestInfo.dwCertChoice = CRYPTUI_WIZ_CERT_REQUEST_CERT_TYPE;
  4064. CertRequestInfo.pCertType = &CertWizType;
  4065. CertWizType.dwSize = sizeof(CertWizType);
  4066. CertWizType.cCertType = 1;
  4067. CertWizType.rgwszCertType = &(pCertType->awszName[0]);
  4068. //ISSUE: we need to call Duncanb's new no-DS look up API
  4069. //for faster performance
  4070. fResult = CryptUIWizCertRequest(CRYPTUI_WIZ_NO_UI_EXCEPT_CSP | CRYPTUI_WIZ_NO_INSTALL_ROOT,
  4071. hwndParent,
  4072. NULL,
  4073. &CertRequestInfo,
  4074. NULL, //pCertContext
  4075. pdwStatus);
  4076. return fResult;
  4077. } */
  4078. //-----------------------------------------------------------------------
  4079. //
  4080. // AECreateEnrollmentRequest
  4081. //
  4082. //
  4083. //-----------------------------------------------------------------------
  4084. BOOL AECreateEnrollmentRequest(
  4085. HWND hwndParent,
  4086. BOOL fUIProcess,
  4087. BOOL fMachine,
  4088. LPWSTR pwszMachineName,
  4089. AE_CERTTYPE_INFO *pCertType,
  4090. AE_CA_INFO *pCAInfo,
  4091. HANDLE *phRequest,
  4092. DWORD *pdwLastError)
  4093. {
  4094. BOOL fResult = FALSE;
  4095. CRYPTUI_WIZ_CREATE_CERT_REQUEST_INFO CreateRequestInfo;
  4096. CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW CertPvkNew;
  4097. CRYPT_KEY_PROV_INFO KeyProvInfo;
  4098. DWORD dwFlags=CRYPTUI_WIZ_NO_UI_EXCEPT_CSP |
  4099. CRYPTUI_WIZ_NO_INSTALL_ROOT |
  4100. CRYPTUI_WIZ_ALLOW_ALL_TEMPLATES |
  4101. CRYPTUI_WIZ_ALLOW_ALL_CAS;
  4102. DWORD dwSize=0;
  4103. DWORD dwAcquireFlags=0;
  4104. BOOL fResetProv=FALSE;
  4105. CRYPT_KEY_PROV_INFO *pKeyProvInfo=NULL;
  4106. HANDLE hRequest=NULL;
  4107. memset(&CreateRequestInfo, 0, sizeof(CRYPTUI_WIZ_CREATE_CERT_REQUEST_INFO));
  4108. memset(&CertPvkNew, 0, sizeof(CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW));
  4109. memset(&KeyProvInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
  4110. CreateRequestInfo.dwSize = sizeof(CreateRequestInfo);
  4111. //enroll or renewal
  4112. if((pCertType->fRenewal) && (pCertType->pOldCert))
  4113. {
  4114. CreateRequestInfo.dwPurpose = CRYPTUI_WIZ_CERT_RENEW;
  4115. CreateRequestInfo.pRenewCertContext = pCertType->pOldCert;
  4116. //we should not archive renewal certificate for cross template RA
  4117. if((pCertType->fNeedRA) && (pCertType->fCrossRA))
  4118. dwFlags |= CRYPTUI_WIZ_NO_ARCHIVE_RENEW_CERT;
  4119. //we should disalbe UI for machine or non-UI enrollment renew/RA certificate
  4120. if((TRUE == fMachine) || (FALSE == fUIProcess))
  4121. {
  4122. dwSize=0;
  4123. if(!CertGetCertificateContextProperty(pCertType->pOldCert,
  4124. CERT_KEY_PROV_INFO_PROP_ID,
  4125. NULL,
  4126. &dwSize))
  4127. goto error;
  4128. pKeyProvInfo=(CRYPT_KEY_PROV_INFO *)LocalAlloc(LPTR, dwSize);
  4129. if(NULL == pKeyProvInfo)
  4130. goto error;
  4131. if(!CertGetCertificateContextProperty(pCertType->pOldCert,
  4132. CERT_KEY_PROV_INFO_PROP_ID,
  4133. pKeyProvInfo,
  4134. &dwSize))
  4135. goto error;
  4136. dwAcquireFlags=pKeyProvInfo->dwFlags;
  4137. pKeyProvInfo->dwFlags |= CRYPT_SILENT;
  4138. //set the property
  4139. if(!CertSetCertificateContextProperty(pCertType->pOldCert,
  4140. CERT_KEY_PROV_INFO_PROP_ID,
  4141. CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG,
  4142. pKeyProvInfo))
  4143. goto error;
  4144. fResetProv=TRUE;
  4145. }
  4146. }
  4147. else
  4148. CreateRequestInfo.dwPurpose = CRYPTUI_WIZ_CERT_ENROLL;
  4149. //cert template information
  4150. CreateRequestInfo.hCertType = pCertType->hCertType;
  4151. //machine name
  4152. if(fMachine)
  4153. {
  4154. CreateRequestInfo.fMachineContext = TRUE;
  4155. }
  4156. //private key information
  4157. CreateRequestInfo.dwPvkChoice = CRYPTUI_WIZ_CERT_REQUEST_PVK_CHOICE_NEW;
  4158. CreateRequestInfo.pPvkNew = &CertPvkNew;
  4159. CertPvkNew.dwSize = sizeof(CertPvkNew);
  4160. CertPvkNew.pKeyProvInfo = &KeyProvInfo;
  4161. CertPvkNew.dwGenKeyFlags = 0; //no need to specify the exportable flags
  4162. //SILENT is always set for machine
  4163. if(fMachine)
  4164. KeyProvInfo.dwFlags = CRYPT_MACHINE_KEYSET | CRYPT_SILENT;
  4165. else
  4166. {
  4167. if(fUIProcess)
  4168. KeyProvInfo.dwFlags = 0;
  4169. else
  4170. KeyProvInfo.dwFlags = CRYPT_SILENT;
  4171. }
  4172. //CA information
  4173. CreateRequestInfo.pwszCALocation = pCAInfo->awszCADNS[0];
  4174. CreateRequestInfo.pwszCAName = pCAInfo->awszCAName[0];
  4175. if(!CryptUIWizCreateCertRequestNoDS(
  4176. dwFlags,
  4177. hwndParent,
  4178. &CreateRequestInfo,
  4179. &hRequest))
  4180. goto error;
  4181. if(NULL==hRequest)
  4182. goto error;
  4183. *phRequest=hRequest;
  4184. hRequest=NULL;
  4185. fResult = TRUE;
  4186. error:
  4187. //get the last error
  4188. if(FALSE == fResult)
  4189. {
  4190. *pdwLastError=GetLastError();
  4191. }
  4192. //reset the property
  4193. if(TRUE == fResetProv)
  4194. {
  4195. if((pKeyProvInfo) && (pCertType->pOldCert))
  4196. {
  4197. pKeyProvInfo->dwFlags = dwAcquireFlags;
  4198. //set the property
  4199. CertSetCertificateContextProperty(pCertType->pOldCert,
  4200. CERT_KEY_PROV_INFO_PROP_ID,
  4201. CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG,
  4202. pKeyProvInfo);
  4203. }
  4204. }
  4205. if(pKeyProvInfo)
  4206. LocalFree(pKeyProvInfo);
  4207. if(hRequest)
  4208. CryptUIWizFreeCertRequestNoDS(hRequest);
  4209. return fResult;
  4210. }
  4211. //-----------------------------------------------------------------------
  4212. //
  4213. // AECancelled
  4214. //
  4215. //-----------------------------------------------------------------------
  4216. BOOL AECancelled(HANDLE hCancelEvent)
  4217. {
  4218. if(NULL==hCancelEvent)
  4219. return FALSE;
  4220. //test if the event is signalled
  4221. if(WAIT_OBJECT_0 == WaitForSingleObject(hCancelEvent, 0))
  4222. return TRUE;
  4223. return FALSE;
  4224. }
  4225. //-----------------------------------------------------------------------
  4226. //
  4227. // AEDoEnrollment
  4228. //
  4229. // return TRUE is no need to do another renewal.
  4230. // *pdwStatus contain the real enrollment status.
  4231. //
  4232. //-----------------------------------------------------------------------
  4233. BOOL AEDoEnrollment(HWND hwndParent,
  4234. HANDLE hCancelEvent,
  4235. BOOL fUIProcess,
  4236. DWORD dwLogLevel,
  4237. HANDLE hToken,
  4238. BOOL fMachine,
  4239. LPWSTR pwszMachineName,
  4240. AE_CERTTYPE_INFO *pCertType,
  4241. DWORD dwCA,
  4242. AE_CA_INFO *rgCAInfo,
  4243. DWORD *pdwStatus)
  4244. {
  4245. BOOL fResult = FALSE;
  4246. DWORD dwIndex = 0;
  4247. DWORD dwCAIndex = 0;
  4248. BOOL fRenewal = FALSE;
  4249. DWORD dwEventID = 0;
  4250. BOOL fFoundCA = FALSE;
  4251. DWORD idsSummary = 0; //keep the last failure case
  4252. DWORD dwLastError = 0;
  4253. CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO QueryCertRequestInfo;
  4254. HANDLE hRequest=NULL;
  4255. PCCERT_CONTEXT pCertContext=NULL;
  4256. //init the out parameter
  4257. *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR;
  4258. //detect if we are performing an enrollment or renewal
  4259. if((pCertType->fRenewal) && (pCertType->pOldCert))
  4260. {
  4261. if((pCertType->fNeedRA) && (pCertType->fCrossRA))
  4262. fRenewal=FALSE;
  4263. else
  4264. fRenewal=TRUE;
  4265. }
  4266. else
  4267. fRenewal=FALSE;
  4268. //loop through all the CAs
  4269. for(dwIndex =0; dwIndex < dwCA; dwIndex++)
  4270. {
  4271. dwCAIndex = (dwIndex + pCertType->dwRandomCAIndex) % dwCA;
  4272. if(AECancelled(hCancelEvent))
  4273. {
  4274. //no need to renew any more
  4275. fResult=TRUE;
  4276. //log that autoenrollment is cancelled
  4277. AELogAutoEnrollmentEvent(dwLogLevel,
  4278. FALSE,
  4279. S_OK,
  4280. EVENT_AUTOENROLL_CANCELLED,
  4281. fMachine,
  4282. hToken,
  4283. 0);
  4284. break;
  4285. }
  4286. //make sure the CA supports the specific template
  4287. if(!AEIsAnElement((pCertType->awszName)[0],
  4288. rgCAInfo[dwCAIndex].awszCertificateTemplate))
  4289. continue;
  4290. //make sure the CA's validity period of more than the renewing certificate
  4291. if(TRUE == fRenewal)
  4292. {
  4293. if(!AEIsCALonger(rgCAInfo[dwCAIndex].hCAInfo, pCertType->pOldCert))
  4294. continue;
  4295. }
  4296. //enroll to the CA
  4297. *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR;
  4298. fFoundCA = TRUE;
  4299. //create a certificate request
  4300. if(NULL==hRequest)
  4301. {
  4302. if(!AECreateEnrollmentRequest(hwndParent, fUIProcess, fMachine, pwszMachineName, pCertType, &(rgCAInfo[dwCAIndex]), &hRequest, &dwLastError))
  4303. {
  4304. //check if user cancelled the enrollment. If so, no
  4305. //need to try another CA.
  4306. if((HRESULT_FROM_WIN32(ERROR_CANCELLED) == dwLastError) ||
  4307. (SCARD_W_CANCELLED_BY_USER == dwLastError))
  4308. {
  4309. //no need to renewal anymore
  4310. fResult = TRUE;
  4311. //log that autoenrollment is cancelled
  4312. AELogAutoEnrollmentEvent(dwLogLevel,
  4313. FALSE,
  4314. S_OK,
  4315. EVENT_AUTOENROLL_CANCELLED_TEMPLATE,
  4316. fMachine,
  4317. hToken,
  4318. 1,
  4319. pCertType->awszDisplay[0]);
  4320. break;
  4321. }
  4322. else
  4323. {
  4324. idsSummary=IDS_SUMMARY_REQUEST;
  4325. if(CT_FLAG_REQUIRE_PRIVATE_KEY_ARCHIVAL & pCertType->dwPrivateKeyFlag)
  4326. {
  4327. //we have a chance of success with another CA
  4328. if(hRequest)
  4329. {
  4330. CryptUIWizFreeCertRequestNoDS(hRequest);
  4331. hRequest=NULL;
  4332. }
  4333. continue;
  4334. }
  4335. else
  4336. {
  4337. //we have no hope to create a request successfully
  4338. //mark dwIndex to the dwCA so that we will log an event at the end of the loop
  4339. dwIndex=dwCA;
  4340. break;
  4341. }
  4342. }
  4343. }
  4344. }
  4345. //check the cancel again because significant time can pass during
  4346. //request creation
  4347. if(AECancelled(hCancelEvent))
  4348. {
  4349. //no need to renew any more
  4350. fResult=TRUE;
  4351. //log that autoenrollment is cancelled
  4352. AELogAutoEnrollmentEvent(dwLogLevel,
  4353. FALSE,
  4354. S_OK,
  4355. EVENT_AUTOENROLL_CANCELLED,
  4356. fMachine,
  4357. hToken,
  4358. 0);
  4359. break;
  4360. }
  4361. if(CryptUIWizSubmitCertRequestNoDS(
  4362. hRequest,
  4363. hwndParent,
  4364. rgCAInfo[dwCAIndex].awszCAName[0],
  4365. rgCAInfo[dwCAIndex].awszCADNS[0],
  4366. pdwStatus,
  4367. &pCertContext))
  4368. {
  4369. //no need to try another CA if the request is successful or pending
  4370. if((CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED == (*pdwStatus)) ||
  4371. (CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNDER_SUBMISSION == (*pdwStatus))
  4372. )
  4373. {
  4374. //no need to renewal anymore
  4375. fResult = TRUE;
  4376. if(CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED == (*pdwStatus))
  4377. {
  4378. //we copy the certificate to publishing
  4379. if(pCertContext)
  4380. {
  4381. CertAddCertificateContextToStore(pCertType->hIssuedStore,
  4382. pCertContext,
  4383. CERT_STORE_ADD_USE_EXISTING,
  4384. NULL);
  4385. CertFreeCertificateContext(pCertContext);
  4386. pCertContext=NULL;
  4387. }
  4388. dwEventID=fRenewal ? EVENT_RENEWAL_SUCCESS_ONCE : EVENT_ENROLL_SUCCESS_ONCE;
  4389. }
  4390. else
  4391. {
  4392. dwEventID=fRenewal ? EVENT_RENEWAL_PENDING_ONCE : EVENT_ENROLL_PENDING_ONCE;
  4393. }
  4394. //log the enrollment sucess or pending event
  4395. AELogAutoEnrollmentEvent(dwLogLevel,
  4396. FALSE,
  4397. S_OK,
  4398. dwEventID,
  4399. fMachine,
  4400. hToken,
  4401. 3,
  4402. pCertType->awszDisplay[0],
  4403. rgCAInfo[dwCAIndex].awszCADisplay[0],
  4404. rgCAInfo[dwCAIndex].awszCADNS[0]);
  4405. //log if the private key is re-used
  4406. memset(&QueryCertRequestInfo, 0, sizeof(QueryCertRequestInfo));
  4407. QueryCertRequestInfo.dwSize=sizeof(QueryCertRequestInfo);
  4408. if(CryptUIWizQueryCertRequestNoDS(hRequest,
  4409. &QueryCertRequestInfo))
  4410. {
  4411. if(CRYPTUI_WIZ_QUERY_CERT_REQUEST_STATUS_CREATE_REUSED_PRIVATE_KEY &
  4412. (QueryCertRequestInfo.dwStatus))
  4413. {
  4414. AELogAutoEnrollmentEvent(dwLogLevel,
  4415. FALSE,
  4416. S_OK,
  4417. EVENT_PRIVATE_KEY_REUSED,
  4418. fMachine,
  4419. hToken,
  4420. 1,
  4421. pCertType->awszDisplay[0]);
  4422. }
  4423. }
  4424. break;
  4425. }
  4426. }
  4427. //get the last error
  4428. dwLastError=GetLastError();
  4429. idsSummary=IDS_SUMMARY_CA;
  4430. //log the one enrollment warning
  4431. AELogAutoEnrollmentEvent(dwLogLevel,
  4432. TRUE,
  4433. HRESULT_FROM_WIN32(dwLastError),
  4434. fRenewal ? EVENT_RENEWAL_FAIL_ONCE : EVENT_ENROLL_FAIL_ONCE,
  4435. fMachine,
  4436. hToken,
  4437. 3,
  4438. pCertType->awszDisplay[0],
  4439. rgCAInfo[dwCAIndex].awszCADisplay[0],
  4440. rgCAInfo[dwCAIndex].awszCADNS[0]);
  4441. //we should recreate the request for key archival
  4442. if(CT_FLAG_REQUIRE_PRIVATE_KEY_ARCHIVAL & pCertType->dwPrivateKeyFlag)
  4443. {
  4444. if(hRequest)
  4445. {
  4446. CryptUIWizFreeCertRequestNoDS(hRequest);
  4447. hRequest=NULL;
  4448. }
  4449. }
  4450. }
  4451. //log all enrollments error
  4452. //the loop will exit only if CANCEL, or SUCCEED, or we run out of CAs to try or
  4453. //the request can not be created
  4454. if(dwIndex == dwCA)
  4455. {
  4456. //we either run out of CAs to try or the request can not be created
  4457. if(0 != idsSummary)
  4458. pCertType->idsSummary=idsSummary;
  4459. if(fFoundCA)
  4460. {
  4461. dwEventID = fRenewal ? EVENT_RENEWAL_FAIL : EVENT_ENROLL_FAIL;
  4462. }
  4463. else
  4464. {
  4465. //if there is no CA, no need to try re-enrollment
  4466. if(fRenewal)
  4467. pCertType->fRenewal=FALSE;
  4468. dwEventID = fRenewal ? EVENT_RENEWAL_NO_CA_FAIL : EVENT_ENROLL_NO_CA_FAIL;
  4469. }
  4470. AELogAutoEnrollmentEvent(dwLogLevel,
  4471. fFoundCA ? TRUE : FALSE,
  4472. HRESULT_FROM_WIN32(dwLastError),
  4473. dwEventID,
  4474. fMachine,
  4475. hToken,
  4476. 1,
  4477. pCertType->awszDisplay[0]);
  4478. }
  4479. if(hRequest)
  4480. CryptUIWizFreeCertRequestNoDS(hRequest);
  4481. return fResult;
  4482. }
  4483. //-----------------------------------------------------------------------
  4484. //
  4485. // AEEnrollmentCertificates
  4486. //
  4487. //-----------------------------------------------------------------------
  4488. BOOL AEEnrollmentCertificates(AE_GENERAL_INFO *pAE_General_Info, DWORD dwEnrollStatus)
  4489. {
  4490. AE_CERTTYPE_INFO *rgCertTypeInfo = NULL;
  4491. DWORD dwIndex =0 ;
  4492. DWORD dwStatus= 0;
  4493. DWORD dwRandom = 0;
  4494. HCRYPTPROV hProv = NULL;
  4495. rgCertTypeInfo = pAE_General_Info->rgCertTypeInfo;
  4496. if(NULL == rgCertTypeInfo)
  4497. return FALSE;
  4498. if((0 == pAE_General_Info->dwCA) || (NULL==pAE_General_Info->rgCAInfo))
  4499. return FALSE;
  4500. if(!CryptAcquireContextW(&hProv,
  4501. NULL,
  4502. MS_DEF_PROV_W,
  4503. PROV_RSA_FULL,
  4504. CRYPT_VERIFYCONTEXT))
  4505. hProv=NULL;
  4506. //going through all the active requests
  4507. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  4508. {
  4509. //we enroll/renew for templates that are active
  4510. if(dwEnrollStatus != rgCertTypeInfo[dwIndex].dwStatus)
  4511. continue;
  4512. if(pAE_General_Info->fUIProcess != rgCertTypeInfo[dwIndex].fUIActive)
  4513. continue;
  4514. //select a random CA index to balance the load
  4515. if((hProv) && (CryptGenRandom(hProv, sizeof(dwRandom), (BYTE *)(&dwRandom))))
  4516. {
  4517. rgCertTypeInfo[dwIndex].dwRandomCAIndex = dwRandom % (pAE_General_Info->dwCA);
  4518. }
  4519. else
  4520. rgCertTypeInfo[dwIndex].dwRandomCAIndex = 0;
  4521. //enroll
  4522. dwStatus=0;
  4523. //report progress
  4524. if(pAE_General_Info->fUIProcess)
  4525. {
  4526. //continue if user choose CANCEL in view RA dialogue
  4527. if(!AEUIProgressReport(FALSE, &(rgCertTypeInfo[dwIndex]),pAE_General_Info->hwndDlg, pAE_General_Info->hCancelEvent))
  4528. {
  4529. AEUIProgressAdvance(pAE_General_Info);
  4530. continue;
  4531. }
  4532. }
  4533. if(AEDoEnrollment( pAE_General_Info->hwndDlg ? pAE_General_Info->hwndDlg : pAE_General_Info->hwndParent,
  4534. pAE_General_Info->hCancelEvent,
  4535. pAE_General_Info->fUIProcess,
  4536. pAE_General_Info->dwLogLevel,
  4537. pAE_General_Info->hToken,
  4538. pAE_General_Info->fMachine,
  4539. pAE_General_Info->wszMachineName,
  4540. &(rgCertTypeInfo[dwIndex]),
  4541. pAE_General_Info->dwCA,
  4542. pAE_General_Info->rgCAInfo,
  4543. &dwStatus))
  4544. {
  4545. //mark the status
  4546. if(CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED == dwStatus)
  4547. rgCertTypeInfo[dwIndex].dwStatus=CERT_REQUEST_STATUS_OBTAINED;
  4548. }
  4549. else
  4550. {
  4551. //if renewal failed, we try to re-enrollment if no RA is required
  4552. if((rgCertTypeInfo[dwIndex].fRenewal) && (FALSE == (rgCertTypeInfo[dwIndex].fNeedRA)))
  4553. {
  4554. rgCertTypeInfo[dwIndex].fRenewal=FALSE;
  4555. dwStatus=0;
  4556. if(AEDoEnrollment( pAE_General_Info->hwndDlg ? pAE_General_Info->hwndDlg : pAE_General_Info->hwndParent,
  4557. pAE_General_Info->hCancelEvent,
  4558. pAE_General_Info->fUIProcess,
  4559. pAE_General_Info->dwLogLevel,
  4560. pAE_General_Info->hToken,
  4561. pAE_General_Info->fMachine,
  4562. pAE_General_Info->wszMachineName,
  4563. &(rgCertTypeInfo[dwIndex]),
  4564. pAE_General_Info->dwCA,
  4565. pAE_General_Info->rgCAInfo,
  4566. &dwStatus))
  4567. {
  4568. //mark the status
  4569. if(CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED == dwStatus)
  4570. rgCertTypeInfo[dwIndex].dwStatus=CERT_REQUEST_STATUS_OBTAINED;
  4571. }
  4572. }
  4573. }
  4574. //advance progress
  4575. if(pAE_General_Info->fUIProcess)
  4576. {
  4577. AEUIProgressAdvance(pAE_General_Info);
  4578. }
  4579. }
  4580. if(hProv)
  4581. CryptReleaseContext(hProv, 0);
  4582. return TRUE;
  4583. }
  4584. //-----------------------------------------------------------------------
  4585. //
  4586. // AEIsDeletableCert
  4587. // Decide if we should archive or delete the certificate
  4588. //
  4589. //-----------------------------------------------------------------------
  4590. BOOL AEIsDeletableCert(PCCERT_CONTEXT pCertContext, AE_GENERAL_INFO *pAE_General_Info)
  4591. {
  4592. AE_CERTTYPE_INFO *pCertType=NULL;
  4593. BOOL fDelete=FALSE;
  4594. AE_TEMPLATE_INFO AETemplateInfo;
  4595. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  4596. //only interested in certificate with template information
  4597. if(!AERetrieveTemplateInfo(pCertContext, &AETemplateInfo))
  4598. goto Ret;
  4599. pCertType=AEFindTemplateInRequestTree(&AETemplateInfo, pAE_General_Info);
  4600. if(NULL==pCertType)
  4601. goto Ret;
  4602. if(CT_FLAG_REMOVE_INVALID_CERTIFICATE_FROM_PERSONAL_STORE & (pCertType->dwEnrollmentFlag))
  4603. fDelete=TRUE;
  4604. else
  4605. fDelete=FALSE;
  4606. Ret:
  4607. AEFreeTemplateInfo(&AETemplateInfo);
  4608. return fDelete;
  4609. }
  4610. //-----------------------------------------------------------------------
  4611. //
  4612. // AEIsSupersedeTemplate
  4613. //
  4614. // Check if pArchiveCert is superseded by pCertType
  4615. //
  4616. //-----------------------------------------------------------------------
  4617. BOOL AEIsSupersedeTemplate(PCCERT_CONTEXT pArchiveCert, AE_CERTTYPE_INFO *pCertType, AE_GENERAL_INFO *pAE_General_Info)
  4618. {
  4619. BOOL fSuperSede=FALSE;
  4620. AE_TEMPLATE_INFO AETemplateInfo;
  4621. AE_CERTTYPE_INFO *pArchiveCertType=NULL;
  4622. LPWSTR *awszSuperseding=NULL;
  4623. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  4624. //only interested in certificate with template information
  4625. if(!AERetrieveTemplateInfo(pArchiveCert, &AETemplateInfo))
  4626. goto Ret;
  4627. pArchiveCertType=AEFindTemplateInRequestTree(&AETemplateInfo, pAE_General_Info);
  4628. if(NULL==pArchiveCertType)
  4629. goto Ret;
  4630. //clear the visited flag in AE_General_Info
  4631. AEClearVistedFlag(pAE_General_Info);
  4632. if(S_OK == CAGetCertTypePropertyEx(
  4633. pCertType->hCertType,
  4634. CERTTYPE_PROP_SUPERSEDE,
  4635. &(awszSuperseding)))
  4636. {
  4637. if(awszSuperseding && awszSuperseding[0])
  4638. {
  4639. if(AEIfSupersede(pArchiveCertType->awszName[0], awszSuperseding, pAE_General_Info))
  4640. {
  4641. fSuperSede=TRUE;
  4642. }
  4643. //clear the visited flag in AE_General_Info
  4644. AEClearVistedFlag(pAE_General_Info);
  4645. }
  4646. //free the property
  4647. if(awszSuperseding)
  4648. CAFreeCertTypeProperty(pCertType->hCertType, awszSuperseding);
  4649. }
  4650. Ret:
  4651. AEFreeTemplateInfo(&AETemplateInfo);
  4652. return fSuperSede;
  4653. }
  4654. //-----------------------------------------------------------------------
  4655. //
  4656. // AEIsSameTemplate
  4657. //
  4658. // Check if the certificate is of the same template of pCertType
  4659. //
  4660. //-----------------------------------------------------------------------
  4661. BOOL AEIsSameTemplate(PCCERT_CONTEXT pCertContext, AE_CERTTYPE_INFO *pCertType, BOOL fVersionCheck)
  4662. {
  4663. BOOL fSame=FALSE;
  4664. AE_TEMPLATE_INFO AETemplateInfo;
  4665. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  4666. if((NULL == pCertType) || (NULL == pCertContext))
  4667. goto Ret;
  4668. //get the template information for the certificate
  4669. if(!AERetrieveTemplateInfo(pCertContext, &AETemplateInfo))
  4670. goto Ret;
  4671. if( (NULL == AETemplateInfo.pwszName) && (NULL == AETemplateInfo.pwszOid))
  4672. goto Ret;
  4673. if(AETemplateInfo.pwszOid)
  4674. {
  4675. //we are guaranteed to have an OID if the schema is greater than or equal to 2
  4676. if(pCertType->dwSchemaVersion >= CERTTYPE_SCHEMA_VERSION_2)
  4677. {
  4678. if(0 == wcscmp(AETemplateInfo.pwszOid, (pCertType->awszOID)[0]))
  4679. {
  4680. if(fVersionCheck)
  4681. {
  4682. if(AETemplateInfo.dwVersion == pCertType->dwVersion)
  4683. {
  4684. fSame=TRUE;
  4685. }
  4686. }
  4687. else
  4688. {
  4689. fSame=TRUE;
  4690. }
  4691. }
  4692. }
  4693. }
  4694. else
  4695. {
  4696. //we are guaranteed to have a name
  4697. if(0 == wcscmp(AETemplateInfo.pwszName, (pCertType->awszName)[0]))
  4698. {
  4699. fSame=TRUE;
  4700. }
  4701. }
  4702. Ret:
  4703. AEFreeTemplateInfo(&AETemplateInfo);
  4704. return fSame;
  4705. }
  4706. //-----------------------------------------------------------------------
  4707. //
  4708. // AEArchiveObsoleteCertificates
  4709. // archive old certificate after the enrollment/renewal
  4710. //
  4711. // clean up the hUserDS store (delete the expired or revoked certificate)
  4712. //-----------------------------------------------------------------------
  4713. BOOL AEArchiveObsoleteCertificates(AE_GENERAL_INFO *pAE_General_Info)
  4714. {
  4715. AE_CERTTYPE_INFO *rgCertTypeInfo = NULL;
  4716. DWORD dwIndex = 0;
  4717. CRYPT_DATA_BLOB Archived;
  4718. BOOL fArchived = FALSE;
  4719. BOOL fDSArchived = FALSE;
  4720. AE_CERT_INFO AECertInfo;
  4721. BOOL fRepublish=FALSE;
  4722. BYTE rgbHash[SHA1_HASH_LENGTH];
  4723. CRYPT_HASH_BLOB blobHash;
  4724. BOOL fHash=FALSE;
  4725. DWORD dwOpenStoreFlags = CERT_SYSTEM_STORE_CURRENT_USER;
  4726. DWORD dwProp=CERT_ARCHIVED_PROP_ID;
  4727. BOOL fSameDns=TRUE;
  4728. HCERTSTORE hUserDS = NULL;
  4729. HCERTSTORE hMyArchive = NULL;
  4730. PCCERT_CONTEXT pCertContext = NULL;
  4731. PCCERT_CONTEXT pMyContext = NULL;
  4732. PCCERT_CONTEXT pDSContext = NULL;
  4733. PCCERT_CONTEXT pIssuedContext = NULL;
  4734. PCCERT_CONTEXT pDnsContext = NULL;
  4735. PCCERT_CONTEXT pDnsOldContext = NULL;
  4736. PCCERT_CONTEXT pSelectedContext = NULL;
  4737. PCCERT_CONTEXT pMyDnsContext = NULL;
  4738. PCCERT_CONTEXT pMyArchiveCert = NULL;
  4739. rgCertTypeInfo = pAE_General_Info->rgCertTypeInfo;
  4740. if(NULL == rgCertTypeInfo)
  4741. return FALSE;
  4742. memset(&Archived, 0, sizeof(CRYPT_DATA_BLOB));
  4743. memset(&AECertInfo, 0, sizeof(AE_CERT_INFO));
  4744. //open the UserDS store
  4745. if(!(pAE_General_Info->fMachine))
  4746. {
  4747. hUserDS = AEOpenUserDSStore(pAE_General_Info, 0);
  4748. }
  4749. //verify the DNS name of issued certificate.
  4750. //mark the CERT_AUTO_ENROLL_RETRY_PROP_ID property
  4751. if(pAE_General_Info->fMachine)
  4752. {
  4753. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  4754. {
  4755. if(CERT_REQUEST_STATUS_OBTAINED == rgCertTypeInfo[dwIndex].dwStatus)
  4756. {
  4757. if(rgCertTypeInfo[dwIndex].hIssuedStore)
  4758. {
  4759. if(pDnsContext = CertEnumCertificatesInStore(
  4760. rgCertTypeInfo[dwIndex].hIssuedStore, NULL))
  4761. {
  4762. pMyDnsContext = FindCertificateInOtherStore(
  4763. pAE_General_Info->hMyStore,
  4764. pDnsContext);
  4765. if(pMyDnsContext)
  4766. {
  4767. //detect if DSN name match
  4768. if(AEVerifyDNSName(pAE_General_Info, pMyDnsContext))
  4769. {
  4770. //the DNS name match;
  4771. //clear the CERT_AUTO_ENROLL_RETRY_PROP_ID property
  4772. CertSetCertificateContextProperty(
  4773. pMyDnsContext,
  4774. CERT_AUTO_ENROLL_RETRY_PROP_ID,
  4775. 0,
  4776. NULL);
  4777. }
  4778. else
  4779. {
  4780. fSameDns=TRUE;
  4781. pDnsOldContext=NULL;
  4782. pSelectedContext=NULL;
  4783. while(pDnsOldContext = CertEnumCertificatesInStore(
  4784. rgCertTypeInfo[dwIndex].hArchiveStore, pDnsOldContext))
  4785. {
  4786. //only consider same template scenario for retrial purpose
  4787. //only consider certificates with same version
  4788. if(AEIsSameTemplate(pDnsOldContext, &(rgCertTypeInfo[dwIndex]), TRUE))
  4789. {
  4790. if(!AEIsSameDNS(pMyDnsContext, pDnsOldContext))
  4791. {
  4792. fSameDns=FALSE;
  4793. CertFreeCertificateContext(pDnsOldContext);
  4794. pDnsOldContext=NULL;
  4795. break;
  4796. }
  4797. else
  4798. {
  4799. if(NULL == pSelectedContext)
  4800. {
  4801. pSelectedContext=CertDuplicateCertificateContext(pDnsOldContext);
  4802. }
  4803. else
  4804. {
  4805. //we use the least retrial wait amoung all old DNS certificates
  4806. //of the same certificate template
  4807. if(!AEFasterRetrialSchedule(pSelectedContext, pDnsOldContext))
  4808. {
  4809. CertFreeCertificateContext(pSelectedContext);
  4810. pSelectedContext = NULL;
  4811. pSelectedContext=CertDuplicateCertificateContext(pDnsOldContext);
  4812. }
  4813. }
  4814. }
  4815. }
  4816. }
  4817. //start over again if the DNS from the new certificate is
  4818. //different from existing ones or this is the 1st time
  4819. //a mis-match DNS has occurred
  4820. if((NULL == pSelectedContext) || (FALSE == fSameDns))
  4821. {
  4822. //clear the CERT_AUTO_ENROLL_RETRY_PROP_ID property
  4823. CertSetCertificateContextProperty(
  4824. pMyDnsContext,
  4825. CERT_AUTO_ENROLL_RETRY_PROP_ID,
  4826. 0,
  4827. NULL);
  4828. }
  4829. else
  4830. {
  4831. AEUpdateRetryProperty(pAE_General_Info, (rgCertTypeInfo[dwIndex].awszDisplay)[0], pMyDnsContext, pSelectedContext);
  4832. }
  4833. if(pSelectedContext)
  4834. {
  4835. CertFreeCertificateContext(pSelectedContext);
  4836. pSelectedContext = NULL;
  4837. }
  4838. }
  4839. CertFreeCertificateContext(pMyDnsContext);
  4840. pMyDnsContext = NULL;
  4841. }
  4842. CertFreeCertificateContext(pDnsContext);
  4843. pDnsContext = NULL;
  4844. }
  4845. }
  4846. }
  4847. }
  4848. }
  4849. //archive certificates
  4850. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  4851. {
  4852. fHash=FALSE;
  4853. fRepublish=FALSE;
  4854. if(CERT_REQUEST_STATUS_OBTAINED == rgCertTypeInfo[dwIndex].dwStatus)
  4855. {
  4856. //get the hash of newly enrolled certificate
  4857. blobHash.cbData=SHA1_HASH_LENGTH;
  4858. blobHash.pbData=rgbHash;
  4859. if(rgCertTypeInfo[dwIndex].hIssuedStore)
  4860. {
  4861. if(pIssuedContext = CertEnumCertificatesInStore(
  4862. rgCertTypeInfo[dwIndex].hIssuedStore, NULL))
  4863. {
  4864. if(CryptHashCertificate(
  4865. NULL,
  4866. 0,
  4867. X509_ASN_ENCODING,
  4868. pIssuedContext->pbCertEncoded,
  4869. pIssuedContext->cbCertEncoded,
  4870. blobHash.pbData,
  4871. &(blobHash.cbData)))
  4872. {
  4873. fHash=TRUE;
  4874. }
  4875. }
  4876. //free the cert context
  4877. if(pIssuedContext)
  4878. {
  4879. CertFreeCertificateContext(pIssuedContext);
  4880. pIssuedContext = NULL;
  4881. }
  4882. }
  4883. pCertContext=NULL;
  4884. while(pCertContext = CertEnumCertificatesInStore(
  4885. rgCertTypeInfo[dwIndex].hArchiveStore, pCertContext))
  4886. {
  4887. //archive or delete the certificate from my store
  4888. pMyContext = FindCertificateInOtherStore(
  4889. pAE_General_Info->hMyStore,
  4890. pCertContext);
  4891. if(pMyContext)
  4892. {
  4893. //set the Hash of the newly enrolled certificate
  4894. if(fHash)
  4895. {
  4896. CertSetCertificateContextProperty(
  4897. pMyContext,
  4898. CERT_RENEWAL_PROP_ID,
  4899. 0,
  4900. &blobHash);
  4901. }
  4902. if(AEIsDeletableCert(pMyContext, pAE_General_Info))
  4903. {
  4904. CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pMyContext));
  4905. }
  4906. else
  4907. {
  4908. // We force an archive on the old cert and close it.
  4909. CertSetCertificateContextProperty(pMyContext,
  4910. CERT_ARCHIVED_PROP_ID,
  4911. 0,
  4912. &Archived);
  4913. }
  4914. fArchived=TRUE;
  4915. CertFreeCertificateContext(pMyContext);
  4916. pMyContext = NULL;
  4917. }
  4918. //check the DS store. remove the certificates from DS store
  4919. if(hUserDS)
  4920. {
  4921. if(pMyContext = FindCertificateInOtherStore(
  4922. hUserDS,
  4923. pCertContext))
  4924. {
  4925. CertDeleteCertificateFromStore(pMyContext);
  4926. fDSArchived=TRUE;
  4927. pMyContext = NULL;
  4928. fRepublish=TRUE;
  4929. }
  4930. }
  4931. }
  4932. }
  4933. }
  4934. //we remove archived certificates from my store
  4935. //open my store with CERT_STORE_ENUM_ARCHIVED_FLAG
  4936. if(pAE_General_Info->fMachine)
  4937. dwOpenStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  4938. //open my store
  4939. hMyArchive= CertOpenStore(
  4940. CERT_STORE_PROV_SYSTEM_W,
  4941. ENCODING_TYPE,
  4942. NULL,
  4943. dwOpenStoreFlags | CERT_STORE_ENUM_ARCHIVED_FLAG,
  4944. MY_STORE);
  4945. //loop through all templates
  4946. if(hMyArchive)
  4947. {
  4948. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  4949. {
  4950. if(CERT_REQUEST_STATUS_OBTAINED == rgCertTypeInfo[dwIndex].dwStatus)
  4951. {
  4952. //loop through all archived certificates and remove certificates of same template
  4953. //or certificates that are superseded
  4954. pMyArchiveCert=NULL;
  4955. while(pMyArchiveCert=CertFindCertificateInStore(
  4956. hMyArchive, ENCODING_TYPE, 0, CERT_FIND_PROPERTY, &dwProp, pMyArchiveCert))
  4957. {
  4958. if(AEIsSameTemplate(pMyArchiveCert, &(rgCertTypeInfo[dwIndex]), FALSE))
  4959. {
  4960. if(CT_FLAG_REMOVE_INVALID_CERTIFICATE_FROM_PERSONAL_STORE & rgCertTypeInfo[dwIndex].dwEnrollmentFlag)
  4961. {
  4962. CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pMyArchiveCert));
  4963. fArchived=TRUE;
  4964. }
  4965. }
  4966. else
  4967. {
  4968. if(AEIsDeletableCert(pMyArchiveCert, pAE_General_Info))
  4969. {
  4970. if(AEIsSupersedeTemplate(pMyArchiveCert, &(rgCertTypeInfo[dwIndex]), pAE_General_Info))
  4971. {
  4972. CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pMyArchiveCert));
  4973. fArchived=TRUE;
  4974. }
  4975. }
  4976. }
  4977. }
  4978. }
  4979. }
  4980. }
  4981. //now we are done with archiving, we clean up user DS store
  4982. if(AUTO_ENROLLMENT_ENABLE_MY_STORE_MANAGEMENT & (pAE_General_Info->dwPolicy))
  4983. {
  4984. if(hUserDS)
  4985. {
  4986. pDSContext=NULL;
  4987. while(pDSContext = CertEnumCertificatesInStore(hUserDS, pDSContext))
  4988. {
  4989. AEValidateCertificateInfo(pAE_General_Info,
  4990. NULL, //do not evaluate soon to expire
  4991. FALSE, //do not valid private key
  4992. pDSContext,
  4993. &AECertInfo);
  4994. if(FALSE == AECertInfo.fRenewal)
  4995. {
  4996. CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pDSContext));
  4997. fDSArchived=TRUE;
  4998. fRepublish=TRUE;
  4999. }
  5000. memset(&AECertInfo, 0, sizeof(AE_CERT_INFO));
  5001. }
  5002. }
  5003. }
  5004. //we have to republish the certificates as we have rewritten the user DS store
  5005. //CA might has just published to the location
  5006. if(fRepublish)
  5007. {
  5008. if(hUserDS)
  5009. {
  5010. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  5011. {
  5012. if(CERT_REQUEST_STATUS_OBTAINED == rgCertTypeInfo[dwIndex].dwStatus)
  5013. {
  5014. if((rgCertTypeInfo[dwIndex].hIssuedStore) &&
  5015. (CT_FLAG_PUBLISH_TO_DS & rgCertTypeInfo[dwIndex].dwEnrollmentFlag)
  5016. )
  5017. {
  5018. pCertContext=NULL;
  5019. while(pCertContext = CertEnumCertificatesInStore(
  5020. rgCertTypeInfo[dwIndex].hIssuedStore, pCertContext))
  5021. {
  5022. CertAddCertificateContextToStore(hUserDS,
  5023. pCertContext,
  5024. CERT_STORE_ADD_USE_EXISTING,
  5025. NULL);
  5026. }
  5027. }
  5028. }
  5029. }
  5030. }
  5031. }
  5032. //report the event if archival has happened
  5033. if(fArchived)
  5034. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_ARCHIVE_CERT,
  5035. pAE_General_Info->fMachine, pAE_General_Info->hToken, 0);
  5036. if(fDSArchived)
  5037. AELogAutoEnrollmentEvent(pAE_General_Info->dwLogLevel, FALSE, S_OK, EVENT_ARCHIVE_DS_CERT,
  5038. pAE_General_Info->fMachine, pAE_General_Info->hToken, 0);
  5039. if(hUserDS)
  5040. CertCloseStore(hUserDS, 0);
  5041. if(hMyArchive)
  5042. CertCloseStore(hMyArchive, 0);
  5043. return TRUE;
  5044. }
  5045. //-----------------------------------------------------------------------
  5046. //
  5047. // AERemoveSupersedeActive
  5048. // Remove supersedeActive flag after any successful the enrollment/renewal
  5049. //
  5050. //-----------------------------------------------------------------------
  5051. BOOL AERemoveSupersedeActive(AE_GENERAL_INFO *pAE_General_Info)
  5052. {
  5053. AE_CERTTYPE_INFO *rgCertTypeInfo = NULL;
  5054. DWORD dwIndex = 0;
  5055. DWORD dwActiveIndex = 0;
  5056. DWORD dwMarkIndex = 0;
  5057. rgCertTypeInfo = pAE_General_Info->rgCertTypeInfo;
  5058. if(NULL == rgCertTypeInfo)
  5059. return FALSE;
  5060. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  5061. {
  5062. if(CERT_REQUEST_STATUS_OBTAINED == rgCertTypeInfo[dwIndex].dwStatus)
  5063. {
  5064. for(dwActiveIndex=0; dwActiveIndex < rgCertTypeInfo[dwIndex].dwActive; dwActiveIndex++)
  5065. {
  5066. dwMarkIndex = rgCertTypeInfo[dwIndex].prgActive[dwActiveIndex];
  5067. rgCertTypeInfo[dwMarkIndex].dwStatus=CERT_REQUEST_STATUS_OBTAINED;
  5068. }
  5069. }
  5070. }
  5071. return TRUE;
  5072. }
  5073. //-----------------------------------------------------------------------
  5074. //
  5075. // AEEnrollmentWalker
  5076. //
  5077. // This functin performs enrollment tasks
  5078. //
  5079. //
  5080. //-----------------------------------------------------------------------
  5081. BOOL AEEnrollmentWalker(AE_GENERAL_INFO *pAE_General_Info)
  5082. {
  5083. BOOL fResult = FALSE;
  5084. //we need to set the range for the progress bar in the
  5085. //UI case
  5086. if((pAE_General_Info->fUIProcess) && (pAE_General_Info->hwndDlg))
  5087. {
  5088. //set the range
  5089. if(0 != (pAE_General_Info->dwUIEnrollCount))
  5090. {
  5091. SendMessage(GetDlgItem(pAE_General_Info->hwndDlg, IDC_ENROLL_PROGRESS),
  5092. PBM_SETRANGE,
  5093. 0,
  5094. MAKELPARAM(0, ((pAE_General_Info->dwUIEnrollCount) & (0xFFFF)))
  5095. );
  5096. SendMessage(GetDlgItem(pAE_General_Info->hwndDlg, IDC_ENROLL_PROGRESS),
  5097. PBM_SETSTEP,
  5098. (WPARAM)1,
  5099. 0);
  5100. SendMessage(GetDlgItem(pAE_General_Info->hwndDlg, IDC_ENROLL_PROGRESS),
  5101. PBM_SETPOS,
  5102. (WPARAM)0,
  5103. 0);
  5104. }
  5105. }
  5106. //retrieve the pending request. Mark the status to obtained if the
  5107. //certificate is issued and of the correct version
  5108. if(AUTO_ENROLLMENT_ENABLE_PENDING_FETCH & (pAE_General_Info->dwPolicy))
  5109. {
  5110. if(FALSE == pAE_General_Info->fUIProcess)
  5111. {
  5112. if(!AEProcessPendingRequest(pAE_General_Info))
  5113. goto Ret;
  5114. }
  5115. else
  5116. {
  5117. if(!AEProcessUIPendingRequest(pAE_General_Info))
  5118. goto Ret;
  5119. }
  5120. }
  5121. //remove duplicated requests based on "Supersede" relationship
  5122. //supress active templates that are superseded by other templates
  5123. if(!AEManageSupersedeRequests(pAE_General_Info))
  5124. goto Ret;
  5125. //do enrollment/renewal
  5126. if(!AEEnrollmentCertificates(pAE_General_Info, CERT_REQUEST_STATUS_ACTIVE))
  5127. goto Ret;
  5128. //We try to get the superseded templates if supserseding templates failed.
  5129. //Only for machine for the case of two V2 DC templates.
  5130. /*if(TRUE == pAE_General_Info->fMachine)
  5131. {
  5132. //remove supersedeActive based on the obtained flag
  5133. if(!AERemoveSupersedeActive(pAE_General_Info))
  5134. goto Ret;
  5135. //do enrollment/renewal again since we migh fail to get superseding templates
  5136. if(!AEEnrollmentCertificates(pAE_General_Info, CERT_REQUEST_STATUS_SUPERSEDE_ACTIVE))
  5137. goto Ret;
  5138. }*/
  5139. fResult = TRUE;
  5140. Ret:
  5141. return fResult;
  5142. }
  5143. //-----------------------------------------------------------------------------
  5144. //
  5145. // AEUIProgressAdvance
  5146. //
  5147. // Increase the progress bar by one step
  5148. //-----------------------------------------------------------------------------
  5149. BOOL AEUIProgressAdvance(AE_GENERAL_INFO *pAE_General_Info)
  5150. {
  5151. BOOL fResult=FALSE;
  5152. if(NULL==pAE_General_Info)
  5153. goto Ret;
  5154. if(NULL==(pAE_General_Info->hwndDlg))
  5155. goto Ret;
  5156. //check if CANCEL button is clicked
  5157. if(AECancelled(pAE_General_Info->hCancelEvent))
  5158. {
  5159. fResult=TRUE;
  5160. goto Ret;
  5161. }
  5162. //advance the progress bar
  5163. SendMessage(GetDlgItem(pAE_General_Info->hwndDlg, IDC_ENROLL_PROGRESS),
  5164. PBM_STEPIT,
  5165. 0,
  5166. 0);
  5167. fResult=TRUE;
  5168. Ret:
  5169. return fResult;
  5170. }
  5171. //-----------------------------------------------------------------------------
  5172. //
  5173. // AEUIGetNameFromCert
  5174. //
  5175. // Retrieve a unique string to identify the certificate.
  5176. //-----------------------------------------------------------------------------
  5177. BOOL AEUIGetNameFromCert(PCCERT_CONTEXT pCertContext, LPWSTR *ppwszRACert)
  5178. {
  5179. BOOL fResult=FALSE;
  5180. DWORD dwChar=0;
  5181. DWORD cbOID=0;
  5182. PCCRYPT_OID_INFO pOIDInfo=NULL;
  5183. LPWSTR pwszRACert=NULL;
  5184. AE_TEMPLATE_INFO TemplateInfo;
  5185. LPSTR szOID=NULL;
  5186. if((NULL==pCertContext) || (NULL==ppwszRACert))
  5187. goto Ret;
  5188. *ppwszRACert=NULL;
  5189. memset(&TemplateInfo, 0, sizeof(TemplateInfo));
  5190. //get the template name first
  5191. if(!AERetrieveTemplateInfo(pCertContext, &TemplateInfo))
  5192. goto Ret;
  5193. if(TemplateInfo.pwszName)
  5194. {
  5195. pwszRACert=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (wcslen(TemplateInfo.pwszName) + 1));
  5196. if(NULL == pwszRACert)
  5197. goto Ret;
  5198. wcscpy(pwszRACert, TemplateInfo.pwszName);
  5199. }
  5200. else
  5201. {
  5202. if(NULL==(TemplateInfo.pwszOid))
  5203. goto Ret;
  5204. //find the OID
  5205. if(0 == (cbOID = WideCharToMultiByte(CP_ACP,
  5206. 0,
  5207. TemplateInfo.pwszOid,
  5208. -1,
  5209. NULL,
  5210. 0,
  5211. NULL,
  5212. NULL)))
  5213. goto Ret;
  5214. szOID=(LPSTR)LocalAlloc(LPTR, cbOID);
  5215. if(NULL==szOID)
  5216. goto Ret;
  5217. if(0 == WideCharToMultiByte(CP_ACP,
  5218. 0,
  5219. TemplateInfo.pwszOid,
  5220. -1,
  5221. szOID,
  5222. cbOID,
  5223. NULL,
  5224. NULL))
  5225. goto Ret;
  5226. pOIDInfo=CryptFindOIDInfo(
  5227. CRYPT_OID_INFO_OID_KEY,
  5228. szOID,
  5229. CRYPT_TEMPLATE_OID_GROUP_ID);
  5230. if(pOIDInfo)
  5231. {
  5232. if(pOIDInfo->pwszName)
  5233. {
  5234. pwszRACert=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (wcslen(pOIDInfo->pwszName) + 1));
  5235. if(NULL== pwszRACert)
  5236. goto Ret;
  5237. wcscpy(pwszRACert, pOIDInfo->pwszName);
  5238. }
  5239. }
  5240. }
  5241. //if template name does not exist. Get the subject name for now
  5242. /* if(NULL==pwszRACert)
  5243. {
  5244. if(0 == (dwChar=CertGetNameStringW(
  5245. pCertContext,
  5246. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  5247. 0,
  5248. NULL,
  5249. NULL,
  5250. 0)))
  5251. goto Ret;
  5252. pwszRACert=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (dwChar));
  5253. if(NULL== pwszRACert)
  5254. goto Ret;
  5255. if(0 == (dwChar=CertGetNameStringW(
  5256. pCertContext,
  5257. CERT_NAME_SIMPLE_DISPLAY_TYPE,
  5258. 0,
  5259. NULL,
  5260. pwszRACert,
  5261. dwChar)))
  5262. goto Ret;
  5263. } */
  5264. *ppwszRACert = pwszRACert;
  5265. pwszRACert=NULL;
  5266. fResult=TRUE;
  5267. Ret:
  5268. if(pwszRACert)
  5269. LocalFree(pwszRACert);
  5270. if(szOID)
  5271. LocalFree(szOID);
  5272. AEFreeTemplateInfo(&TemplateInfo);
  5273. return fResult;
  5274. }
  5275. //-----------------------------------------------------------------------------
  5276. //
  5277. // AEGetRACertInfo
  5278. //
  5279. //-----------------------------------------------------------------------------
  5280. BOOL AEGetRACertInfo(PCERT_CONTEXT pRAContext,
  5281. LPWSTR pwszRATemplate,
  5282. LPWSTR *ppwszRACertInfo)
  5283. {
  5284. BOOL fResult=FALSE;
  5285. UINT idsMessage=0;
  5286. DWORD dwSize=0;
  5287. LPWSTR pwszIssuer=NULL;
  5288. if(NULL==pRAContext)
  5289. goto Ret;
  5290. if(pwszRATemplate)
  5291. idsMessage=IDS_VIEW_RA_INFO;
  5292. else
  5293. idsMessage=IDS_VIEW_RA_INFO_GENERAL;
  5294. //the cert has to have an issuer
  5295. if(0 == (dwSize=CertNameToStrW(
  5296. ENCODING_TYPE,
  5297. &(pRAContext->pCertInfo->Issuer),
  5298. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  5299. NULL,
  5300. 0)))
  5301. goto Ret;
  5302. pwszIssuer=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * dwSize);
  5303. if(NULL==pwszIssuer)
  5304. goto Ret;
  5305. if(0 == CertNameToStrW(
  5306. ENCODING_TYPE,
  5307. &(pRAContext->pCertInfo->Issuer),
  5308. CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
  5309. pwszIssuer,
  5310. dwSize))
  5311. goto Ret;
  5312. if(!FormatMessageUnicode(
  5313. ppwszRACertInfo,
  5314. idsMessage,
  5315. pwszIssuer,
  5316. pwszRATemplate))
  5317. goto Ret;
  5318. fResult=TRUE;
  5319. Ret:
  5320. if(pwszIssuer)
  5321. LocalFree(pwszIssuer);
  5322. return fResult;
  5323. }
  5324. //-----------------------------------------------------------------------------
  5325. //
  5326. // WinProc for the view RA certificate dialogue
  5327. //
  5328. //-----------------------------------------------------------------------------
  5329. INT_PTR CALLBACK AEViewRADlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  5330. {
  5331. BOOL fPropertyChanged = FALSE;
  5332. AE_VIEW_RA_INFO *pAEViewRAInfo = NULL;
  5333. CRYPTUI_VIEWCERTIFICATE_STRUCT CertViewStruct;
  5334. LPWSTR pwszRACertInfo=NULL;
  5335. switch (msg)
  5336. {
  5337. case WM_INITDIALOG:
  5338. pAEViewRAInfo=(AE_VIEW_RA_INFO *)lParam;
  5339. if(NULL==pAEViewRAInfo)
  5340. break;
  5341. SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pAEViewRAInfo);
  5342. //display the RA template and issuer dynamically
  5343. if(AEGetRACertInfo(pAEViewRAInfo->pRAContext,
  5344. pAEViewRAInfo->pwszRATemplate,
  5345. &pwszRACertInfo))
  5346. {
  5347. SetDlgItemTextW(hwndDlg, IDC_EDIT3, pwszRACertInfo);
  5348. LocalFree((HLOCAL)pwszRACertInfo);
  5349. }
  5350. return TRUE;
  5351. break;
  5352. case WM_NOTIFY:
  5353. break;
  5354. case WM_CLOSE:
  5355. EndDialog(hwndDlg, IDC_BUTTON3);
  5356. return TRUE;
  5357. break;
  5358. case WM_COMMAND:
  5359. switch (LOWORD(wParam))
  5360. {
  5361. //view certificate
  5362. case IDC_BUTTON1:
  5363. if(NULL==(pAEViewRAInfo=(AE_VIEW_RA_INFO *)GetWindowLongPtr(hwndDlg, DWLP_USER)))
  5364. break;
  5365. if(NULL==pAEViewRAInfo->pRAContext)
  5366. break;
  5367. //show the certificate
  5368. memset(&CertViewStruct, 0, sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT));
  5369. CertViewStruct.dwSize=sizeof(CRYPTUI_VIEWCERTIFICATE_STRUCT);
  5370. CertViewStruct.hwndParent=hwndDlg;
  5371. CertViewStruct.dwFlags=CRYPTUI_DISABLE_EDITPROPERTIES;
  5372. CertViewStruct.pCertContext=pAEViewRAInfo->pRAContext;
  5373. fPropertyChanged=FALSE;
  5374. CryptUIDlgViewCertificate(&CertViewStruct, &fPropertyChanged);
  5375. return TRUE;
  5376. //OK
  5377. case IDC_BUTTON2:
  5378. EndDialog(hwndDlg, IDC_BUTTON2);
  5379. return TRUE;
  5380. }
  5381. break;
  5382. default:
  5383. return FALSE;
  5384. }
  5385. return FALSE;
  5386. }
  5387. //-----------------------------------------------------------------------------
  5388. //
  5389. // AEUIProgressReport
  5390. //
  5391. // Report the current enrollment action. Return FALSE if no progress status
  5392. // can be reported.
  5393. //-----------------------------------------------------------------------------
  5394. BOOL AEUIProgressReport(BOOL fPending, AE_CERTTYPE_INFO *pCertType, HWND hwndDlg, HANDLE hCancelEvent)
  5395. {
  5396. BOOL fResult=FALSE;
  5397. UINT idsMessage=0;
  5398. INT_PTR ret=0;
  5399. AE_VIEW_RA_INFO AEViewRAInfo;
  5400. LPWSTR *awszFriendlyName=NULL;
  5401. LPWSTR pwszRACert=NULL;
  5402. LPWSTR pwszReport=NULL;
  5403. memset(&AEViewRAInfo, 0, sizeof(AE_VIEW_RA_INFO));
  5404. if((NULL==pCertType) || (NULL==hwndDlg))
  5405. goto Ret;
  5406. if(NULL==(pCertType->hCertType))
  5407. goto Ret;
  5408. if(AECancelled(hCancelEvent))
  5409. {
  5410. fResult=TRUE;
  5411. goto Ret;
  5412. }
  5413. if(fPending)
  5414. idsMessage=IDS_REPORT_PENDING;
  5415. else
  5416. {
  5417. if((pCertType->fRenewal) && (pCertType->pOldCert))
  5418. {
  5419. if(pCertType->fNeedRA)
  5420. {
  5421. if(FALSE == (pCertType->fCrossRA))
  5422. idsMessage=IDS_REPORT_RENEW;
  5423. else
  5424. idsMessage=IDS_REPORT_ENROLL_RA;
  5425. }
  5426. else
  5427. idsMessage=IDS_REPORT_RENEW;
  5428. }
  5429. else
  5430. idsMessage=IDS_REPORT_ENROLL;
  5431. }
  5432. //retrieve the template's friendly name
  5433. if(S_OK != CAGetCertTypePropertyEx(
  5434. pCertType->hCertType,
  5435. CERTTYPE_PROP_FRIENDLY_NAME,
  5436. &awszFriendlyName))
  5437. goto Ret;
  5438. if(NULL==awszFriendlyName)
  5439. goto Ret;
  5440. if(NULL==(awszFriendlyName[0]))
  5441. goto Ret;
  5442. //retrieve the RA certificate's template name
  5443. if(IDS_REPORT_ENROLL_RA == idsMessage)
  5444. {
  5445. if(!AEUIGetNameFromCert(pCertType->pOldCert, &pwszRACert))
  5446. {
  5447. pwszRACert=NULL;
  5448. }
  5449. }
  5450. if(!FormatMessageUnicode(&pwszReport, idsMessage, awszFriendlyName[0]))
  5451. goto Ret;
  5452. if(0 == SetDlgItemTextW(hwndDlg, IDC_EDIT2, pwszReport))
  5453. goto Ret;
  5454. //we will give user an opportunity to view the RA certificate before we go on
  5455. //format the view message
  5456. if(IDS_REPORT_ENROLL_RA != idsMessage)
  5457. {
  5458. //no need to do anything more
  5459. fResult=TRUE;
  5460. goto Ret;
  5461. }
  5462. AEViewRAInfo.pRAContext=pCertType->pOldCert;
  5463. AEViewRAInfo.pwszRATemplate=pwszRACert;
  5464. //ask user if he/she wants to view the RA certificate
  5465. ret=DialogBoxParam(g_hmodThisDll,
  5466. (LPCWSTR)MAKEINTRESOURCE(IDD_VIEW_RA_CERTIFICATE_DLG),
  5467. hwndDlg,
  5468. AEViewRADlgProc,
  5469. (LPARAM)(&AEViewRAInfo));
  5470. fResult=TRUE;
  5471. Ret:
  5472. if(pwszRACert)
  5473. LocalFree(pwszRACert);
  5474. if(awszFriendlyName)
  5475. CAFreeCertTypeProperty(pCertType->hCertType, awszFriendlyName);
  5476. if(pwszReport)
  5477. LocalFree((HLOCAL) pwszReport);
  5478. return fResult;
  5479. }
  5480. //-----------------------------------------------------------------------------
  5481. //
  5482. // the call back function to compare summary column
  5483. //
  5484. //-----------------------------------------------------------------------------
  5485. int CALLBACK CompareSummary(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  5486. {
  5487. AE_CERTTYPE_INFO *pCertTypeOne=NULL;
  5488. AE_CERTTYPE_INFO *pCertTypeTwo=NULL;
  5489. DWORD dwColumn=0;
  5490. int iCompare=0;
  5491. LPWSTR pwszOne=NULL;
  5492. LPWSTR pwszTwo=NULL;
  5493. pCertTypeOne=(AE_CERTTYPE_INFO *)lParam1;
  5494. pCertTypeTwo=(AE_CERTTYPE_INFO *)lParam2;
  5495. dwColumn=(DWORD)lParamSort;
  5496. if((NULL==pCertTypeOne) || (NULL==pCertTypeTwo))
  5497. goto Ret;
  5498. switch(dwColumn & 0x0000FFFF)
  5499. {
  5500. case AE_SUMMARY_COLUMN_TYPE:
  5501. //we should use wcsicoll instead of wcsicmp since wcsicoll use the
  5502. //lexicographic order of current code page.
  5503. iCompare=CompareStringW(LOCALE_USER_DEFAULT,
  5504. NORM_IGNORECASE,
  5505. pCertTypeOne->awszDisplay[0],
  5506. -1,
  5507. pCertTypeTwo->awszDisplay[0],
  5508. -1);
  5509. break;
  5510. case AE_SUMMARY_COLUMN_REASON:
  5511. pwszOne=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (MAX_DN_SIZE));
  5512. pwszTwo=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (MAX_DN_SIZE));
  5513. if((NULL==pwszOne) || (NULL==pwszTwo))
  5514. goto Ret;
  5515. if(0 == LoadStringW(g_hmodThisDll,
  5516. pCertTypeOne->idsSummary,
  5517. pwszOne,
  5518. MAX_DN_SIZE))
  5519. goto Ret;
  5520. if(0 == LoadStringW(g_hmodThisDll,
  5521. pCertTypeTwo->idsSummary,
  5522. pwszTwo,
  5523. MAX_DN_SIZE))
  5524. goto Ret;
  5525. //we should use wcsicoll instead of wcsicmp since wcsicoll use the
  5526. //lexicographic order of current code page.
  5527. iCompare=CompareStringW(LOCALE_USER_DEFAULT,
  5528. NORM_IGNORECASE,
  5529. pwszOne,
  5530. -1,
  5531. pwszTwo,
  5532. -1);
  5533. break;
  5534. default:
  5535. goto Ret;
  5536. break;
  5537. }
  5538. switch(iCompare)
  5539. {
  5540. case CSTR_LESS_THAN:
  5541. iCompare=-1;
  5542. break;
  5543. case CSTR_EQUAL:
  5544. iCompare=0;
  5545. break;
  5546. case CSTR_GREATER_THAN:
  5547. iCompare=1;
  5548. break;
  5549. default:
  5550. goto Ret;
  5551. break;
  5552. }
  5553. if(dwColumn & SORT_COLUMN_DESCEND)
  5554. iCompare = 0-iCompare;
  5555. Ret:
  5556. if(pwszOne)
  5557. LocalFree(pwszOne);
  5558. if(pwszTwo)
  5559. LocalFree(pwszTwo);
  5560. return iCompare;
  5561. }
  5562. //-----------------------------------------------------------------------------
  5563. //
  5564. // AEDisplaySummaryInfo
  5565. //
  5566. //-----------------------------------------------------------------------------
  5567. BOOL AEDisplaySummaryInfo(HWND hWndListView, AE_GENERAL_INFO *pAE_General_Info)
  5568. {
  5569. BOOL fResult=FALSE;
  5570. AE_CERTTYPE_INFO *rgCertTypeInfo = NULL;
  5571. DWORD dwIndex =0;
  5572. DWORD dwItem=0;
  5573. LV_ITEMW lvItem;
  5574. WCHAR wszReason[MAX_DN_SIZE];
  5575. AE_CERTTYPE_INFO *pCertType=NULL;
  5576. if((NULL==hWndListView) || (NULL==pAE_General_Info))
  5577. goto Ret;
  5578. rgCertTypeInfo = pAE_General_Info->rgCertTypeInfo;
  5579. if(NULL == rgCertTypeInfo)
  5580. goto Ret;
  5581. // set up the fields in the list view item struct that don't change from item to item
  5582. lvItem.mask = LVIF_TEXT | LVIF_PARAM;
  5583. lvItem.state = 0;
  5584. lvItem.stateMask = 0;
  5585. lvItem.iItem=0;
  5586. lvItem.iSubItem=0;
  5587. lvItem.iImage = 0;
  5588. lvItem.lParam = NULL;
  5589. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  5590. {
  5591. if((TRUE == rgCertTypeInfo[dwIndex].fUIActive) && (0 != rgCertTypeInfo[dwIndex].idsSummary))
  5592. {
  5593. if(0 != LoadStringW(g_hmodThisDll,
  5594. rgCertTypeInfo[dwIndex].idsSummary,
  5595. wszReason,
  5596. MAX_DN_SIZE))
  5597. {
  5598. lvItem.iItem=dwItem;
  5599. lvItem.iSubItem=0;
  5600. dwItem++;
  5601. pCertType=&(rgCertTypeInfo[dwIndex]);
  5602. lvItem.lParam = (LPARAM)(pCertType);
  5603. //template name
  5604. lvItem.pszText=rgCertTypeInfo[dwIndex].awszDisplay[0];
  5605. ListView_InsertItem(hWndListView, &lvItem);
  5606. //reason
  5607. lvItem.iSubItem++;
  5608. ListView_SetItemText(hWndListView, lvItem.iItem, lvItem.iSubItem, wszReason);
  5609. }
  5610. }
  5611. }
  5612. fResult=TRUE;
  5613. Ret:
  5614. return fResult;
  5615. }
  5616. //-----------------------------------------------------------------------------
  5617. //
  5618. // WinProc for the summary page
  5619. //
  5620. //-----------------------------------------------------------------------------
  5621. INT_PTR CALLBACK AESummaryDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  5622. {
  5623. AE_GENERAL_INFO *pAE_General_Info=NULL;
  5624. HWND hWndListView=NULL;
  5625. UINT rgIDS[]={IDS_COLUMN_TYPE,
  5626. IDS_COLUMN_REASON};
  5627. DWORD dwIndex=0;
  5628. DWORD dwCount=0;
  5629. LV_COLUMNW lvC;
  5630. WCHAR wszText[AE_SUMMARY_COLUMN_SIZE];
  5631. NM_LISTVIEW *pnmv=NULL;
  5632. DWORD dwSortParam=0;
  5633. static DWORD rgdwSortParam[]=
  5634. {AE_SUMMARY_COLUMN_TYPE | SORT_COLUMN_ASCEND,
  5635. AE_SUMMARY_COLUMN_REASON | SORT_COLUMN_DESCEND};
  5636. switch (msg)
  5637. {
  5638. case WM_INITDIALOG:
  5639. pAE_General_Info=(AE_GENERAL_INFO *)lParam;
  5640. if(NULL==pAE_General_Info)
  5641. break;
  5642. SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pAE_General_Info);
  5643. //init the list view control
  5644. //add the colums to the list view
  5645. hWndListView = GetDlgItem(hwndDlg, IDC_LIST2);
  5646. if(NULL==hWndListView)
  5647. break;
  5648. dwCount=sizeof(rgIDS)/sizeof(rgIDS[0]);
  5649. //set up the common info for the column
  5650. memset(&lvC, 0, sizeof(LV_COLUMNW));
  5651. lvC.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  5652. lvC.fmt = LVCFMT_LEFT; // Left-align the column.
  5653. lvC.cx = 150; // Width of the column, in pixels.
  5654. lvC.iSubItem=0;
  5655. lvC.pszText = wszText; // The text for the column.
  5656. //insert the column one at a time
  5657. for(dwIndex=0; dwIndex < dwCount; dwIndex++)
  5658. {
  5659. //get the column header
  5660. wszText[0]=L'\0';
  5661. if(0 != LoadStringW(g_hmodThisDll, rgIDS[dwIndex], wszText, AE_SUMMARY_COLUMN_SIZE))
  5662. {
  5663. ListView_InsertColumn(hWndListView, dwIndex, &lvC);
  5664. }
  5665. }
  5666. // set the style in the list view so that it highlights an entire line
  5667. SendMessage(hWndListView, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
  5668. AEDisplaySummaryInfo(hWndListView, pAE_General_Info);
  5669. //autosize the columns
  5670. for(dwIndex=0; dwIndex < dwCount; dwIndex++)
  5671. {
  5672. ListView_SetColumnWidth(hWndListView, dwIndex, LVSCW_AUTOSIZE);
  5673. }
  5674. //sort 1st column of the list view
  5675. dwSortParam=rgdwSortParam[0];
  5676. SendDlgItemMessage(hwndDlg,
  5677. IDC_LIST2,
  5678. LVM_SORTITEMS,
  5679. (WPARAM) (LPARAM) dwSortParam,
  5680. (LPARAM) (PFNLVCOMPARE)CompareSummary);
  5681. return TRUE;
  5682. break;
  5683. case WM_NOTIFY:
  5684. switch (((NMHDR FAR *) lParam)->code)
  5685. {
  5686. //the column has been changed
  5687. case LVN_COLUMNCLICK:
  5688. pnmv = (NM_LISTVIEW *) lParam;
  5689. dwSortParam=0;
  5690. //get the column number
  5691. switch(pnmv->iSubItem)
  5692. {
  5693. case 0:
  5694. case 1:
  5695. dwSortParam=rgdwSortParam[pnmv->iSubItem];
  5696. break;
  5697. default:
  5698. dwSortParam=0;
  5699. break;
  5700. }
  5701. if(0!=dwSortParam)
  5702. {
  5703. //remember to flip the ascend ording
  5704. if(dwSortParam & SORT_COLUMN_ASCEND)
  5705. {
  5706. dwSortParam &= 0x0000FFFF;
  5707. dwSortParam |= SORT_COLUMN_DESCEND;
  5708. }
  5709. else
  5710. {
  5711. if(dwSortParam & SORT_COLUMN_DESCEND)
  5712. {
  5713. dwSortParam &= 0x0000FFFF;
  5714. dwSortParam |= SORT_COLUMN_ASCEND;
  5715. }
  5716. }
  5717. //sort the column
  5718. SendDlgItemMessage(hwndDlg,
  5719. IDC_LIST2,
  5720. LVM_SORTITEMS,
  5721. (WPARAM) (LPARAM) dwSortParam,
  5722. (LPARAM) (PFNLVCOMPARE)CompareSummary);
  5723. rgdwSortParam[pnmv->iSubItem]=dwSortParam;
  5724. }
  5725. break;
  5726. }
  5727. break;
  5728. case WM_CLOSE:
  5729. EndDialog(hwndDlg, IDC_BUTTON1);
  5730. return TRUE;
  5731. break;
  5732. case WM_COMMAND:
  5733. switch (LOWORD(wParam))
  5734. {
  5735. case IDC_BUTTON1:
  5736. EndDialog(hwndDlg, IDC_BUTTON1);
  5737. return TRUE;
  5738. }
  5739. break;
  5740. default:
  5741. return FALSE;
  5742. }
  5743. return FALSE;
  5744. }
  5745. //-----------------------------------------------------------------------------
  5746. //
  5747. // AEDisplaySummaryPage
  5748. //
  5749. //-----------------------------------------------------------------------------
  5750. BOOL AEDisplaySummaryPage(AE_GENERAL_INFO *pAE_General_Info)
  5751. {
  5752. BOOL fResult=FALSE;
  5753. DWORD dwIndex=0;
  5754. BOOL fSummary=FALSE;
  5755. AE_CERTTYPE_INFO *rgCertTypeInfo=NULL;
  5756. AE_CERTTYPE_INFO *pCertType=NULL;
  5757. //decide if there is need to show the summary page.
  5758. //Checking for idsSummary for each template
  5759. if(NULL == pAE_General_Info)
  5760. goto Ret;
  5761. if(NULL == (rgCertTypeInfo=pAE_General_Info->rgCertTypeInfo))
  5762. goto Ret;
  5763. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  5764. {
  5765. if((TRUE == rgCertTypeInfo[dwIndex].fUIActive) && (0 != rgCertTypeInfo[dwIndex].idsSummary))
  5766. {
  5767. fSummary=TRUE;
  5768. break;
  5769. }
  5770. }
  5771. //show the summary dialogue
  5772. if(TRUE == fSummary)
  5773. {
  5774. if(pAE_General_Info->hwndDlg)
  5775. {
  5776. DialogBoxParam(g_hmodThisDll,
  5777. (LPCWSTR)MAKEINTRESOURCE(IDD_USER_SUMMARY_DLG),
  5778. pAE_General_Info->hwndDlg,
  5779. AESummaryDlgProc,
  5780. (LPARAM)(pAE_General_Info));
  5781. }
  5782. }
  5783. fResult=TRUE;
  5784. Ret:
  5785. return fResult;
  5786. }
  5787. //-----------------------------------------------------------------------------
  5788. // WinProc for the autoenrollment progress window
  5789. //
  5790. //-----------------------------------------------------------------------------
  5791. INT_PTR CALLBACK progressDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  5792. {
  5793. AE_GENERAL_INFO *pAE_General_Info = NULL;
  5794. switch (msg)
  5795. {
  5796. case WM_INITDIALOG:
  5797. pAE_General_Info=(AE_GENERAL_INFO *)lParam;
  5798. //copy the hwndDlg to the enrollment thread
  5799. pAE_General_Info->hwndDlg=hwndDlg;
  5800. //start the interacive enrollment thread
  5801. if(1 != ResumeThread(pAE_General_Info->hThread))
  5802. {
  5803. pAE_General_Info->hwndDlg=NULL;
  5804. //we have to end the dialogue
  5805. EndDialog(hwndDlg, IDC_BUTTON1);
  5806. return TRUE;
  5807. }
  5808. SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pAE_General_Info);
  5809. return TRUE;
  5810. break;
  5811. case WM_NOTIFY:
  5812. break;
  5813. case WM_CLOSE:
  5814. if(NULL==(pAE_General_Info=(AE_GENERAL_INFO *)GetWindowLongPtr(hwndDlg, DWLP_USER)))
  5815. break;
  5816. //disable the cancel button
  5817. EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON1), FALSE);
  5818. //signal the cancel event
  5819. if(pAE_General_Info->hCancelEvent)
  5820. SetEvent(pAE_General_Info->hCancelEvent);
  5821. //close the dialogue if the enrollment work is completed
  5822. if(WAIT_OBJECT_0 == WaitForSingleObject(pAE_General_Info->hCompleteEvent, 0))
  5823. {
  5824. EndDialog(hwndDlg, IDC_BUTTON1);
  5825. }
  5826. return TRUE;
  5827. break;
  5828. case WM_COMMAND:
  5829. switch (LOWORD(wParam))
  5830. {
  5831. case IDC_BUTTON1:
  5832. if(NULL==(pAE_General_Info=(AE_GENERAL_INFO *)GetWindowLongPtr(hwndDlg, DWLP_USER)))
  5833. break;
  5834. //disable the cancel button
  5835. EnableWindow(GetDlgItem(hwndDlg,IDC_BUTTON1), FALSE);
  5836. //signal the cancel event
  5837. if(pAE_General_Info->hCancelEvent)
  5838. SetEvent(pAE_General_Info->hCancelEvent);
  5839. return TRUE;
  5840. }
  5841. break;
  5842. default:
  5843. return FALSE;
  5844. }
  5845. return FALSE;
  5846. }
  5847. //-----------------------------------------------------------------------------
  5848. // AEInteractiveThreadProc
  5849. //
  5850. // The thread procedue to do interactive enrollment
  5851. //-----------------------------------------------------------------------------
  5852. DWORD WINAPI AEInteractiveThreadProc(LPVOID lpParameter)
  5853. {
  5854. BOOL fResult=FALSE;
  5855. AE_GENERAL_INFO *pAE_General_Info = NULL;
  5856. if(NULL==lpParameter)
  5857. return FALSE;
  5858. __try
  5859. {
  5860. pAE_General_Info=(AE_GENERAL_INFO *)lpParameter;
  5861. pAE_General_Info->fUIProcess=TRUE;
  5862. fResult = AEEnrollmentWalker(pAE_General_Info);
  5863. //show the summary page if not canceled
  5864. if(!AECancelled(pAE_General_Info->hCancelEvent))
  5865. {
  5866. AEDisplaySummaryPage(pAE_General_Info);
  5867. }
  5868. //signal that the process is completed
  5869. SetEvent(pAE_General_Info->hCompleteEvent);
  5870. //signal the progress window that we are done
  5871. if(pAE_General_Info->hwndDlg)
  5872. {
  5873. //click the close button
  5874. SendMessage(pAE_General_Info->hwndDlg,
  5875. WM_CLOSE, //WM_COMMAND,
  5876. 0, //IDC_BUTTON1,
  5877. NULL);
  5878. }
  5879. }
  5880. __except ( EXCEPTION_EXECUTE_HANDLER )
  5881. {
  5882. }
  5883. return fResult;
  5884. }
  5885. //-----------------------------------------------------------------------------
  5886. // AEInteractiveEnrollment
  5887. //
  5888. // We are doing interactive enrollment
  5889. //-----------------------------------------------------------------------------
  5890. BOOL AEInteractiveEnrollment(AE_GENERAL_INFO *pAE_General_Info)
  5891. {
  5892. DWORD dwThreadID=0;
  5893. BOOL fResult=FALSE;
  5894. //create a notification event for cancel process
  5895. pAE_General_Info->hCancelEvent=CreateEvent(
  5896. NULL,
  5897. TRUE, // bmanual reset type
  5898. FALSE, // initial state
  5899. NULL);
  5900. if(NULL==(pAE_General_Info->hCancelEvent))
  5901. goto ret;
  5902. //create a notification event for complete process
  5903. pAE_General_Info->hCompleteEvent=CreateEvent(
  5904. NULL,
  5905. TRUE, // bmanual reset type
  5906. FALSE, // initial state
  5907. NULL);
  5908. if(NULL==(pAE_General_Info->hCompleteEvent))
  5909. goto ret;
  5910. //spawn a thread
  5911. pAE_General_Info->hThread = CreateThread(NULL,
  5912. 0,
  5913. AEInteractiveThreadProc,
  5914. pAE_General_Info,
  5915. CREATE_SUSPENDED, //suspend execution
  5916. &dwThreadID);
  5917. if(NULL==(pAE_General_Info->hThread))
  5918. goto ret;
  5919. //create the dialogue
  5920. DialogBoxParam(
  5921. g_hmodThisDll,
  5922. MAKEINTRESOURCE(IDD_USER_AUTOENROLL_GENERAL_DLG),
  5923. pAE_General_Info->hwndParent,
  5924. progressDlgProc,
  5925. (LPARAM)(pAE_General_Info));
  5926. //wait for thread to finish
  5927. if(WAIT_FAILED == WaitForSingleObject(pAE_General_Info->hThread, INFINITE))
  5928. goto ret;
  5929. fResult=TRUE;
  5930. ret:
  5931. //log the event
  5932. if(!fResult)
  5933. {
  5934. AELogAutoEnrollmentEvent(
  5935. pAE_General_Info->dwLogLevel,
  5936. TRUE,
  5937. HRESULT_FROM_WIN32(GetLastError()),
  5938. EVENT_FAIL_INTERACTIVE_START,
  5939. pAE_General_Info->fMachine,
  5940. pAE_General_Info->hToken,
  5941. 0);
  5942. }
  5943. return fResult;
  5944. }
  5945. //-----------------------------------------------------------------------------
  5946. //
  5947. // WinProc for the confirmation to start certificate autoenrollment
  5948. //
  5949. //-----------------------------------------------------------------------------
  5950. INT_PTR CALLBACK AEConfirmDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  5951. {
  5952. switch (msg)
  5953. {
  5954. case WM_INITDIALOG:
  5955. return TRUE;
  5956. break;
  5957. case WM_NOTIFY:
  5958. break;
  5959. case WM_CLOSE:
  5960. EndDialog(hwndDlg, IDC_BUTTON2);
  5961. return TRUE;
  5962. break;
  5963. case WM_COMMAND:
  5964. switch (LOWORD(wParam))
  5965. {
  5966. case IDC_BUTTON1:
  5967. EndDialog(hwndDlg, IDC_BUTTON1);
  5968. return TRUE;
  5969. case IDC_BUTTON2:
  5970. EndDialog(hwndDlg, IDC_BUTTON2);
  5971. return TRUE;
  5972. }
  5973. break;
  5974. default:
  5975. return FALSE;
  5976. }
  5977. return FALSE;
  5978. }
  5979. //-----------------------------------------------------------------------
  5980. //
  5981. // AERegisterSysTrayApp
  5982. //
  5983. // This functin registers autoenrollment in the sys tray area
  5984. // as an notification
  5985. //
  5986. //
  5987. //-----------------------------------------------------------------------
  5988. BOOL AERegisterSysTrayApp(HWND hwndParent)
  5989. {
  5990. BOOL fResult=FALSE;
  5991. BOOL fInit=FALSE;
  5992. INT_PTR ret=0;
  5993. DWORD dwError=0;
  5994. CQueryContinue *pCQueryContinue=NULL;
  5995. if(FAILED(CoInitialize(NULL)))
  5996. goto Ret;
  5997. fInit=TRUE;
  5998. pCQueryContinue=new CQueryContinue();
  5999. if(NULL==pCQueryContinue)
  6000. goto Ret;
  6001. if(S_OK != pCQueryContinue->DoBalloon())
  6002. goto Ret;
  6003. //ask user if autoenrollment should be performed
  6004. ret=DialogBox(g_hmodThisDll,
  6005. (LPCWSTR)MAKEINTRESOURCE(IDD_USER_AUTOENROLL_INFO_DLG),
  6006. hwndParent,
  6007. AEConfirmDlgProc);
  6008. if(IDC_BUTTON1 != ret)
  6009. {
  6010. dwError=GetLastError();
  6011. goto Ret;
  6012. }
  6013. fResult=TRUE;
  6014. Ret:
  6015. if(pCQueryContinue)
  6016. {
  6017. delete pCQueryContinue;
  6018. }
  6019. if(fInit)
  6020. CoUninitialize();
  6021. return fResult;
  6022. }
  6023. //-----------------------------------------------------------------------
  6024. //
  6025. // AEUIDisabled
  6026. //
  6027. // Detect if the user notification balloon is disabled by user
  6028. // setting the autoenrollment registry key in current user
  6029. //
  6030. //
  6031. //-----------------------------------------------------------------------
  6032. BOOL AEUIDisabled()
  6033. {
  6034. BOOL fResult=FALSE;
  6035. HKEY hKey=NULL;
  6036. if(ERROR_SUCCESS == RegOpenKeyEx(
  6037. HKEY_CURRENT_USER, // handle to open key
  6038. AUTO_ENROLLMENT_DISABLE_KEY, // subkey name
  6039. 0, // reserved
  6040. KEY_READ, // security access mask
  6041. &hKey)) // handle to open key
  6042. {
  6043. fResult=TRUE;
  6044. }
  6045. if(hKey)
  6046. RegCloseKey(hKey);
  6047. return fResult;
  6048. }
  6049. //-----------------------------------------------------------------------
  6050. //
  6051. // AEUIRequired
  6052. //
  6053. // Detect if the user notification balloon is needed
  6054. //
  6055. //
  6056. //-----------------------------------------------------------------------
  6057. BOOL AEUIRequired(AE_GENERAL_INFO *pAE_General_Info)
  6058. {
  6059. BOOL fUI=FALSE;
  6060. AE_CERTTYPE_INFO *rgCertTypeInfo = NULL;
  6061. DWORD dwIndex = 0;
  6062. if(NULL==pAE_General_Info)
  6063. return FALSE;
  6064. rgCertTypeInfo = pAE_General_Info->rgCertTypeInfo;
  6065. pAE_General_Info->dwUIEnrollCount=0;
  6066. if(NULL == rgCertTypeInfo)
  6067. return FALSE;
  6068. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  6069. {
  6070. if(rgCertTypeInfo[dwIndex].fUIActive)
  6071. {
  6072. if(CERT_REQUEST_STATUS_ACTIVE == rgCertTypeInfo[dwIndex].dwStatus)
  6073. {
  6074. fUI=TRUE;
  6075. (pAE_General_Info->dwUIEnrollCount)++;
  6076. }
  6077. }
  6078. }
  6079. //add the pending count
  6080. if(pAE_General_Info->dwUIPendCount)
  6081. {
  6082. fUI=TRUE;
  6083. (pAE_General_Info->dwUIEnrollCount) +=(pAE_General_Info->dwUIPendCount);
  6084. }
  6085. return fUI;
  6086. }
  6087. //-----------------------------------------------------------------------
  6088. //
  6089. // AEProcessEnrollment
  6090. //
  6091. // This functin does the autoenrollment based on ACL and manage MY
  6092. // store.
  6093. //
  6094. //
  6095. //-----------------------------------------------------------------------
  6096. BOOL AEProcessEnrollment(HWND hwndParent, BOOL fMachine, LDAP *pld, DWORD dwPolicy, DWORD dwLogLevel)
  6097. {
  6098. BOOL fResult=FALSE;
  6099. AE_GENERAL_INFO *pAE_General_Info=NULL;
  6100. pAE_General_Info=(AE_GENERAL_INFO *)LocalAlloc(LPTR, sizeof(AE_GENERAL_INFO));
  6101. if(NULL==pAE_General_Info)
  6102. goto Ret;
  6103. memset(pAE_General_Info, 0, sizeof(AE_GENERAL_INFO));
  6104. if(NULL==pld)
  6105. goto Ret;
  6106. //we obtain all information needed for process enrollment
  6107. pAE_General_Info->hwndParent = hwndParent;
  6108. pAE_General_Info->pld = pld;
  6109. pAE_General_Info->fMachine = fMachine;
  6110. pAE_General_Info->dwPolicy = dwPolicy;
  6111. pAE_General_Info->dwLogLevel = dwLogLevel;
  6112. __try
  6113. {
  6114. if(!AERetrieveGeneralInfo(pAE_General_Info))
  6115. {
  6116. AELogAutoEnrollmentEvent(dwLogLevel,
  6117. TRUE,
  6118. HRESULT_FROM_WIN32(GetLastError()),
  6119. EVENT_FAIL_GENERAL_INFOMATION,
  6120. fMachine,
  6121. pAE_General_Info->hToken,
  6122. 0);
  6123. goto Ret;
  6124. }
  6125. if((0 == pAE_General_Info->dwCertType) || (NULL==pAE_General_Info->rgCertTypeInfo))
  6126. {
  6127. AELogAutoEnrollmentEvent(dwLogLevel, FALSE, S_OK,
  6128. EVENT_NO_CERT_TEMPLATE, fMachine, pAE_General_Info->hToken,0);
  6129. AE_DEBUG((AE_WARNING, L"No CertType's available for auto-enrollment\n\r"));
  6130. goto Ret;
  6131. }
  6132. //we build the auto-enrollment requests based on the ACL on the DS
  6133. if(AUTO_ENROLLMENT_ENABLE_TEMPLATE_CHECK & (pAE_General_Info->dwPolicy))
  6134. {
  6135. if(!AEMarkAutoenrollment(pAE_General_Info))
  6136. goto Ret;
  6137. }
  6138. //we build the auto-enrollment requests based on the ARCS store
  6139. //this is enabled by default and can only be disabled if autoenrollment is
  6140. //completely disabled
  6141. if(!AEMarkAEObject(pAE_General_Info))
  6142. goto Ret;
  6143. //manage MY store. Check if we already have required certificates
  6144. //we should always check my store with different behavior based on
  6145. //AUTO_ENROLLMENT_ENABLE_MY_STORE_MANAGEMENT flag
  6146. if(!AEManageAndMarkMyStore(pAE_General_Info))
  6147. goto Ret;
  6148. //manage UserDS store for user autoenrollment
  6149. if(!fMachine)
  6150. {
  6151. if(!AECheckUserDSStore(pAE_General_Info))
  6152. goto Ret;
  6153. }
  6154. //manage pending request store. Remove expired pending requests
  6155. if(AUTO_ENROLLMENT_ENABLE_PENDING_FETCH & (pAE_General_Info->dwPolicy))
  6156. {
  6157. if(!AECheckPendingRequests(pAE_General_Info))
  6158. goto Ret;
  6159. }
  6160. //get CA information
  6161. if(!AERetrieveCAInfo(pAE_General_Info->pld,
  6162. pAE_General_Info->fMachine,
  6163. pAE_General_Info->hToken,
  6164. &(pAE_General_Info->dwCA),
  6165. &(pAE_General_Info->rgCAInfo)))
  6166. {
  6167. AELogAutoEnrollmentEvent(dwLogLevel, TRUE, HRESULT_FROM_WIN32(GetLastError()),
  6168. EVENT_FAIL_CA_INFORMATION, fMachine, pAE_General_Info->hToken, 0);
  6169. AE_DEBUG((AE_ERROR, L"Unable to retrieve CA information (%lx)\n\r", GetLastError()));
  6170. goto Ret;
  6171. }
  6172. if((0 == pAE_General_Info->dwCA) || (NULL==pAE_General_Info->rgCAInfo))
  6173. {
  6174. //we do not have any CAs on the domain. All we need to do is to archive
  6175. //archive old certificate after the enrollment/renewal
  6176. AEArchiveObsoleteCertificates(pAE_General_Info);
  6177. AELogAutoEnrollmentEvent(dwLogLevel, FALSE, S_OK,
  6178. EVENT_NO_CA, fMachine, pAE_General_Info->hToken, 0);
  6179. AE_DEBUG((AE_WARNING, L"No CA's available for auto-enrollment\n\r"));
  6180. goto Ret;
  6181. }
  6182. //we check if active templates do have a CA that we can enroll for
  6183. if(!AEManageActiveTemplates(pAE_General_Info))
  6184. goto Ret;
  6185. //perform autoenrollment as the background
  6186. pAE_General_Info->fUIProcess=FALSE;
  6187. if(!AEEnrollmentWalker(pAE_General_Info))
  6188. goto Ret;
  6189. //perform autoenrollment as a sys tray application for user only
  6190. if(FALSE == fMachine)
  6191. {
  6192. //test if the notification balloon is disabled
  6193. if(!AEUIDisabled())
  6194. {
  6195. //test if the notification balloon is needed
  6196. if(AEUIRequired(pAE_General_Info))
  6197. {
  6198. //register the sys tray application
  6199. if(AERegisterSysTrayApp(pAE_General_Info->hwndParent))
  6200. {
  6201. //perform autoenrollment in interactive mode
  6202. AEInteractiveEnrollment(pAE_General_Info);
  6203. }
  6204. }
  6205. }
  6206. }
  6207. //archive old certificate after the enrollment/renewal
  6208. if(!AEArchiveObsoleteCertificates(pAE_General_Info))
  6209. goto Ret;
  6210. }
  6211. __except ( EXCEPTION_EXECUTE_HANDLER )
  6212. {
  6213. goto Ret;
  6214. }
  6215. fResult=TRUE;
  6216. Ret:
  6217. //free memory only if no thread is created
  6218. if(pAE_General_Info)
  6219. {
  6220. AEFreeGeneralInfo(pAE_General_Info);
  6221. LocalFree(pAE_General_Info);
  6222. }
  6223. return fResult;
  6224. }
  6225. //-----------------------------------------------------------------------
  6226. //
  6227. // AEExpress
  6228. //
  6229. // Detect if the user autoenrollment has the express key set. If the
  6230. // Express key is set, user autoenrollment will not wait for machine
  6231. // autoenrollment to complete on root certificates download
  6232. //
  6233. //
  6234. //-----------------------------------------------------------------------
  6235. BOOL AEExpress()
  6236. {
  6237. BOOL fResult=FALSE;
  6238. HKEY hKey=NULL;
  6239. if(ERROR_SUCCESS == RegOpenKeyEx(
  6240. HKEY_CURRENT_USER, // handle to open key
  6241. AUTO_ENROLLMENT_EXPRESS_KEY, // subkey name
  6242. 0, // reserved
  6243. KEY_READ, // security access mask
  6244. &hKey)) // handle to open key
  6245. {
  6246. fResult=TRUE;
  6247. }
  6248. if(hKey)
  6249. RegCloseKey(hKey);
  6250. return fResult;
  6251. }
  6252. //-----------------------------------------------------------------------
  6253. //
  6254. // AEMainThreadProc
  6255. //
  6256. // The background thread for non-blocking autoenrollment background
  6257. // processing.
  6258. //
  6259. //-----------------------------------------------------------------------
  6260. DWORD WINAPI AEMainThreadProc(LPVOID lpParameter)
  6261. {
  6262. HRESULT hr=S_OK;
  6263. BOOL fMachine=FALSE;
  6264. DWORD dwPolicy=0;
  6265. DWORD dwLogLevel=STATUS_SEVERITY_ERROR;
  6266. HWND hwndParent=0;
  6267. DWORD dwStatus=0;
  6268. LARGE_INTEGER ftPreTimeStamp;
  6269. LARGE_INTEGER ftPostTimeStamp;
  6270. BOOL fNeedToSetupTimer=FALSE;
  6271. LDAP *pld = NULL;
  6272. //get the system time stamp
  6273. GetSystemTimeAsFileTime((LPFILETIME)&ftPreTimeStamp);
  6274. //the two input parameters are not yet used
  6275. if(NULL==lpParameter)
  6276. goto CommonReturn;
  6277. hwndParent = ((AE_MAIN_THREAD_INFO *)lpParameter)->hwndParent;
  6278. dwStatus = ((AE_MAIN_THREAD_INFO *)lpParameter)->dwStatus;
  6279. AE_DEBUG((AE_INFO, L"Beginning CertAutoEnrollment(%s).\n", (CERT_AUTO_ENROLLMENT_START_UP==dwStatus?L"START_UP":L"WAKE_UP")));
  6280. //no autoenrollment in the safe boot mode
  6281. //no autoenrollment if we are not in a domain
  6282. if(AEInSafeBoot() || !AEIsDomainMember())
  6283. goto CommonReturn;
  6284. //we need to set up the timer
  6285. fNeedToSetupTimer=TRUE;
  6286. //detect if we are running under user or machine context
  6287. if(!AEIsLocalSystem(&fMachine))
  6288. goto CommonReturn;
  6289. AE_DEBUG((AE_INFO, L"CertAutoEnrollment running as %s.\n", (fMachine?L"machine":L"user")));
  6290. AESetWakeUpFlag(fMachine, TRUE);
  6291. //we wait for 70 seconds for user case to give enough time for
  6292. //machine autoenrollment to complete, which will download certificates
  6293. //from the directory
  6294. if(!fMachine)
  6295. {
  6296. if(!AEExpress())
  6297. {
  6298. Sleep(USER_AUTOENROLL_DELAY_FOR_MACHINE * 1000);
  6299. }
  6300. }
  6301. //get the autoenrollment log level
  6302. if(!AERetrieveLogLevel(fMachine, &dwLogLevel))
  6303. goto CommonReturn;
  6304. //log the autoenrollment start event
  6305. AELogAutoEnrollmentEvent(dwLogLevel, FALSE, S_OK, EVENT_AUTOENROLL_START, fMachine, NULL, 0);
  6306. //get the autoenrollment policy flag
  6307. if(!AEGetPolicyFlag(fMachine, &dwPolicy))
  6308. goto CommonReturn;
  6309. //no need to do anything if autoenrollment is completely disabled
  6310. if(AUTO_ENROLLMENT_DISABLE_ALL & dwPolicy)
  6311. goto CommonReturn;
  6312. //download NTAuth And Enterprise root store for machine
  6313. if(fMachine)
  6314. {
  6315. //bind to the DS
  6316. if(S_OK != (hr=AERobustLdapBind(&pld)))
  6317. {
  6318. SetLastError(hr);
  6319. AELogAutoEnrollmentEvent(dwLogLevel, TRUE, hr, EVENT_FAIL_BIND_TO_DS, fMachine, NULL, 0);
  6320. goto CommonReturn;
  6321. }
  6322. AEDownloadStore(pld);
  6323. }
  6324. //if we are required to do a WIN2K style autoenrollment, and the machine/user's
  6325. //ACRS store is empty, just return as we done.
  6326. if(0 == dwPolicy)
  6327. {
  6328. if(IsACRSStoreEmpty(fMachine))
  6329. goto CommonReturn;
  6330. }
  6331. if(NULL==pld)
  6332. {
  6333. //bind to the DS
  6334. if(S_OK != (hr=AERobustLdapBind(&pld)))
  6335. {
  6336. SetLastError(hr);
  6337. AELogAutoEnrollmentEvent(dwLogLevel, TRUE, hr, EVENT_FAIL_BIND_TO_DS, fMachine, NULL, 0);
  6338. goto CommonReturn;
  6339. }
  6340. }
  6341. AEProcessEnrollment(hwndParent, fMachine, pld, dwPolicy, dwLogLevel);
  6342. CommonReturn:
  6343. //get the system time
  6344. GetSystemTimeAsFileTime((LPFILETIME)&ftPostTimeStamp);
  6345. //set up the timer for next time
  6346. if(TRUE == fNeedToSetupTimer)
  6347. {
  6348. // we will need to do this again in a few hours.
  6349. AESetWakeUpTimer(fMachine, &ftPreTimeStamp, &ftPostTimeStamp);
  6350. }
  6351. if(pld)
  6352. ldap_unbind(pld);
  6353. if(lpParameter)
  6354. LocalFree((HLOCAL)lpParameter);
  6355. AELogAutoEnrollmentEvent(dwLogLevel, FALSE, S_OK, EVENT_AUTOENROLL_COMPLETE, fMachine, NULL, 0);
  6356. return TRUE;
  6357. }
  6358. //--------------------------------------------------------------------------
  6359. //
  6360. // CertAutoEnrollment
  6361. //
  6362. // Function to perform autoenrollment actions. It creates a working
  6363. // thread and return immediately so that it is non-blocking.
  6364. //
  6365. // Parameters:
  6366. // IN hwndParent: The parent window
  6367. // IN dwStatus: The status under which the function is called.
  6368. // It can be one of the following:
  6369. // CERT_AUTO_ENROLLMENT_START_UP
  6370. // CERT_AUTO_ENROLLMENT_WAKE_UP
  6371. //
  6372. //--------------------------------------------------------------------------
  6373. HANDLE
  6374. WINAPI
  6375. CertAutoEnrollment(IN HWND hwndParent,
  6376. IN DWORD dwStatus)
  6377. {
  6378. DWORD dwThreadID=0;
  6379. //memory will be freed in the main thread
  6380. AE_MAIN_THREAD_INFO *pAE_Main_Thread_Info=NULL;
  6381. HANDLE hThread=NULL;
  6382. pAE_Main_Thread_Info=(AE_MAIN_THREAD_INFO *)LocalAlloc(LPTR, sizeof(AE_MAIN_THREAD_INFO));
  6383. if(NULL==pAE_Main_Thread_Info)
  6384. return NULL;
  6385. memset(pAE_Main_Thread_Info, 0, sizeof(AE_MAIN_THREAD_INFO));
  6386. pAE_Main_Thread_Info->hwndParent=hwndParent;
  6387. pAE_Main_Thread_Info->dwStatus=dwStatus;
  6388. hThread = CreateThread(NULL,
  6389. 0,
  6390. AEMainThreadProc,
  6391. pAE_Main_Thread_Info,
  6392. 0, //execute immediately
  6393. &dwThreadID);
  6394. //set the thread priority to low so that we will not compete with the shell
  6395. SetThreadPriority(hThread, THREAD_PRIORITY_BELOW_NORMAL);
  6396. return hThread;
  6397. }
  6398. //--------------------------------------------------------------------
  6399. //
  6400. // AERetrieveClientToken
  6401. //
  6402. //--------------------------------------------------------------------
  6403. BOOL AERetrieveClientToken(HANDLE *phToken)
  6404. {
  6405. HRESULT hr = S_OK;
  6406. HANDLE hHandle = NULL;
  6407. HANDLE hClientToken = NULL;
  6408. hHandle = GetCurrentThread();
  6409. if (NULL == hHandle)
  6410. {
  6411. hr = HRESULT_FROM_WIN32(GetLastError());
  6412. }
  6413. else
  6414. {
  6415. if (!OpenThreadToken(hHandle,
  6416. TOKEN_QUERY,
  6417. TRUE, // open as self
  6418. &hClientToken))
  6419. {
  6420. hr = HRESULT_FROM_WIN32(GetLastError());
  6421. CloseHandle(hHandle);
  6422. hHandle = NULL;
  6423. }
  6424. }
  6425. if(hr != S_OK)
  6426. {
  6427. hHandle = GetCurrentProcess();
  6428. if (NULL == hHandle)
  6429. {
  6430. hr = HRESULT_FROM_WIN32(GetLastError());
  6431. }
  6432. else
  6433. {
  6434. HANDLE hProcessToken = NULL;
  6435. hr = S_OK;
  6436. if (!OpenProcessToken(hHandle,
  6437. TOKEN_DUPLICATE,
  6438. &hProcessToken))
  6439. {
  6440. hr = HRESULT_FROM_WIN32(GetLastError());
  6441. CloseHandle(hHandle);
  6442. hHandle = NULL;
  6443. }
  6444. else
  6445. {
  6446. if(!DuplicateToken(hProcessToken,
  6447. SecurityImpersonation,
  6448. &hClientToken))
  6449. {
  6450. hr = HRESULT_FROM_WIN32(GetLastError());
  6451. CloseHandle(hHandle);
  6452. hHandle = NULL;
  6453. }
  6454. CloseHandle(hProcessToken);
  6455. }
  6456. }
  6457. }
  6458. if(S_OK == hr)
  6459. *phToken = hClientToken;
  6460. if(hHandle)
  6461. CloseHandle(hHandle);
  6462. return (S_OK == hr);
  6463. }
  6464. //--------------------------------------------------------------------------
  6465. //
  6466. // AEGetComputerName
  6467. //
  6468. //
  6469. //--------------------------------------------------------------------------
  6470. LPWSTR AEGetComputerName(COMPUTER_NAME_FORMAT NameType)
  6471. {
  6472. DWORD dwSize=0;
  6473. LPWSTR pwszName=NULL;
  6474. if(!GetComputerNameEx(NameType, NULL, &dwSize))
  6475. {
  6476. if(ERROR_MORE_DATA != GetLastError())
  6477. goto Ret;
  6478. }
  6479. else
  6480. {
  6481. //this is to work around a bug in cluster code that it returns TRUE
  6482. //to retrive the size
  6483. dwSize++;
  6484. }
  6485. pwszName=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * dwSize);
  6486. if(NULL == pwszName)
  6487. goto Ret;
  6488. if(!GetComputerNameEx(NameType, pwszName, &dwSize))
  6489. {
  6490. LocalFree(pwszName);
  6491. pwszName=NULL;
  6492. goto Ret;
  6493. }
  6494. Ret:
  6495. return pwszName;
  6496. }
  6497. //--------------------------------------------------------------------------
  6498. //
  6499. // AERetrieveGeneralInfo
  6500. //
  6501. //
  6502. //--------------------------------------------------------------------------
  6503. BOOL AERetrieveGeneralInfo(AE_GENERAL_INFO *pAE_General_Info)
  6504. {
  6505. BOOL fResult = FALSE;
  6506. DWORD dwOpenStoreFlags = CERT_SYSTEM_STORE_CURRENT_USER;
  6507. DWORD cMachineName = MAX_COMPUTERNAME_LENGTH + 2;
  6508. LONG dwResult = 0;
  6509. SCARDCONTEXT hSCContext=NULL;
  6510. //get the client token
  6511. if(pAE_General_Info->fMachine)
  6512. {
  6513. if(!AENetLogonUser(NULL, NULL, NULL, &(pAE_General_Info->hToken)))
  6514. {
  6515. AE_DEBUG((AE_ERROR, L"Obtain local system's token (%lx)\n\r", GetLastError()));
  6516. goto Ret;
  6517. }
  6518. }
  6519. else
  6520. {
  6521. if(!AERetrieveClientToken(&(pAE_General_Info->hToken)))
  6522. goto Ret;
  6523. }
  6524. //get the machine name
  6525. if (!GetComputerNameW(pAE_General_Info->wszMachineName,
  6526. &cMachineName))
  6527. goto Ret;
  6528. if(pAE_General_Info->fMachine)
  6529. dwOpenStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  6530. //open my store
  6531. if (NULL == (pAE_General_Info->hMyStore = CertOpenStore(
  6532. CERT_STORE_PROV_SYSTEM_W,
  6533. ENCODING_TYPE,
  6534. NULL,
  6535. dwOpenStoreFlags,
  6536. MY_STORE)))
  6537. {
  6538. AE_DEBUG((AE_ERROR, L"Unable to open MY store (%lx)\n\r", GetLastError()));
  6539. goto Ret;
  6540. }
  6541. if(!CertControlStore(pAE_General_Info->hMyStore,
  6542. 0,
  6543. CERT_STORE_CTRL_AUTO_RESYNC,
  6544. NULL))
  6545. {
  6546. AE_DEBUG((AE_ERROR, L"Unable configure MY store for auto-resync(%lx)\n\r", GetLastError()));
  6547. goto Ret;
  6548. }
  6549. //open request store
  6550. if (NULL == (pAE_General_Info->hRequestStore = CertOpenStore(
  6551. CERT_STORE_PROV_SYSTEM_W,
  6552. ENCODING_TYPE,
  6553. NULL,
  6554. dwOpenStoreFlags,
  6555. REQUEST_STORE)))
  6556. {
  6557. AE_DEBUG((AE_ERROR, L"Unable to open Request store (%lx)\n\r", GetLastError()));
  6558. goto Ret;
  6559. }
  6560. //get CertType information
  6561. if(!AERetrieveCertTypeInfo( pAE_General_Info->pld,
  6562. pAE_General_Info->fMachine,
  6563. &(pAE_General_Info->dwCertType),
  6564. &(pAE_General_Info->rgCertTypeInfo)))
  6565. {
  6566. AE_DEBUG((AE_ERROR, L"Unable to retrieve CertType information (%lx)\n\r", GetLastError()));
  6567. goto Ret;
  6568. }
  6569. //load xenroll module. No need to check errors since this is not a fatal error
  6570. pAE_General_Info->hXenroll = LoadLibrary(L"xenroll.dll");
  6571. //detect if the smart card subsystem if running for users only
  6572. if(FALSE == pAE_General_Info->fMachine)
  6573. {
  6574. dwResult = SCardEstablishContext(
  6575. SCARD_SCOPE_USER,
  6576. NULL,
  6577. NULL,
  6578. &hSCContext );
  6579. if((0 == dwResult) && (NULL != hSCContext))
  6580. pAE_General_Info->fSmartcardSystem=TRUE;
  6581. }
  6582. //get the NetBIOS name and the DNS name of the computer. This is different from
  6583. //wszMachineName, since it will be the physicalNetBIOS name
  6584. //No need to check errors since this is not a fatal error
  6585. pAE_General_Info->pwszDns=AEGetComputerName(ComputerNameDnsFullyQualified);
  6586. pAE_General_Info->pwszNetBIOS=AEGetComputerName(ComputerNameNetBIOS);
  6587. fResult = TRUE;
  6588. Ret:
  6589. if(hSCContext)
  6590. SCardReleaseContext(hSCContext);
  6591. if(FALSE == fResult)
  6592. AEFreeGeneralInfo(pAE_General_Info);
  6593. return fResult;
  6594. }
  6595. //--------------------------------------------------------------------------
  6596. //
  6597. // AEFreeGeneralInfo
  6598. //
  6599. //
  6600. //--------------------------------------------------------------------------
  6601. BOOL AEFreeGeneralInfo(AE_GENERAL_INFO *pAE_General_Info)
  6602. {
  6603. if(pAE_General_Info)
  6604. {
  6605. if(pAE_General_Info->hToken)
  6606. CloseHandle(pAE_General_Info->hToken);
  6607. if(pAE_General_Info->hMyStore)
  6608. CertCloseStore(pAE_General_Info->hMyStore, 0);
  6609. if(pAE_General_Info->hRequestStore)
  6610. CertCloseStore(pAE_General_Info->hRequestStore, 0);
  6611. //free CA information
  6612. AEFreeCAInfo(pAE_General_Info->dwCA, pAE_General_Info->rgCAInfo);
  6613. //free CertType information
  6614. AEFreeCertTypeInfo(pAE_General_Info->dwCertType, pAE_General_Info->rgCertTypeInfo);
  6615. if(pAE_General_Info->hXenroll)
  6616. FreeLibrary(pAE_General_Info->hXenroll);
  6617. if(pAE_General_Info->hCancelEvent)
  6618. CloseHandle(pAE_General_Info->hCancelEvent);
  6619. if(pAE_General_Info->hCompleteEvent)
  6620. CloseHandle(pAE_General_Info->hCompleteEvent);
  6621. if(pAE_General_Info->hThread)
  6622. CloseHandle(pAE_General_Info->hThread);
  6623. if(pAE_General_Info->pwszDns)
  6624. LocalFree(pAE_General_Info->pwszDns);
  6625. if(pAE_General_Info->pwszNetBIOS)
  6626. LocalFree(pAE_General_Info->pwszNetBIOS);
  6627. memset(pAE_General_Info, 0, sizeof(AE_GENERAL_INFO));
  6628. }
  6629. return TRUE;
  6630. }
  6631. //--------------------------------------------------------------------------
  6632. //
  6633. // AERetrieveCertTypeInfo
  6634. //
  6635. //--------------------------------------------------------------------------
  6636. BOOL AERetrieveCertTypeInfo(LDAP *pld, BOOL fMachine, DWORD *pdwCertType, AE_CERTTYPE_INFO **prgCertType)
  6637. {
  6638. BOOL fResult=FALSE;
  6639. DWORD dwCount=0;
  6640. DWORD dwCertType=0;
  6641. DWORD dwIndex=0;
  6642. HRESULT hr=E_FAIL;
  6643. HCERTTYPE hCTCurrent = NULL;
  6644. HCERTTYPE hCTNew = NULL;
  6645. AE_CERTTYPE_INFO *rgCertTypeInfo=NULL;
  6646. *pdwCertType=0;
  6647. *prgCertType=NULL;
  6648. if(S_OK != (hr = CAEnumCertTypesEx(
  6649. (LPCWSTR)pld,
  6650. fMachine?CT_ENUM_MACHINE_TYPES | CT_FIND_LOCAL_SYSTEM | CT_FLAG_SCOPE_IS_LDAP_HANDLE: CT_ENUM_USER_TYPES | CT_FLAG_SCOPE_IS_LDAP_HANDLE,
  6651. &hCTCurrent)))
  6652. {
  6653. SetLastError(hr);
  6654. goto Ret;
  6655. }
  6656. if((NULL == hCTCurrent) || (0 == (dwCount = CACountCertTypes(hCTCurrent))))
  6657. {
  6658. AE_DEBUG((AE_WARNING, L"No CT's available for auto-enrollment\n\r"));
  6659. fResult=TRUE;
  6660. goto Ret;
  6661. }
  6662. rgCertTypeInfo=(AE_CERTTYPE_INFO *)LocalAlloc(LPTR, sizeof(AE_CERTTYPE_INFO) * dwCount);
  6663. if(NULL==rgCertTypeInfo)
  6664. {
  6665. SetLastError(E_OUTOFMEMORY);
  6666. goto Ret;
  6667. }
  6668. memset(rgCertTypeInfo, 0, sizeof(AE_CERTTYPE_INFO) * dwCount);
  6669. for(dwIndex = 0; dwIndex < dwCount; dwIndex++ )
  6670. {
  6671. //check if we have a new certificate template
  6672. if(dwIndex > 0)
  6673. {
  6674. hr = CAEnumNextCertType(hCTCurrent, &hCTNew);
  6675. if((S_OK != hr) || (NULL == hCTNew))
  6676. {
  6677. // Clean up from previous calls
  6678. if(dwCertType < dwCount)
  6679. AEFreeCertTypeStruct(&(rgCertTypeInfo[dwCertType]));
  6680. break;
  6681. }
  6682. hCTCurrent = hCTNew;
  6683. }
  6684. // Clean up from previous calls
  6685. AEFreeCertTypeStruct(&(rgCertTypeInfo[dwCertType]));
  6686. //copy the new CertType' data
  6687. //hCertType
  6688. rgCertTypeInfo[dwCertType].hCertType = hCTCurrent;
  6689. //CTName
  6690. hr = CAGetCertTypePropertyEx(
  6691. hCTCurrent,
  6692. CERTTYPE_PROP_DN,
  6693. &(rgCertTypeInfo[dwCertType].awszName));
  6694. if((S_OK != hr) ||
  6695. (NULL == rgCertTypeInfo[dwCertType].awszName) ||
  6696. (NULL == (rgCertTypeInfo[dwCertType].awszName)[0])
  6697. )
  6698. {
  6699. AE_DEBUG((AE_INFO, L"No name property for CertType\n\r"));
  6700. continue;
  6701. }
  6702. //FriendlyName
  6703. hr = CAGetCertTypePropertyEx(
  6704. hCTCurrent,
  6705. CERTTYPE_PROP_FRIENDLY_NAME,
  6706. &(rgCertTypeInfo[dwCertType].awszDisplay));
  6707. if((S_OK != hr) ||
  6708. (NULL == rgCertTypeInfo[dwCertType].awszDisplay) ||
  6709. (NULL == (rgCertTypeInfo[dwCertType].awszDisplay)[0])
  6710. )
  6711. {
  6712. AE_DEBUG((AE_INFO, L"No display property for CertType\n\r"));
  6713. //get the DN as the display name
  6714. hr = CAGetCertTypePropertyEx(
  6715. hCTCurrent,
  6716. CERTTYPE_PROP_DN,
  6717. &(rgCertTypeInfo[dwCertType].awszDisplay));
  6718. if((S_OK != hr) ||
  6719. (NULL == rgCertTypeInfo[dwCertType].awszDisplay) ||
  6720. (NULL == (rgCertTypeInfo[dwCertType].awszDisplay)[0])
  6721. )
  6722. {
  6723. AE_DEBUG((AE_INFO, L"No name property for CertType\n\r"));
  6724. continue;
  6725. }
  6726. }
  6727. //dwSchemaVersion
  6728. hr = CAGetCertTypePropertyEx(
  6729. hCTCurrent,
  6730. CERTTYPE_PROP_SCHEMA_VERSION,
  6731. &(rgCertTypeInfo[dwCertType].dwSchemaVersion));
  6732. if(hr != S_OK)
  6733. {
  6734. AE_DEBUG((AE_INFO, L"No schema version for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6735. continue;
  6736. }
  6737. //dwVersion
  6738. hr = CAGetCertTypePropertyEx(
  6739. hCTCurrent,
  6740. CERTTYPE_PROP_REVISION,
  6741. &(rgCertTypeInfo[dwCertType].dwVersion));
  6742. if(hr != S_OK)
  6743. {
  6744. AE_DEBUG((AE_INFO, L"No major version for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6745. continue;
  6746. }
  6747. //dwEnrollmentFlag
  6748. hr = CAGetCertTypeFlagsEx(
  6749. hCTCurrent,
  6750. CERTTYPE_ENROLLMENT_FLAG,
  6751. &(rgCertTypeInfo[dwCertType].dwEnrollmentFlag));
  6752. if(hr != S_OK)
  6753. {
  6754. AE_DEBUG((AE_INFO, L"No enrollment flag for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6755. continue;
  6756. }
  6757. //dwPrivatekeyFlag
  6758. hr = CAGetCertTypeFlagsEx(
  6759. hCTCurrent,
  6760. CERTTYPE_PRIVATE_KEY_FLAG,
  6761. &(rgCertTypeInfo[dwCertType].dwPrivateKeyFlag));
  6762. if(hr != S_OK)
  6763. {
  6764. AE_DEBUG((AE_INFO, L"No private key flag for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6765. continue;
  6766. }
  6767. //expiration offset
  6768. hr = CAGetCertTypeExpiration(
  6769. hCTCurrent,
  6770. NULL,
  6771. (LPFILETIME)&(rgCertTypeInfo[dwCertType].ftExpirationOffset));
  6772. //we might not get the expiration date
  6773. if(hr != S_OK)
  6774. {
  6775. AE_DEBUG((AE_WARNING, L"Could not get cert type expirations: %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6776. }
  6777. //oid
  6778. hr = CAGetCertTypePropertyEx(
  6779. hCTCurrent,
  6780. CERTTYPE_PROP_OID,
  6781. &(rgCertTypeInfo[dwCertType].awszOID));
  6782. //we might not get the oid property
  6783. if(rgCertTypeInfo[dwCertType].dwSchemaVersion >= CERTTYPE_SCHEMA_VERSION_2)
  6784. {
  6785. if((S_OK != hr) ||
  6786. (NULL == rgCertTypeInfo[dwCertType].awszOID) ||
  6787. (NULL == (rgCertTypeInfo[dwCertType].awszOID)[0])
  6788. )
  6789. {
  6790. AE_DEBUG((AE_INFO, L"No oid for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6791. continue;
  6792. }
  6793. }
  6794. //supersede
  6795. hr = CAGetCertTypePropertyEx(
  6796. hCTCurrent,
  6797. CERTTYPE_PROP_SUPERSEDE,
  6798. &(rgCertTypeInfo[dwCertType].awszSupersede));
  6799. //we might not get the supersede property
  6800. if(hr != S_OK)
  6801. {
  6802. AE_DEBUG((AE_INFO, L"No supersede for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6803. }
  6804. //hArchiveStore
  6805. if(NULL == (rgCertTypeInfo[dwCertType].hArchiveStore=CertOpenStore(
  6806. CERT_STORE_PROV_MEMORY,
  6807. ENCODING_TYPE,
  6808. NULL,
  6809. 0,
  6810. NULL)))
  6811. {
  6812. AE_DEBUG((AE_INFO, L"Unable to open archive cert store for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6813. continue;
  6814. }
  6815. //hObtainedStore
  6816. if(NULL == (rgCertTypeInfo[dwCertType].hObtainedStore=CertOpenStore(
  6817. CERT_STORE_PROV_MEMORY,
  6818. ENCODING_TYPE,
  6819. NULL,
  6820. 0,
  6821. NULL)))
  6822. {
  6823. AE_DEBUG((AE_INFO, L"Unable to open obtained cert store for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6824. continue;
  6825. }
  6826. //hIssuedStore
  6827. if(NULL == (rgCertTypeInfo[dwCertType].hIssuedStore=CertOpenStore(
  6828. CERT_STORE_PROV_MEMORY,
  6829. ENCODING_TYPE,
  6830. NULL,
  6831. 0,
  6832. NULL)))
  6833. {
  6834. AE_DEBUG((AE_INFO, L"Unable to open issued cert store for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6835. continue;
  6836. }
  6837. //allocate memory
  6838. rgCertTypeInfo[dwCertType].prgActive=(DWORD *)LocalAlloc(LPTR, sizeof(DWORD) * dwCount);
  6839. if(NULL == rgCertTypeInfo[dwCertType].prgActive)
  6840. {
  6841. AE_DEBUG((AE_INFO, L"Unable to allocate memory for CT %ls\n\r", (rgCertTypeInfo[dwCertType].awszName)[0]));
  6842. continue;
  6843. }
  6844. memset(rgCertTypeInfo[dwCertType].prgActive, 0, sizeof(DWORD) * dwCount);
  6845. dwCertType++;
  6846. }
  6847. *pdwCertType=dwCertType;
  6848. *prgCertType=rgCertTypeInfo;
  6849. fResult = TRUE;
  6850. Ret:
  6851. return fResult;
  6852. }
  6853. //--------------------------------------------------------------------------
  6854. //
  6855. // AEFreeCertTypeInfo
  6856. //
  6857. //
  6858. //--------------------------------------------------------------------------
  6859. BOOL AEFreeCertTypeInfo(DWORD dwCertType, AE_CERTTYPE_INFO *rgCertTypeInfo)
  6860. {
  6861. DWORD dwIndex=0;
  6862. if(rgCertTypeInfo)
  6863. {
  6864. for(dwIndex=0; dwIndex < dwCertType; dwIndex++)
  6865. AEFreeCertTypeStruct(&(rgCertTypeInfo[dwIndex]));
  6866. LocalFree(rgCertTypeInfo);
  6867. }
  6868. return TRUE;
  6869. }
  6870. //--------------------------------------------------------------------------
  6871. //
  6872. // AEFreeCertTypeStruct
  6873. //
  6874. //
  6875. //--------------------------------------------------------------------------
  6876. BOOL AEFreeCertTypeStruct(AE_CERTTYPE_INFO *pCertTypeInfo)
  6877. {
  6878. DWORD dwIndex=0;
  6879. if(pCertTypeInfo)
  6880. {
  6881. if(pCertTypeInfo->hCertType)
  6882. {
  6883. if(pCertTypeInfo->awszName)
  6884. CAFreeCertTypeProperty(pCertTypeInfo->hCertType, pCertTypeInfo->awszName);
  6885. if(pCertTypeInfo->awszDisplay)
  6886. CAFreeCertTypeProperty(pCertTypeInfo->hCertType, pCertTypeInfo->awszDisplay);
  6887. if(pCertTypeInfo->awszOID)
  6888. CAFreeCertTypeProperty(pCertTypeInfo->hCertType, pCertTypeInfo->awszOID);
  6889. if(pCertTypeInfo->awszSupersede)
  6890. CAFreeCertTypeProperty(pCertTypeInfo->hCertType, pCertTypeInfo->awszSupersede);
  6891. CACloseCertType(pCertTypeInfo->hCertType);
  6892. }
  6893. if(pCertTypeInfo->prgActive)
  6894. LocalFree(pCertTypeInfo->prgActive);
  6895. if(pCertTypeInfo->pOldCert)
  6896. CertFreeCertificateContext(pCertTypeInfo->pOldCert);
  6897. if(pCertTypeInfo->hArchiveStore)
  6898. CertCloseStore(pCertTypeInfo->hArchiveStore, 0);
  6899. if(pCertTypeInfo->hObtainedStore)
  6900. CertCloseStore(pCertTypeInfo->hObtainedStore, 0);
  6901. if(pCertTypeInfo->hIssuedStore)
  6902. CertCloseStore(pCertTypeInfo->hIssuedStore, 0);
  6903. if(pCertTypeInfo->dwPendCount)
  6904. {
  6905. if(pCertTypeInfo->rgPendInfo)
  6906. {
  6907. for(dwIndex=0; dwIndex < pCertTypeInfo->dwPendCount; dwIndex++)
  6908. {
  6909. if((pCertTypeInfo->rgPendInfo[dwIndex]).blobPKCS7.pbData)
  6910. LocalFree((pCertTypeInfo->rgPendInfo[dwIndex]).blobPKCS7.pbData);
  6911. if((pCertTypeInfo->rgPendInfo[dwIndex]).blobHash.pbData)
  6912. LocalFree((pCertTypeInfo->rgPendInfo[dwIndex]).blobHash.pbData);
  6913. }
  6914. LocalFree(pCertTypeInfo->rgPendInfo);
  6915. }
  6916. }
  6917. memset(pCertTypeInfo, 0, sizeof(AE_CERTTYPE_INFO));
  6918. }
  6919. return TRUE;
  6920. }
  6921. //--------------------------------------------------------------------------
  6922. //
  6923. // AERetrieveCAInfo
  6924. //
  6925. //
  6926. //--------------------------------------------------------------------------
  6927. BOOL AERetrieveCAInfo(LDAP *pld, BOOL fMachine, HANDLE hToken, DWORD *pdwCA, AE_CA_INFO **prgCAInfo)
  6928. {
  6929. BOOL fResult = FALSE;
  6930. DWORD dwCount=0;
  6931. DWORD dwCA=0;
  6932. DWORD dwIndex=0;
  6933. HRESULT hr=E_FAIL;
  6934. HCAINFO hCACurrent = NULL;
  6935. HCAINFO hCANew = NULL;
  6936. AE_CA_INFO *rgCAInfo=NULL;
  6937. *pdwCA=0;
  6938. *prgCAInfo=NULL;
  6939. if(S_OK != (hr = CAEnumFirstCA(
  6940. (LPCWSTR)pld,
  6941. CA_FLAG_SCOPE_IS_LDAP_HANDLE | (fMachine?CA_FIND_LOCAL_SYSTEM:0),
  6942. &hCACurrent)))
  6943. {
  6944. SetLastError(hr);
  6945. goto Ret;
  6946. }
  6947. if((NULL == hCACurrent) || (0 == (dwCount = CACountCAs(hCACurrent))))
  6948. {
  6949. AE_DEBUG((AE_WARNING, L"No CA's available for auto-enrollment\n\r"));
  6950. fResult=TRUE;
  6951. goto Ret;
  6952. }
  6953. rgCAInfo=(AE_CA_INFO *)LocalAlloc(LPTR, sizeof(AE_CA_INFO) * dwCount);
  6954. if(NULL==rgCAInfo)
  6955. {
  6956. SetLastError(E_OUTOFMEMORY);
  6957. goto Ret;
  6958. }
  6959. memset(rgCAInfo, 0, sizeof(AE_CA_INFO) * dwCount);
  6960. for(dwIndex = 0; dwIndex < dwCount; dwIndex++ )
  6961. {
  6962. //check if we have a new CA
  6963. if(dwIndex > 0)
  6964. {
  6965. hr = CAEnumNextCA(hCACurrent, &hCANew);
  6966. if((S_OK != hr) || (NULL == hCANew))
  6967. {
  6968. // Clean up from previous calls
  6969. if(dwCA < dwCount)
  6970. AEFreeCAStruct(&(rgCAInfo[dwCA]));
  6971. break;
  6972. }
  6973. hCACurrent = hCANew;
  6974. }
  6975. // Clean up from previous calls
  6976. AEFreeCAStruct(&(rgCAInfo[dwCA]));
  6977. //copy the new CA' data
  6978. //hCAInfo
  6979. rgCAInfo[dwCA].hCAInfo = hCACurrent;
  6980. //CAName
  6981. hr = CAGetCAProperty(hCACurrent,
  6982. CA_PROP_NAME,
  6983. &(rgCAInfo[dwCA].awszCAName));
  6984. if((S_OK != hr) ||
  6985. (NULL == rgCAInfo[dwCA].awszCAName) ||
  6986. (NULL == (rgCAInfo[dwCA].awszCAName)[0])
  6987. )
  6988. {
  6989. AE_DEBUG((AE_INFO, L"No name property for ca\n\r"));
  6990. continue;
  6991. }
  6992. //access check
  6993. if(S_OK != CAAccessCheckEx(rgCAInfo[dwCA].hCAInfo, hToken, CERTTYPE_ACCESS_CHECK_ENROLL | CERTTYPE_ACCESS_CHECK_NO_MAPPING))
  6994. {
  6995. AE_DEBUG((AE_INFO, L"No access for CA %ls\n\r", (rgCAInfo[dwCA].awszCAName)[0]));
  6996. continue;
  6997. }
  6998. //CA Display
  6999. hr = CAGetCAProperty(hCACurrent,
  7000. CA_PROP_DISPLAY_NAME,
  7001. &(rgCAInfo[dwCA].awszCADisplay));
  7002. if((S_OK != hr) ||
  7003. (NULL == rgCAInfo[dwCA].awszCADisplay) ||
  7004. (NULL == (rgCAInfo[dwCA].awszCADisplay)[0])
  7005. )
  7006. {
  7007. AE_DEBUG((AE_INFO, L"No display name property for ca\n\r"));
  7008. hr = CAGetCAProperty(hCACurrent,
  7009. CA_PROP_NAME,
  7010. &(rgCAInfo[dwCA].awszCADisplay));
  7011. if((S_OK != hr) ||
  7012. (NULL == rgCAInfo[dwCA].awszCADisplay) ||
  7013. (NULL == (rgCAInfo[dwCA].awszCADisplay)[0])
  7014. )
  7015. {
  7016. AE_DEBUG((AE_INFO, L"No name property for ca\n\r"));
  7017. continue;
  7018. }
  7019. }
  7020. //CADNS
  7021. hr = CAGetCAProperty(hCACurrent,
  7022. CA_PROP_DNSNAME,
  7023. &(rgCAInfo[dwCA].awszCADNS));
  7024. if((S_OK != hr) ||
  7025. (NULL == rgCAInfo[dwCA].awszCADNS) ||
  7026. (NULL == (rgCAInfo[dwCA].awszCADNS)[0])
  7027. )
  7028. {
  7029. AE_DEBUG((AE_INFO, L"No DNS property for CA %ls\n\r", (rgCAInfo[dwCA].awszCAName)[0]));
  7030. continue;
  7031. }
  7032. //CACertificateTemplate
  7033. hr = CAGetCAProperty(hCACurrent,
  7034. CA_PROP_CERT_TYPES,
  7035. &(rgCAInfo[dwCA].awszCertificateTemplate));
  7036. if((S_OK != hr) ||
  7037. (NULL == rgCAInfo[dwCA].awszCertificateTemplate) ||
  7038. (NULL == (rgCAInfo[dwCA].awszCertificateTemplate)[0])
  7039. )
  7040. {
  7041. AE_DEBUG((AE_INFO, L"No CertType property for CA %ls\n\r", (rgCAInfo[dwCA].awszCAName)[0]));
  7042. continue;
  7043. }
  7044. dwCA++;
  7045. }
  7046. *pdwCA=dwCA;
  7047. *prgCAInfo=rgCAInfo;
  7048. fResult = TRUE;
  7049. Ret:
  7050. return fResult;
  7051. }
  7052. //--------------------------------------------------------------------------
  7053. //
  7054. // AEFreeCAInfo
  7055. //
  7056. //
  7057. //--------------------------------------------------------------------------
  7058. BOOL AEFreeCAInfo(DWORD dwCA, AE_CA_INFO *rgCAInfo)
  7059. {
  7060. DWORD dwIndex=0;
  7061. if(rgCAInfo)
  7062. {
  7063. for(dwIndex=0; dwIndex < dwCA; dwIndex++)
  7064. AEFreeCAStruct(&(rgCAInfo[dwIndex]));
  7065. LocalFree(rgCAInfo);
  7066. }
  7067. return TRUE;
  7068. }
  7069. //--------------------------------------------------------------------------
  7070. //
  7071. // AEFreeCAStruct
  7072. //
  7073. //
  7074. //--------------------------------------------------------------------------
  7075. BOOL AEFreeCAStruct(AE_CA_INFO *pCAInfo)
  7076. {
  7077. if(pCAInfo)
  7078. {
  7079. if(pCAInfo->hCAInfo)
  7080. {
  7081. if(pCAInfo->awszCAName)
  7082. {
  7083. CAFreeCAProperty(pCAInfo->hCAInfo,pCAInfo->awszCAName);
  7084. }
  7085. if(pCAInfo->awszCADisplay)
  7086. {
  7087. CAFreeCAProperty(pCAInfo->hCAInfo,pCAInfo->awszCADisplay);
  7088. }
  7089. if(pCAInfo->awszCADNS)
  7090. {
  7091. CAFreeCAProperty(pCAInfo->hCAInfo, pCAInfo->awszCADNS);
  7092. }
  7093. if(pCAInfo->awszCertificateTemplate)
  7094. {
  7095. CAFreeCAProperty(pCAInfo->hCAInfo,pCAInfo->awszCertificateTemplate);
  7096. }
  7097. CACloseCA(pCAInfo->hCAInfo);
  7098. }
  7099. memset(pCAInfo, 0, sizeof(AE_CA_INFO));
  7100. }
  7101. return TRUE;
  7102. }
  7103. //--------------------------------------------------------------------------
  7104. //
  7105. // AEClearVistedFlag
  7106. //
  7107. //--------------------------------------------------------------------------
  7108. BOOL AEClearVistedFlag(AE_GENERAL_INFO *pAE_General_Info)
  7109. {
  7110. DWORD dwIndex=0;
  7111. if(pAE_General_Info)
  7112. {
  7113. if(pAE_General_Info->rgCertTypeInfo)
  7114. {
  7115. for(dwIndex=0; dwIndex < pAE_General_Info->dwCertType; dwIndex++)
  7116. {
  7117. (pAE_General_Info->rgCertTypeInfo)[dwIndex].fSupersedeVisited=FALSE;
  7118. }
  7119. }
  7120. }
  7121. return TRUE;
  7122. }
  7123. //--------------------------------------------------------------------------
  7124. //
  7125. // AEIfSupersede
  7126. //
  7127. // Recursively find if pwsz is superseded by one of the template in awsz.
  7128. // Notice that we should not loop in the superseding relationship.
  7129. // Superseding tree should be one directional tree without duplicated nodes.
  7130. //
  7131. //--------------------------------------------------------------------------
  7132. BOOL AEIfSupersede(LPWSTR pwsz, LPWSTR *awsz, AE_GENERAL_INFO *pAE_General_Info)
  7133. {
  7134. BOOL fResult = FALSE;
  7135. LPWSTR *pwszArray = awsz;
  7136. AE_TEMPLATE_INFO AETemplateInfo;
  7137. AE_CERTTYPE_INFO *pCertType = NULL;
  7138. LPWSTR *awszSupersede=NULL;
  7139. if((NULL==pwsz) || (NULL==awsz))
  7140. return FALSE;
  7141. while(*pwszArray)
  7142. {
  7143. if(0 == wcscmp(pwsz, *pwszArray))
  7144. {
  7145. fResult = TRUE;
  7146. break;
  7147. }
  7148. //find the template
  7149. memset(&AETemplateInfo, 0, sizeof(AE_TEMPLATE_INFO));
  7150. AETemplateInfo.pwszName=*pwszArray;
  7151. pCertType = AEFindTemplateInRequestTree(
  7152. &AETemplateInfo,
  7153. pAE_General_Info);
  7154. if(pCertType)
  7155. {
  7156. if(!(pCertType->fSupersedeVisited))
  7157. {
  7158. //mark that we have visited superseding relationship for this template
  7159. pCertType->fSupersedeVisited=TRUE;
  7160. if(S_OK == CAGetCertTypePropertyEx(
  7161. pCertType->hCertType,
  7162. CERTTYPE_PROP_SUPERSEDE,
  7163. &(awszSupersede)))
  7164. {
  7165. fResult = AEIfSupersede(pwsz, awszSupersede, pAE_General_Info);
  7166. if(awszSupersede)
  7167. CAFreeCertTypeProperty(
  7168. pCertType->hCertType,
  7169. awszSupersede);
  7170. awszSupersede=NULL;
  7171. if(TRUE == fResult)
  7172. break;
  7173. }
  7174. }
  7175. }
  7176. pwszArray++;
  7177. }
  7178. return fResult;
  7179. }
  7180. //--------------------------------------------------------------------------
  7181. //
  7182. // AEIsAnElement
  7183. //
  7184. //
  7185. //--------------------------------------------------------------------------
  7186. BOOL AEIsAnElement(LPWSTR pwsz, LPWSTR *awsz)
  7187. {
  7188. BOOL fResult = FALSE;
  7189. LPWSTR *pwszArray = awsz;
  7190. if((NULL==pwsz) || (NULL==awsz))
  7191. return FALSE;
  7192. while(*pwszArray)
  7193. {
  7194. if(0 == wcscmp(pwsz, *pwszArray))
  7195. {
  7196. fResult = TRUE;
  7197. break;
  7198. }
  7199. pwszArray++;
  7200. }
  7201. return fResult;
  7202. }
  7203. //--------------------------------------------------------------------------
  7204. //
  7205. // AECopyCertStore
  7206. //
  7207. //
  7208. //--------------------------------------------------------------------------
  7209. BOOL AECopyCertStore(HCERTSTORE hSrcStore,
  7210. HCERTSTORE hDesStore)
  7211. {
  7212. PCCERT_CONTEXT pCertContext=NULL;
  7213. if((NULL==hSrcStore) || (NULL==hDesStore))
  7214. return FALSE;
  7215. while(pCertContext = CertEnumCertificatesInStore(hSrcStore, pCertContext))
  7216. {
  7217. CertAddCertificateContextToStore(hDesStore,
  7218. pCertContext,
  7219. CERT_STORE_ADD_USE_EXISTING,
  7220. NULL);
  7221. }
  7222. return TRUE;
  7223. }
  7224. //--------------------------------------------------------------------------
  7225. //
  7226. // AEIsEmptyStore
  7227. //
  7228. //
  7229. //--------------------------------------------------------------------------
  7230. BOOL AEIsEmptyStore(HCERTSTORE hCertStore)
  7231. {
  7232. PCCERT_CONTEXT pCertContext=NULL;
  7233. if(NULL == hCertStore)
  7234. return TRUE;
  7235. if(pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext))
  7236. {
  7237. CertFreeCertificateContext(pCertContext);
  7238. return FALSE;
  7239. }
  7240. return TRUE;
  7241. }
  7242. //--------------------------------------------------------------------------
  7243. //
  7244. // AEGetConfigDN
  7245. //
  7246. //
  7247. //--------------------------------------------------------------------------
  7248. HRESULT
  7249. AEGetConfigDN(
  7250. IN LDAP *pld,
  7251. OUT LPWSTR *pwszConfigDn
  7252. )
  7253. {
  7254. HRESULT hr;
  7255. ULONG LdapError;
  7256. LDAPMessage *SearchResult = NULL;
  7257. LDAPMessage *Entry = NULL;
  7258. WCHAR *Attr = NULL;
  7259. BerElement *BerElement;
  7260. WCHAR **Values = NULL;
  7261. WCHAR *AttrArray[3];
  7262. struct l_timeval timeout;
  7263. WCHAR *ConfigurationNamingContext = L"configurationNamingContext";
  7264. WCHAR *ObjectClassFilter = L"objectCategory=*";
  7265. //
  7266. // Set the out parameters to null
  7267. //
  7268. if(pwszConfigDn)
  7269. {
  7270. *pwszConfigDn = NULL;
  7271. }
  7272. timeout.tv_sec = 300;
  7273. timeout.tv_usec = 0;
  7274. //
  7275. // Query for the ldap server oerational attributes to obtain the default
  7276. // naming context.
  7277. //
  7278. AttrArray[0] = ConfigurationNamingContext;
  7279. AttrArray[1] = NULL; // this is the sentinel
  7280. LdapError = ldap_search_ext_s(pld,
  7281. NULL,
  7282. LDAP_SCOPE_BASE,
  7283. ObjectClassFilter,
  7284. AttrArray,
  7285. FALSE,
  7286. NULL,
  7287. NULL,
  7288. &timeout,
  7289. 10000,
  7290. &SearchResult);
  7291. hr = HRESULT_FROM_WIN32(LdapMapErrorToWin32(LdapError));
  7292. if (S_OK == hr)
  7293. {
  7294. Entry = ldap_first_entry(pld, SearchResult);
  7295. if (Entry)
  7296. {
  7297. Values = ldap_get_values(pld,
  7298. Entry,
  7299. ConfigurationNamingContext);
  7300. if (Values && Values[0])
  7301. {
  7302. (*pwszConfigDn) = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*(wcslen(Values[0])+1));
  7303. if(NULL==(*pwszConfigDn))
  7304. hr=E_OUTOFMEMORY;
  7305. else
  7306. wcscpy((*pwszConfigDn), Values[0]);
  7307. }
  7308. ldap_value_free(Values);
  7309. }
  7310. if (pwszConfigDn && (!(*pwszConfigDn)))
  7311. {
  7312. // We could not get the default domain or out of memory - bail out
  7313. if(E_OUTOFMEMORY != hr)
  7314. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  7315. }
  7316. if(SearchResult)
  7317. {
  7318. ldap_msgfree(SearchResult);
  7319. }
  7320. }
  7321. return hr;
  7322. }
  7323. //--------------------------------------------------------------------------
  7324. //
  7325. // AERobustLdapBind
  7326. //
  7327. //--------------------------------------------------------------------------
  7328. HRESULT
  7329. AERobustLdapBind(
  7330. OUT LDAP ** ppldap)
  7331. {
  7332. HRESULT hr = S_OK;
  7333. BOOL fForceRediscovery = FALSE;
  7334. DWORD dwDSNameFlags= DS_RETURN_DNS_NAME | DS_BACKGROUND_ONLY;
  7335. LDAP *pld = NULL;
  7336. ULONG ulOptions = 0;
  7337. ULONG ldaperr=LDAP_SERVER_DOWN;
  7338. do {
  7339. if(fForceRediscovery)
  7340. {
  7341. dwDSNameFlags |= DS_FORCE_REDISCOVERY;
  7342. }
  7343. ldaperr = LDAP_SERVER_DOWN;
  7344. if(NULL != pld)
  7345. {
  7346. ldap_unbind(pld);
  7347. pld=NULL;
  7348. }
  7349. // bind to ds
  7350. if((pld = ldap_initW(NULL, LDAP_PORT)) == NULL)
  7351. {
  7352. ldaperr = LdapGetLastError();
  7353. }
  7354. else
  7355. {
  7356. ldaperr = ldap_set_option(pld, LDAP_OPT_GETDSNAME_FLAGS, (VOID *)&dwDSNameFlags);
  7357. if(LDAP_SUCCESS == ldaperr)
  7358. {
  7359. ldaperr = ldap_set_option(pld, LDAP_OPT_SIGN, LDAP_OPT_ON);
  7360. if (LDAP_SUCCESS == ldaperr)
  7361. {
  7362. ldaperr = ldap_bind_sW(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  7363. }
  7364. }
  7365. }
  7366. hr = HRESULT_FROM_WIN32(LdapMapErrorToWin32(ldaperr));
  7367. if(fForceRediscovery)
  7368. {
  7369. break;
  7370. }
  7371. fForceRediscovery = TRUE;
  7372. } while(ldaperr == LDAP_SERVER_DOWN);
  7373. if(S_OK != hr)
  7374. goto error;
  7375. *ppldap = pld;
  7376. pld = NULL;
  7377. hr=S_OK;
  7378. error:
  7379. if(pld)
  7380. {
  7381. ldap_unbind(pld);
  7382. }
  7383. return hr;
  7384. }
  7385. //---------------------------------------------------------------------------
  7386. //
  7387. // AEAllocAndCopy
  7388. //
  7389. //---------------------------------------------------------------------------
  7390. BOOL AEAllocAndCopy(LPWSTR pwszSrc, LPWSTR *ppwszDest)
  7391. {
  7392. if((NULL==ppwszDest) || (NULL==pwszSrc))
  7393. {
  7394. SetLastError(E_INVALIDARG);
  7395. return FALSE;
  7396. }
  7397. *ppwszDest=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (wcslen(pwszSrc) + 1));
  7398. if(NULL==(*ppwszDest))
  7399. {
  7400. SetLastError(E_OUTOFMEMORY);
  7401. return FALSE;
  7402. }
  7403. wcscpy(*ppwszDest, pwszSrc);
  7404. return TRUE;
  7405. }
  7406. //--------------------------------------------------------------------------
  7407. // Name: AELogAutoEnrollmentEvent
  7408. //
  7409. // Description: This function registers an event in the event log of the
  7410. // local machine. Takes an optional argument list.
  7411. //
  7412. //--------------------------------------------------------------------------
  7413. void AELogAutoEnrollmentEvent(IN DWORD dwLogLevel,
  7414. IN BOOL fError,
  7415. IN HRESULT hr,
  7416. IN DWORD dwEventId,
  7417. IN BOOL fMachine,
  7418. IN HANDLE hToken,
  7419. IN DWORD dwParamCount,
  7420. ...
  7421. )
  7422. {
  7423. BYTE FastBuffer[MAX_DN_SIZE];
  7424. DWORD cbUser =0;
  7425. BOOL fAlloced = FALSE;
  7426. PSID pSID = NULL;
  7427. WORD dwEventType = 0;
  7428. LPWSTR awszStrings[PENDING_ALLOC_SIZE + 3];
  7429. WORD cStrings = 0;
  7430. LPWSTR wszString = NULL;
  7431. WCHAR wszMsg[MAX_DN_SIZE];
  7432. WCHAR wszUser[MAX_DN_SIZE];
  7433. DWORD dwIndex=0;
  7434. DWORD dwSize=0;
  7435. HANDLE hEventSource = NULL;
  7436. LPWSTR wszHR=NULL;
  7437. PTOKEN_USER ptgUser = NULL;
  7438. va_list ArgList;
  7439. //check the log level; log errors and success by default
  7440. if(((dwEventId >> 30) < dwLogLevel) && ((dwEventId >> 30) != STATUS_SEVERITY_SUCCESS))
  7441. return;
  7442. if(NULL==(hEventSource = RegisterEventSourceW(NULL, EVENT_AUTO_NAME)))
  7443. return;
  7444. //copy the user/machine string
  7445. wszUser[0]=L'\0';
  7446. //use the user name for user case
  7447. if(FALSE == fMachine)
  7448. {
  7449. dwSize=MAX_DN_SIZE;
  7450. if(!GetUserNameEx(
  7451. NameSamCompatible, // name format
  7452. wszUser, // name buffer
  7453. &dwSize)) // size of name buffer
  7454. {
  7455. LoadStringW(g_hmodThisDll, IDS_USER, wszUser, MAX_DN_SIZE);
  7456. }
  7457. }
  7458. else
  7459. {
  7460. LoadStringW(g_hmodThisDll, IDS_MACHINE, wszUser, MAX_DN_SIZE);
  7461. }
  7462. awszStrings[cStrings++] = wszUser;
  7463. //copy the variable strings if present
  7464. va_start(ArgList, dwParamCount);
  7465. for(dwIndex=0; dwIndex < dwParamCount; dwIndex++)
  7466. {
  7467. wszString = va_arg(ArgList, LPWSTR);
  7468. awszStrings[cStrings++] = wszString;
  7469. if(cStrings >= PENDING_ALLOC_SIZE)
  7470. {
  7471. break;
  7472. }
  7473. }
  7474. va_end(ArgList);
  7475. //copy the hr error code
  7476. if(fError)
  7477. {
  7478. if(S_OK == hr)
  7479. hr=E_FAIL;
  7480. wsprintfW(wszMsg, L"0x%lx", hr);
  7481. awszStrings[cStrings++] = wszMsg;
  7482. if(0 != FormatMessage(
  7483. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  7484. NULL,
  7485. hr,
  7486. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  7487. (WCHAR *)&wszHR,
  7488. 0,
  7489. NULL))
  7490. {
  7491. if(wszHR)
  7492. {
  7493. awszStrings[cStrings++] = wszHR;
  7494. }
  7495. else
  7496. {
  7497. awszStrings[cStrings++]=L" ";
  7498. }
  7499. }
  7500. else
  7501. {
  7502. //provide an empty event log so that there will be no insertion strings
  7503. awszStrings[cStrings++]=L" ";
  7504. }
  7505. }
  7506. // check if the token is non zero is so then impersonating so get the SID
  7507. if((FALSE == fMachine) && (hToken))
  7508. {
  7509. ptgUser = (PTOKEN_USER)FastBuffer; // try fast buffer first
  7510. cbUser = MAX_DN_SIZE;
  7511. if (!GetTokenInformation(
  7512. hToken, // identifies access token
  7513. TokenUser, // TokenUser info type
  7514. ptgUser, // retrieved info buffer
  7515. cbUser, // size of buffer passed-in
  7516. &cbUser // required buffer size
  7517. ))
  7518. {
  7519. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  7520. {
  7521. if (NULL != (ptgUser = (PTOKEN_USER)LocalAlloc(LPTR, cbUser)))
  7522. {
  7523. fAlloced = TRUE;
  7524. // get the user info and assign the sid if able to
  7525. if (GetTokenInformation(
  7526. hToken, // identifies access token
  7527. TokenUser, // TokenUser info type
  7528. ptgUser, // retrieved info buffer
  7529. cbUser, // size of buffer passed-in
  7530. &cbUser // required buffer size
  7531. ))
  7532. {
  7533. pSID = ptgUser->User.Sid;
  7534. }
  7535. }
  7536. }
  7537. }
  7538. else
  7539. {
  7540. // assign the sid when fast buffer worked
  7541. pSID = ptgUser->User.Sid;
  7542. }
  7543. }
  7544. switch(dwEventId >> 30)
  7545. {
  7546. case 0:
  7547. dwEventType = EVENTLOG_SUCCESS;
  7548. break;
  7549. case 1:
  7550. dwEventType = EVENTLOG_INFORMATION_TYPE;
  7551. break;
  7552. case 2:
  7553. dwEventType = EVENTLOG_WARNING_TYPE;
  7554. break;
  7555. case 3:
  7556. dwEventType = EVENTLOG_ERROR_TYPE;
  7557. break;
  7558. }
  7559. ReportEventW(hEventSource, // handle of event source
  7560. dwEventType, // event type
  7561. 0, // event category
  7562. dwEventId, // event ID
  7563. pSID, // current user's SID
  7564. cStrings, // strings in lpszStrings
  7565. 0, // no bytes of raw data
  7566. (LPCWSTR*)awszStrings, // array of error strings
  7567. NULL // no raw data
  7568. );
  7569. if (hEventSource)
  7570. DeregisterEventSource(hEventSource);
  7571. if(fAlloced)
  7572. {
  7573. if(ptgUser)
  7574. LocalFree(ptgUser);
  7575. }
  7576. if(wszHR)
  7577. LocalFree(wszHR);
  7578. return;
  7579. }
  7580. //--------------------------------------------------------------------------
  7581. //
  7582. // FormatMessageUnicode
  7583. //
  7584. //--------------------------------------------------------------------------
  7585. BOOL FormatMessageUnicode(LPWSTR * ppwszFormat, UINT ids, ...)
  7586. {
  7587. // get format string from resources
  7588. WCHAR wszFormat[MAX_DN_SIZE];
  7589. va_list argList;
  7590. DWORD cbMsg=0;
  7591. BOOL fResult=FALSE;
  7592. if(NULL == ppwszFormat)
  7593. goto Ret;
  7594. if(!LoadStringW(g_hmodThisDll, ids, wszFormat, sizeof(wszFormat) / sizeof(wszFormat[0])))
  7595. goto Ret;
  7596. // format message into requested buffer
  7597. va_start(argList, ids);
  7598. cbMsg = FormatMessageW(
  7599. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  7600. wszFormat,
  7601. 0, // dwMessageId
  7602. 0, // dwLanguageId
  7603. (LPWSTR) (ppwszFormat),
  7604. 0, // minimum size to allocate
  7605. &argList);
  7606. va_end(argList);
  7607. if(!cbMsg)
  7608. goto Ret;
  7609. fResult=TRUE;
  7610. Ret:
  7611. return fResult;
  7612. }
  7613. //--------------------------------------------------------------------------
  7614. //
  7615. // AENetLogonUser
  7616. //
  7617. //Abstract:
  7618. //
  7619. // This module implements the network logon type by interfacing
  7620. // with the NT Lan Man Security Support Provider (NTLMSSP).
  7621. //
  7622. // If the logon succeds via the provided credentials, we duplicate
  7623. // the resultant Impersonation token to a Primary level token.
  7624. // This allows the result to be used in a call to CreateProcessAsUser
  7625. //
  7626. //Author:
  7627. //
  7628. // Scott Field (sfield) 09-Jun-96
  7629. //--------------------------------------------------------------------------
  7630. BOOL
  7631. AENetLogonUser(
  7632. LPTSTR UserName,
  7633. LPTSTR DomainName,
  7634. LPTSTR Password,
  7635. PHANDLE phToken
  7636. )
  7637. {
  7638. SECURITY_STATUS SecStatus;
  7639. CredHandle CredentialHandle1;
  7640. CredHandle CredentialHandle2;
  7641. CtxtHandle ClientContextHandle;
  7642. CtxtHandle ServerContextHandle;
  7643. SecPkgCredentials_Names sNames;
  7644. ULONG ContextAttributes;
  7645. ULONG PackageCount;
  7646. ULONG PackageIndex;
  7647. PSecPkgInfo PackageInfo;
  7648. DWORD cbMaxToken=0;
  7649. TimeStamp Lifetime;
  7650. SEC_WINNT_AUTH_IDENTITY AuthIdentity;
  7651. SecBufferDesc NegotiateDesc;
  7652. SecBuffer NegotiateBuffer;
  7653. SecBufferDesc ChallengeDesc;
  7654. SecBuffer ChallengeBuffer;
  7655. BOOL bSuccess = FALSE ; // assume this function will fail
  7656. NegotiateBuffer.pvBuffer = NULL;
  7657. ChallengeBuffer.pvBuffer = NULL;
  7658. sNames.sUserName = NULL;
  7659. ClientContextHandle.dwUpper = -1;
  7660. ClientContextHandle.dwLower = -1;
  7661. ServerContextHandle.dwUpper = -1;
  7662. ServerContextHandle.dwLower = -1;
  7663. CredentialHandle1.dwUpper = -1;
  7664. CredentialHandle1.dwLower = -1;
  7665. CredentialHandle2.dwUpper = -1;
  7666. CredentialHandle2.dwLower = -1;
  7667. //
  7668. // << this section could be cached in a repeat caller scenario >>
  7669. //
  7670. //
  7671. // Get info about the security packages.
  7672. //
  7673. if(EnumerateSecurityPackages(
  7674. &PackageCount,
  7675. &PackageInfo
  7676. ) != SEC_E_OK) return FALSE;
  7677. //
  7678. // loop through the packages looking for NTLM
  7679. //
  7680. for(PackageIndex = 0 ; PackageIndex < PackageCount ; PackageIndex++ ) {
  7681. if(PackageInfo[PackageIndex].Name != NULL) {
  7682. if(CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, PackageInfo[PackageIndex].Name, -1, MICROSOFT_KERBEROS_NAME, -1) == CSTR_EQUAL) {
  7683. cbMaxToken = PackageInfo[PackageIndex].cbMaxToken;
  7684. bSuccess = TRUE;
  7685. break;
  7686. }
  7687. }
  7688. }
  7689. FreeContextBuffer( PackageInfo );
  7690. if(!bSuccess) return FALSE;
  7691. bSuccess = FALSE; // reset to assume failure
  7692. //
  7693. // << end of cached section >>
  7694. //
  7695. //
  7696. // Acquire a credential handle for the server side
  7697. //
  7698. SecStatus = AcquireCredentialsHandle(
  7699. NULL, // New principal
  7700. MICROSOFT_KERBEROS_NAME, // Package Name
  7701. SECPKG_CRED_INBOUND,
  7702. NULL,
  7703. NULL,
  7704. NULL,
  7705. NULL,
  7706. &CredentialHandle1,
  7707. &Lifetime
  7708. );
  7709. if ( SecStatus != SEC_E_OK ) {
  7710. goto cleanup;
  7711. }
  7712. //
  7713. // Acquire a credential handle for the client side
  7714. //
  7715. ZeroMemory( &AuthIdentity, sizeof(AuthIdentity) );
  7716. if ( DomainName != NULL ) {
  7717. AuthIdentity.Domain = DomainName;
  7718. AuthIdentity.DomainLength = lstrlen(DomainName);
  7719. }
  7720. if ( UserName != NULL ) {
  7721. AuthIdentity.User = UserName;
  7722. AuthIdentity.UserLength = lstrlen(UserName);
  7723. }
  7724. if ( Password != NULL ) {
  7725. AuthIdentity.Password = Password;
  7726. AuthIdentity.PasswordLength = lstrlen(Password);
  7727. }
  7728. AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  7729. SecStatus = AcquireCredentialsHandle(
  7730. NULL, // New principal
  7731. MICROSOFT_KERBEROS_NAME, // Package Name
  7732. SECPKG_CRED_OUTBOUND,
  7733. NULL,
  7734. (DomainName == NULL && UserName == NULL && Password == NULL) ?
  7735. NULL : &AuthIdentity,
  7736. NULL,
  7737. NULL,
  7738. &CredentialHandle2,
  7739. &Lifetime
  7740. );
  7741. if ( SecStatus != SEC_E_OK ) {
  7742. goto cleanup;
  7743. }
  7744. SecStatus = QueryCredentialsAttributes(&CredentialHandle1, SECPKG_CRED_ATTR_NAMES, &sNames);
  7745. if ( SecStatus != SEC_E_OK ) {
  7746. goto cleanup;
  7747. }
  7748. //
  7749. // Get the NegotiateMessage (ClientSide)
  7750. //
  7751. NegotiateDesc.ulVersion = 0;
  7752. NegotiateDesc.cBuffers = 1;
  7753. NegotiateDesc.pBuffers = &NegotiateBuffer;
  7754. NegotiateBuffer.cbBuffer = cbMaxToken;
  7755. NegotiateBuffer.BufferType = SECBUFFER_TOKEN;
  7756. NegotiateBuffer.pvBuffer = LocalAlloc( LMEM_FIXED, NegotiateBuffer.cbBuffer );
  7757. if ( NegotiateBuffer.pvBuffer == NULL ) {
  7758. goto cleanup;
  7759. }
  7760. SecStatus = InitializeSecurityContext(
  7761. &CredentialHandle2,
  7762. NULL, // No Client context yet
  7763. sNames.sUserName, // target name
  7764. ISC_REQ_SEQUENCE_DETECT,
  7765. 0, // Reserved 1
  7766. SECURITY_NATIVE_DREP,
  7767. NULL, // No initial input token
  7768. 0, // Reserved 2
  7769. &ClientContextHandle,
  7770. &NegotiateDesc,
  7771. &ContextAttributes,
  7772. &Lifetime
  7773. );
  7774. if(SecStatus != SEC_E_OK)
  7775. {
  7776. goto cleanup;
  7777. }
  7778. //
  7779. // Get the ChallengeMessage (ServerSide)
  7780. //
  7781. NegotiateBuffer.BufferType |= SECBUFFER_READONLY;
  7782. ChallengeDesc.ulVersion = 0;
  7783. ChallengeDesc.cBuffers = 1;
  7784. ChallengeDesc.pBuffers = &ChallengeBuffer;
  7785. ChallengeBuffer.cbBuffer = cbMaxToken;
  7786. ChallengeBuffer.BufferType = SECBUFFER_TOKEN;
  7787. ChallengeBuffer.pvBuffer = LocalAlloc( LMEM_FIXED, ChallengeBuffer.cbBuffer );
  7788. if ( ChallengeBuffer.pvBuffer == NULL ) {
  7789. goto cleanup;
  7790. }
  7791. SecStatus = AcceptSecurityContext(
  7792. &CredentialHandle1,
  7793. NULL, // No Server context yet
  7794. &NegotiateDesc,
  7795. ISC_REQ_SEQUENCE_DETECT,
  7796. SECURITY_NATIVE_DREP,
  7797. &ServerContextHandle,
  7798. &ChallengeDesc,
  7799. &ContextAttributes,
  7800. &Lifetime
  7801. );
  7802. if(SecStatus != SEC_E_OK)
  7803. {
  7804. goto cleanup;
  7805. }
  7806. if(QuerySecurityContextToken(&ServerContextHandle, phToken) != SEC_E_OK)
  7807. goto cleanup;
  7808. bSuccess = TRUE;
  7809. cleanup:
  7810. //
  7811. // Delete context
  7812. //
  7813. if((ClientContextHandle.dwUpper != -1) ||
  7814. (ClientContextHandle.dwLower != -1))
  7815. {
  7816. DeleteSecurityContext( &ClientContextHandle );
  7817. }
  7818. if((ServerContextHandle.dwUpper != -1) ||
  7819. (ServerContextHandle.dwLower != -1))
  7820. {
  7821. DeleteSecurityContext( &ServerContextHandle );
  7822. }
  7823. //
  7824. // Free credential handles
  7825. //
  7826. if((CredentialHandle1.dwUpper != -1) ||
  7827. (CredentialHandle1.dwLower != -1))
  7828. {
  7829. FreeCredentialsHandle( &CredentialHandle1 );
  7830. }
  7831. if((CredentialHandle2.dwUpper != -1) ||
  7832. (CredentialHandle2.dwLower != -1))
  7833. {
  7834. FreeCredentialsHandle( &CredentialHandle2 );
  7835. }
  7836. if ( NegotiateBuffer.pvBuffer != NULL ) {
  7837. //
  7838. // NegotiateBuffer.cbBuffer may change on the error path --
  7839. // use the original allocation size.
  7840. //
  7841. SecureZeroMemory( NegotiateBuffer.pvBuffer, cbMaxToken );
  7842. LocalFree( NegotiateBuffer.pvBuffer );
  7843. }
  7844. if ( ChallengeBuffer.pvBuffer != NULL ) {
  7845. //
  7846. // ChallengeBuffer.cbBuffer may change on the error path --
  7847. // use the original allocation size.
  7848. //
  7849. SecureZeroMemory( ChallengeBuffer.pvBuffer, cbMaxToken );
  7850. LocalFree( ChallengeBuffer.pvBuffer );
  7851. }
  7852. if ( sNames.sUserName != NULL ) {
  7853. FreeContextBuffer( sNames.sUserName );
  7854. }
  7855. return bSuccess;
  7856. }
  7857. //--------------------------------------------------------------------------
  7858. //
  7859. // AEDebugLog
  7860. //
  7861. //--------------------------------------------------------------------------
  7862. #if DBG
  7863. void
  7864. AEDebugLog(long Mask, LPCWSTR Format, ...)
  7865. {
  7866. va_list ArgList;
  7867. int iOut;
  7868. WCHAR wszOutString[MAX_DEBUG_BUFFER];
  7869. if (Mask & g_AutoenrollDebugLevel)
  7870. {
  7871. // Make the prefix first: "Process.Thread> GINA-XXX"
  7872. iOut=wsprintfW(wszOutString, L"%3u.%3u> AUTOENRL: ", GetCurrentProcessId(), GetCurrentThreadId());
  7873. if((iOut > 0) && (iOut < MAX_DEBUG_BUFFER - 1))
  7874. {
  7875. va_start(ArgList, Format);
  7876. _vsnwprintf(&wszOutString[iOut], MAX_DEBUG_BUFFER - iOut, Format, ArgList);
  7877. //null terminating the string
  7878. wszOutString[MAX_DEBUG_BUFFER - 1]=L'\0';
  7879. va_end(ArgList);
  7880. OutputDebugStringW(wszOutString);
  7881. }
  7882. }
  7883. }
  7884. #endif
  7885. //--------------------------------------------------------------------------
  7886. //
  7887. // AERemoveRegKey
  7888. //
  7889. // Remove the registry key for local system and all its sub keys.
  7890. //
  7891. //--------------------------------------------------------------------------
  7892. DWORD AERemoveRegKey(LPWSTR pwszRegKey)
  7893. {
  7894. DWORD dwLastError=0; //we should try to clean up as much as possible
  7895. DWORD dwIndex=0;
  7896. DWORD dwSubKey=0;
  7897. DWORD dwSubKeyLen=0;
  7898. DWORD dwData=0;
  7899. HKEY hDSKey=NULL;
  7900. LPWSTR pwszSubKey=NULL;
  7901. //remove the optimization registry. OK if the key does not exist
  7902. if(ERROR_SUCCESS != RegOpenKeyEx(
  7903. HKEY_LOCAL_MACHINE,
  7904. pwszRegKey,
  7905. 0,
  7906. KEY_ALL_ACCESS,
  7907. &hDSKey))
  7908. goto Ret;
  7909. //remove all subkeys of hDSKey
  7910. if(ERROR_SUCCESS != (dwLastError = RegQueryInfoKey(
  7911. hDSKey,
  7912. NULL,
  7913. NULL,
  7914. NULL,
  7915. &dwSubKey,
  7916. &dwSubKeyLen,
  7917. NULL,
  7918. NULL,
  7919. NULL,
  7920. NULL,
  7921. NULL,
  7922. NULL)))
  7923. goto Ret;
  7924. //terminating NULL
  7925. dwSubKeyLen++;
  7926. pwszSubKey=(LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * dwSubKeyLen);
  7927. if(NULL == pwszSubKey)
  7928. {
  7929. dwLastError=ERROR_NOT_ENOUGH_MEMORY;
  7930. goto Ret;
  7931. }
  7932. for(dwIndex=0; dwIndex < dwSubKey; dwIndex++)
  7933. {
  7934. dwData = dwSubKeyLen;
  7935. if(ERROR_SUCCESS == (dwLastError = RegEnumKeyEx(
  7936. hDSKey,
  7937. 0, // As we delete, the index changes
  7938. pwszSubKey,
  7939. &dwData,
  7940. NULL,
  7941. NULL,
  7942. NULL,
  7943. NULL)))
  7944. {
  7945. RegDeleteKey(hDSKey, pwszSubKey);
  7946. }
  7947. }
  7948. //remove the root registry key
  7949. dwLastError=RegDeleteKey(HKEY_LOCAL_MACHINE, pwszRegKey);
  7950. Ret:
  7951. if(pwszSubKey)
  7952. LocalFree(pwszSubKey);
  7953. if(hDSKey)
  7954. RegCloseKey(hDSKey);
  7955. return dwLastError;
  7956. }
  7957. //--------------------------------------------------------------------------
  7958. //
  7959. // CertAutoRemove
  7960. //
  7961. // Function to remove enterprise specific public key trust upon domain disjoin.
  7962. // Should be called under local admin's context.
  7963. //
  7964. // The function will:
  7965. // remove autoenrollment directory cache registry;
  7966. // remove certificates under root enterprise store;
  7967. // remove certificates under NTAuth enterprise store;
  7968. // remove certificates under CA enterprise store;
  7969. //
  7970. //
  7971. // Parameters:
  7972. // IN dwFlags:
  7973. // CERT_AUTO_REMOVE_COMMIT
  7974. // CERT_AUTO_REMOVE_ROLL_BACK
  7975. //
  7976. // Return Value:
  7977. // BOOL: TURE is upon success
  7978. //
  7979. //--------------------------------------------------------------------------
  7980. BOOL
  7981. WINAPI
  7982. CertAutoRemove(IN DWORD dwFlags)
  7983. {
  7984. DWORD dwError=0;
  7985. DWORD dwLastError=0; //we should try to clean up as much as possible
  7986. DWORD dwIndex=0;
  7987. PCCERT_CONTEXT pContext=NULL;
  7988. WCHAR wszNameBuf[64];
  7989. HANDLE hEvent=NULL;
  7990. HCERTSTORE hLocalStore=NULL;
  7991. if((CERT_AUTO_REMOVE_COMMIT != dwFlags) &&
  7992. (CERT_AUTO_REMOVE_ROLL_BACK != dwFlags))
  7993. {
  7994. dwLastError=ERROR_INVALID_PARAMETER;
  7995. goto Ret;
  7996. }
  7997. if(CERT_AUTO_REMOVE_ROLL_BACK == dwFlags)
  7998. {
  7999. //start machine autoenrollment
  8000. wcscpy(wszNameBuf, L"Global\\");
  8001. wcscat(wszNameBuf, MACHINE_AUTOENROLLMENT_TRIGGER_EVENT);
  8002. hEvent=OpenEvent(EVENT_MODIFY_STATE, FALSE, wszNameBuf);
  8003. if (NULL == hEvent)
  8004. {
  8005. dwLastError=GetLastError();
  8006. goto Ret;
  8007. }
  8008. if (!SetEvent(hEvent))
  8009. {
  8010. dwLastError=GetLastError();
  8011. goto Ret;
  8012. }
  8013. }
  8014. else
  8015. {
  8016. //remove all downloaded certificates
  8017. for(dwIndex =0; dwIndex < g_dwStoreInfo; dwIndex++)
  8018. {
  8019. hLocalStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  8020. 0,
  8021. 0,
  8022. CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
  8023. g_rgStoreInfo[dwIndex].pwszStoreName);
  8024. if(hLocalStore)
  8025. {
  8026. while(pContext = CertEnumCertificatesInStore(hLocalStore, pContext))
  8027. {
  8028. CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pContext));
  8029. }
  8030. CertCloseStore(hLocalStore,0);
  8031. hLocalStore=NULL;
  8032. }
  8033. }
  8034. //remove the local machine's DC GUID cache
  8035. dwLastError=AERemoveRegKey(AUTO_ENROLLMENT_DS_KEY);
  8036. dwError=AERemoveRegKey(AUTO_ENROLLMENT_TEMPLATE_KEY);
  8037. if(0 == dwLastError)
  8038. dwLastError=dwError;
  8039. }
  8040. Ret:
  8041. if(hLocalStore)
  8042. CertCloseStore(hLocalStore,0);
  8043. if (hEvent)
  8044. CloseHandle(hEvent);
  8045. if(0 != dwLastError)
  8046. {
  8047. SetLastError(dwLastError);
  8048. return FALSE;
  8049. }
  8050. return TRUE;
  8051. }
  8052. //--------------------------------------------------------------------------
  8053. //
  8054. // DLLMain
  8055. //
  8056. //
  8057. //--------------------------------------------------------------------------
  8058. extern "C"
  8059. BOOL WINAPI
  8060. DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  8061. {
  8062. BOOL fResult=TRUE;
  8063. INITCOMMONCONTROLSEX initcomm = {
  8064. sizeof(initcomm), ICC_NATIVEFNTCTL_CLASS | ICC_LISTVIEW_CLASSES | ICC_PROGRESS_CLASS
  8065. };
  8066. switch( dwReason )
  8067. {
  8068. case DLL_PROCESS_ATTACH:
  8069. g_hmodThisDll=hInstance;
  8070. DisableThreadLibraryCalls( hInstance );
  8071. //Init common control for progress bar
  8072. InitCommonControlsEx(&initcomm);
  8073. break;
  8074. case DLL_PROCESS_DETACH:
  8075. break;
  8076. }
  8077. return fResult;
  8078. }