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.

5138 lines
155 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: autoenrl.c
  3. *
  4. * Copyright (c) 1997, Microsoft Corporation
  5. *
  6. * Module for Public Key certificate auto enrollment
  7. *
  8. * History:
  9. * 11-21-97 jeffspel Created.
  10. * 01-30-98 jeffspel changed to include machine auto enrollment
  11. \***************************************************************************/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "tchar.h"
  15. #define AE_DEFAULT_REFRESH_RATE 8 // 8 hour default autoenrollment rate
  16. #define SYSTEM_POLICIES_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\System")
  17. #define MAX_TEMPLATE_NAME_VALUE_SIZE 64 // sizeof (CERT_NAME_VALUE) + wcslen(wszCERTTYPE_DC)
  18. #define MAX_DN_SIZE 256
  19. #define MACHINE_AUTOENROLL_INITIAL_DELAY 10 // seconds
  20. #define USER_AUTOENROLL_INITIAL_DELAY 120 // seconds
  21. LPWSTR g_wszEmptyExtension=L"Empty Extension";
  22. #if DBG
  23. DWORD g_AutoenrollDebugLevel = AE_ERROR ; //| AE_WARNING | AE_INFO | AE_TRACE;
  24. #endif
  25. PISECURITY_DESCRIPTOR AEMakeGenericSecurityDesc();
  26. //
  27. // Structure to hold information passed to Auto Enrollment threads
  28. //
  29. HANDLE g_hUserMutex = 0;
  30. HANDLE g_hMachineMutex = 0;
  31. #define DS_ATTR_COMMON_NAME TEXT("cn")
  32. #define DS_ATTR_DNS_NAME TEXT("dNSHostName")
  33. #define DS_ATTR_EMAIL_ADDR TEXT("mail")
  34. #define DS_ATTR_OBJECT_GUID TEXT("objectGUID")
  35. #define DS_ATTR_UPN TEXT("userPrincipalName")
  36. static HINSTANCE g_hInstSecur32 = NULL;
  37. static HINSTANCE g_hInstWldap32 = NULL;
  38. static PFNLDAP_INIT g_pfnldap_init = NULL;
  39. static PFNLDAP_BIND_S g_pfnldap_bind_s = NULL;
  40. static PFNLDAP_SET_OPTION g_pfnldap_set_option = NULL;
  41. static PFNLDAP_SEARCH_EXT_S g_pfnldap_search_ext_s = NULL;
  42. static PFNLDAP_FIRST_ENTRY g_pfnldap_first_entry = NULL;
  43. static PFNLDAP_EXPLODE_DN g_pfnldap_explode_dn = NULL;
  44. static PFNLDAP_GET_VALUES g_pfnldap_get_values = NULL;
  45. static PFNLDAP_VALUE_FREE g_pfnldap_value_free = NULL;
  46. static PFNLDAP_MSGFREE g_pfnldap_msgfree = NULL;
  47. static PFNLDAP_UNBIND g_pfnldap_unbind = NULL;
  48. static PFNLDAPGETLASTERROR g_pfnLdapGetLastError = NULL;
  49. static PFNLDAPMAPERRORTOWIN32 g_pfnLdapMapErrorToWin32 = NULL;
  50. static PFNGETUSERNAMEEX g_pfnGetUserNameEx = NULL;
  51. #ifndef CERT_ENTERPRISE_SYSTEM_STORE_REGPATH
  52. #define CERT_ENTERPRISE_SYSTEM_STORE_REGPATH L"Software\\Microsoft\\EnterpriseCertificates"
  53. #endif
  54. typedef struct _AUTO_ENROLL_THREAD_INFO_
  55. {
  56. BOOL fMachineEnrollment;
  57. HANDLE hNotifyEvent;
  58. HANDLE hTimer;
  59. HANDLE hToken;
  60. HANDLE hNotifyWait;
  61. HANDLE hTimerWait;
  62. } AUTO_ENROLL_THREAD_INFO, *PAUTO_ENROLL_THREAD_INFO;
  63. //
  64. // Structure to hold internal information needed perform Auto Enrollment
  65. //
  66. typedef struct _INTERNAL_CA_LIST_
  67. {
  68. HCAINFO hCAInfo;
  69. LPWSTR wszName;
  70. BYTE CACertHash[20];
  71. LPWSTR wszDNSName;
  72. LPWSTR *awszCertificateTemplates;
  73. } INTERNAL_CA_LIST, *PINTERNAL_CA_LIST;
  74. typedef struct _INTERNAL_INFO_
  75. {
  76. BOOL fMachineEnrollment;
  77. HANDLE hToken;
  78. HCERTSTORE hRootStore;
  79. HCERTSTORE hCAStore;
  80. HCERTSTORE hMYStore;
  81. LPTSTR * awszldap_UPN;
  82. LPTSTR wszConstructedUPN;
  83. LPTSTR * awszEmail;
  84. LPTSTR wszDN;
  85. CERT_NAME_BLOB blobDN;
  86. // List of all ca's
  87. DWORD ccaList;
  88. PINTERNAL_CA_LIST acaList;
  89. } INTERNAL_INFO, *PINTERNAL_INFO;
  90. typedef struct _AE_INSTANCE_INFO_
  91. {
  92. PCCTL_CONTEXT pCTLContext;
  93. PINTERNAL_INFO pInternalInfo;
  94. PCCERT_CONTEXT pOldCert;
  95. BOOL fRenewalOK;
  96. DWORD dwRandomIndex;
  97. LPWSTR pwszCertType;
  98. LPWSTR pwszAEIdentifier;
  99. CERT_EXTENSIONS *pCertTypeExtensions;
  100. DWORD dwCertTypeFlags;
  101. LARGE_INTEGER ftExpirationOffset;
  102. } AE_INSTANCE_INFO, *PAE_INSTANCE_INFO;
  103. // Key usage masks
  104. typedef struct _KUMASK {
  105. DWORD dwMask;
  106. LPSTR pszAlg;
  107. } KUMASK;
  108. KUMASK g_aKUMasks[] =
  109. {
  110. {~CERT_KEY_AGREEMENT_KEY_USAGE, szOID_RSA_RSA },
  111. {~CERT_KEY_ENCIPHERMENT_KEY_USAGE, szOID_OIWSEC_dsa },
  112. {~CERT_KEY_ENCIPHERMENT_KEY_USAGE, szOID_X957_DSA },
  113. {~CERT_KEY_ENCIPHERMENT_KEY_USAGE, szOID_ANSI_X942_DH },
  114. {~CERT_KEY_ENCIPHERMENT_KEY_USAGE, szOID_RSA_DH },
  115. {~CERT_KEY_AGREEMENT_KEY_USAGE, szOID_OIWSEC_rsaXchg },
  116. {~CERT_KEY_ENCIPHERMENT_KEY_USAGE, szOID_INFOSEC_mosaicKMandUpdSig }
  117. };
  118. DWORD g_cKUMasks = sizeof(g_aKUMasks)/sizeof(g_aKUMasks[0]);
  119. #define DEFAULT_AUTO_ENROLL_PROV "pautoenr.dll"
  120. #define AUTOENROLL_EVENT_LOG_SUBKEY L"System\\CurrentControlSet\\Services\\EventLog\\System\\AutoEnroll"
  121. #define SZ_AUTO_ENROLL L"AutoEnroll"
  122. HRESULT
  123. myGetConfigDN(
  124. IN LDAP *pld,
  125. OUT LPWSTR *pwszConfigDn
  126. );
  127. LPWSTR
  128. HelperExtensionToString(PCERT_EXTENSION Extension);
  129. HRESULT
  130. aeRobustLdapBind(
  131. OUT LDAP ** ppldap,
  132. IN BOOL fGC);
  133. //
  134. // Time skew margin for fast CA's
  135. //
  136. #define FILETIME_TICKS_PER_SECOND 10000000
  137. #define DEFAULT_AUTOENROLL_SKEW 60*60*1 // 1 hour
  138. //
  139. // ERROR values to be logged as events when auto enrollment fails
  140. //
  141. //
  142. // memory allocation and free routines
  143. void *AEAlloc(
  144. IN DWORD cb
  145. )
  146. {
  147. return LocalAlloc(LMEM_ZEROINIT, cb);
  148. }
  149. void AEFree(
  150. void *p
  151. )
  152. {
  153. LocalFree(p);
  154. }
  155. HRESULT GetExceptionError(EXCEPTION_POINTERS const *pep)
  156. {
  157. if((pep == NULL) || (pep->ExceptionRecord == NULL))
  158. {
  159. return E_UNEXPECTED;
  160. }
  161. return pep->ExceptionRecord->ExceptionCode;
  162. }
  163. //
  164. // Name: AELogTestResult
  165. //
  166. // Description: This function logs the result of a certificate
  167. // test into the AE_CERT_TEST_ARRAY
  168. //
  169. void AELogTestResult(PAE_CERT_TEST_ARRAY *ppAEData,
  170. DWORD idTest,
  171. ...)
  172. {
  173. va_list ArgList;
  174. va_start(ArgList, idTest);
  175. if((*ppAEData == NULL) ||
  176. ((*ppAEData)->cTests == (*ppAEData)->cMaxTests))
  177. {
  178. PAE_CERT_TEST_ARRAY pAENew = NULL;
  179. DWORD cAENew = ((*ppAEData)?(*ppAEData)->cMaxTests:0) +
  180. AE_CERT_TEST_SIZE_INCREMENT;
  181. // We need to grow the array
  182. pAENew = LocalAlloc(LMEM_FIXED, sizeof(AE_CERT_TEST_ARRAY) +
  183. (cAENew - ANYSIZE_ARRAY)*sizeof(AE_CERT_TEST));
  184. if(pAENew == NULL)
  185. {
  186. return;
  187. }
  188. pAENew->dwVersion = AE_CERT_TEST_ARRAY_VERSION;
  189. pAENew->fRenewalOK = ((*ppAEData)?(*ppAEData)->fRenewalOK:FALSE);
  190. pAENew->cTests = ((*ppAEData)?(*ppAEData)->cTests:0);
  191. pAENew->cMaxTests = cAENew;
  192. if((*ppAEData) && (pAENew->cTests != 0))
  193. {
  194. CopyMemory(pAENew->Test, (*ppAEData)->Test, sizeof(AE_CERT_TEST)*pAENew->cTests);
  195. }
  196. if(*ppAEData)
  197. {
  198. AEFree(*ppAEData);
  199. }
  200. (*ppAEData) = pAENew;
  201. }
  202. (*ppAEData)->Test[(*ppAEData)->cTests].idTest = idTest;
  203. if(FormatMessage(
  204. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  205. g_hInstance,
  206. idTest,
  207. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  208. (PVOID)&(*ppAEData)->Test[(*ppAEData)->cTests].pwszReason,
  209. 0,
  210. &ArgList))
  211. {
  212. (*ppAEData)->cTests++;
  213. }
  214. }
  215. void AEFreeTestResult(PAE_CERT_TEST_ARRAY *ppAEData)
  216. {
  217. DWORD iTest = 0;
  218. if((ppAEData == NULL) || (*ppAEData == NULL))
  219. {
  220. return;
  221. }
  222. for(iTest = 0; iTest < (*ppAEData)->cTests; iTest++)
  223. {
  224. if((*ppAEData)->Test[iTest].pwszReason)
  225. {
  226. LocalFree((*ppAEData)->Test[iTest].pwszReason);
  227. }
  228. }
  229. AEFree(*ppAEData);
  230. *ppAEData = NULL;
  231. }
  232. //
  233. // Name: LogAutoEnrollmentEvent
  234. //
  235. // Description: This function registers an event in the event log of the
  236. // local machine.
  237. //
  238. void LogAutoEnrollmentEvent(
  239. IN DWORD dwEventId,
  240. IN HANDLE hToken,
  241. ...
  242. )
  243. {
  244. HANDLE hEventSource = 0;
  245. BYTE FastBuffer[256];
  246. PTOKEN_USER ptgUser;
  247. DWORD cbUser;
  248. BOOL fAlloced = FALSE;
  249. PSID pSID = NULL;
  250. WORD dwEventType = 0;
  251. LPWSTR awszStrings[20];
  252. WORD cStrings = 0;
  253. LPWSTR wszString = NULL;
  254. va_list ArgList;
  255. va_start(ArgList, hToken);
  256. for(wszString = va_arg(ArgList, LPWSTR); wszString != NULL; wszString = va_arg(ArgList, LPWSTR))
  257. {
  258. awszStrings[cStrings++] = wszString;
  259. if(cStrings >= ARRAYSIZE(awszStrings))
  260. {
  261. break;
  262. }
  263. }
  264. va_end(ArgList);
  265. // event logging code
  266. hEventSource = RegisterEventSourceW(NULL, EVENTLOG_SOURCE);
  267. if(NULL == hEventSource)
  268. goto Ret;
  269. // check if the token is non zero is so then impersonating so get the SID
  270. if (hToken)
  271. {
  272. ptgUser = (PTOKEN_USER)FastBuffer; // try fast buffer first
  273. cbUser = 256;
  274. if (!GetTokenInformation(
  275. hToken, // identifies access token
  276. TokenUser, // TokenUser info type
  277. ptgUser, // retrieved info buffer
  278. cbUser, // size of buffer passed-in
  279. &cbUser // required buffer size
  280. ))
  281. {
  282. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  283. {
  284. //
  285. // try again with the specified buffer size
  286. //
  287. if (NULL != (ptgUser = (PTOKEN_USER)AEAlloc(cbUser)))
  288. {
  289. fAlloced = TRUE;
  290. // get the user info and assign the sid if able to
  291. if (GetTokenInformation(
  292. hToken, // identifies access token
  293. TokenUser, // TokenUser info type
  294. ptgUser, // retrieved info buffer
  295. cbUser, // size of buffer passed-in
  296. &cbUser // required buffer size
  297. ))
  298. {
  299. pSID = ptgUser->User.Sid;
  300. }
  301. }
  302. }
  303. }
  304. else
  305. {
  306. // assign the sid when fast buffer worked
  307. pSID = ptgUser->User.Sid;
  308. }
  309. }
  310. switch(dwEventId >> 30)
  311. {
  312. case 0:
  313. dwEventType = EVENTLOG_SUCCESS;
  314. break;
  315. case 1:
  316. dwEventType = EVENTLOG_INFORMATION_TYPE;
  317. break;
  318. case 2:
  319. dwEventType = EVENTLOG_WARNING_TYPE;
  320. break;
  321. case 3:
  322. dwEventType = EVENTLOG_ERROR_TYPE;
  323. break;
  324. }
  325. // UNDONE - probably want a string to go with the error code
  326. if (!ReportEventW(hEventSource, // handle of event source
  327. dwEventType, // event type
  328. 0, // event category
  329. dwEventId, // event ID
  330. pSID, // current user's SID
  331. cStrings, // strings in lpszStrings
  332. 0, // no bytes of raw data
  333. (LPCWSTR*)awszStrings,// array of error strings
  334. NULL // no raw data
  335. ))
  336. {
  337. goto Ret;
  338. }
  339. Ret:
  340. if (hEventSource)
  341. (VOID) DeregisterEventSource(hEventSource);
  342. return;
  343. }
  344. //
  345. // Name: LogAutoEnrollmentError
  346. //
  347. // Description: This function registers an event in the event log of the
  348. // local machine.
  349. //
  350. void LogAutoEnrollmentError(
  351. IN HRESULT hr,
  352. IN DWORD dwEventId,
  353. IN BOOL fMachineEnrollment,
  354. IN HANDLE hToken,
  355. IN LPWSTR wszCertType,
  356. IN LPWSTR wszCA
  357. )
  358. {
  359. HKEY hRegKey = 0;
  360. WCHAR szMsg[512];
  361. HANDLE hEventSource = 0;
  362. LPWSTR lpszStrings[4];
  363. WORD cStrings = 0;
  364. BYTE FastBuffer[256];
  365. PTOKEN_USER ptgUser;
  366. DWORD cbUser;
  367. BOOL fAlloced = FALSE;
  368. PSID pSID = NULL;
  369. WORD dwEventType = 0;
  370. // event logging code
  371. hEventSource = RegisterEventSourceW(NULL, EVENTLOG_SOURCE);
  372. if(NULL == hEventSource)
  373. goto Ret;
  374. wsprintfW(szMsg, L"0x%lx", hr);
  375. lpszStrings[cStrings++] = szMsg;
  376. FormatMessage(
  377. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  378. NULL,
  379. hr,
  380. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  381. (WCHAR *) &lpszStrings[cStrings++],
  382. 0,
  383. NULL);
  384. if(wszCertType)
  385. {
  386. lpszStrings[cStrings++] = wszCertType;
  387. }
  388. if(wszCA)
  389. {
  390. lpszStrings[cStrings++] = wszCA;
  391. }
  392. // check if the token is non zero is so then impersonating so get the SID
  393. if (hToken)
  394. {
  395. ptgUser = (PTOKEN_USER)FastBuffer; // try fast buffer first
  396. cbUser = 256;
  397. if (!GetTokenInformation(
  398. hToken, // identifies access token
  399. TokenUser, // TokenUser info type
  400. ptgUser, // retrieved info buffer
  401. cbUser, // size of buffer passed-in
  402. &cbUser // required buffer size
  403. ))
  404. {
  405. if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  406. {
  407. //
  408. // try again with the specified buffer size
  409. //
  410. if (NULL != (ptgUser = (PTOKEN_USER)AEAlloc(cbUser)))
  411. {
  412. fAlloced = TRUE;
  413. // get the user info and assign the sid if able to
  414. if (GetTokenInformation(
  415. hToken, // identifies access token
  416. TokenUser, // TokenUser info type
  417. ptgUser, // retrieved info buffer
  418. cbUser, // size of buffer passed-in
  419. &cbUser // required buffer size
  420. ))
  421. {
  422. pSID = ptgUser->User.Sid;
  423. }
  424. }
  425. }
  426. }
  427. else
  428. {
  429. // assign the sid when fast buffer worked
  430. pSID = ptgUser->User.Sid;
  431. }
  432. }
  433. switch(dwEventId >> 30)
  434. {
  435. case 0:
  436. dwEventType = EVENTLOG_SUCCESS;
  437. break;
  438. case 1:
  439. dwEventType = EVENTLOG_INFORMATION_TYPE;
  440. break;
  441. case 2:
  442. dwEventType = EVENTLOG_WARNING_TYPE;
  443. break;
  444. case 3:
  445. dwEventType = EVENTLOG_ERROR_TYPE;
  446. break;
  447. }
  448. // UNDONE - probably want a string to go with the error code
  449. if (!ReportEventW(hEventSource, // handle of event source
  450. dwEventType, // event type
  451. 0, // event category
  452. dwEventId, // event ID
  453. pSID, // current user's SID
  454. cStrings, // strings in lpszStrings
  455. 0, // no bytes of raw data
  456. (LPCWSTR*)lpszStrings,// array of error strings
  457. NULL // no raw data
  458. ))
  459. {
  460. goto Ret;
  461. }
  462. Ret:
  463. if (hRegKey)
  464. RegCloseKey(hRegKey);
  465. if (hEventSource)
  466. (VOID) DeregisterEventSource(hEventSource);
  467. if((cStrings == 2) && lpszStrings[1])
  468. {
  469. AEFree(lpszStrings[1]);
  470. }
  471. return;
  472. }
  473. //+-------------------------------------------------------------------------
  474. // Microsoft Auto Enrollment Object Identifiers
  475. //+-------------------------------------------------------------------------
  476. //
  477. // Name: LoadAndCallEnrollmentProvider
  478. //
  479. // Description: This function loads the specified Auto Enrollment provider,
  480. // and calls the entry point to that provider. It then
  481. // unloads the provider.
  482. //
  483. BOOL LoadAndCallEnrollmentProvider(
  484. IN BOOL fMachineEnrollment,
  485. IN PAUTO_ENROLL_INFO pEnrollmentInfo
  486. )
  487. {
  488. HANDLE hAutoEnrollProv = 0;
  489. FARPROC pEntryPoint = NULL;
  490. BOOL fRet = FALSE;
  491. AE_BEGIN(L"LoadAndCallEnrollmentProvider");
  492. // load the auto enrollment provider and get the entry point
  493. if (NULL == (hAutoEnrollProv =
  494. LoadLibraryA(pEnrollmentInfo->pszAutoEnrollProvider)))
  495. {
  496. AE_DEBUG((AE_ERROR, L"Could not load auto-enrollment provider %ls\n\r", pEnrollmentInfo->pszAutoEnrollProvider));
  497. goto Ret;
  498. }
  499. if (NULL == (pEntryPoint = GetProcAddress(hAutoEnrollProv,
  500. "ProvAutoEnrollment")))
  501. {
  502. AE_DEBUG((AE_ERROR, L"Entry point ProvAutoEnrollment not found in %ls\n\r", pEnrollmentInfo->pszAutoEnrollProvider));
  503. goto Ret;
  504. }
  505. if (FALSE == pEntryPoint(fMachineEnrollment, pEnrollmentInfo))
  506. {
  507. AE_DEBUG((AE_ERROR, L"Enrollment Failed, wizard returned %lx error\n", GetLastError()));
  508. LogAutoEnrollmentError(HRESULT_FROM_WIN32(GetLastError()),
  509. EVENT_AE_ENROLLMENT_FAILED,
  510. fMachineEnrollment,
  511. NULL,
  512. pEnrollmentInfo->pwszCertType, pEnrollmentInfo->pwszCAAuthority);
  513. goto Ret;
  514. }
  515. AE_DEBUG((AE_WARNING, L"Enrolled for a %ls certificate\n", pEnrollmentInfo->pwszCertType));
  516. fRet = TRUE;
  517. Ret:
  518. if (hAutoEnrollProv)
  519. FreeLibrary(hAutoEnrollProv);
  520. AE_END();
  521. return fRet;
  522. }
  523. //
  524. // Name: InitInternalInfo
  525. //
  526. // Description: This function initializes information needed to proceed with
  527. // auto enrollment.
  528. //
  529. HRESULT InitInternalInfo(
  530. LDAP *pld,
  531. IN BOOL fMachineEnrollment,
  532. IN HANDLE hToken,
  533. OUT PINTERNAL_INFO pInternalInfo
  534. )
  535. {
  536. HRESULT hrLocal = S_OK;
  537. HRESULT hrNetwork = S_OK;
  538. DWORD dwOpenStoreFlags = CERT_SYSTEM_STORE_CURRENT_USER;
  539. DWORD dwErr = 0;
  540. BOOL fRet = FALSE;
  541. DWORD ldaperr;
  542. DWORD cNameBuffer;
  543. LDAPMessage * SearchResult = NULL;
  544. LDAPMessage * PrincipalAttributes = NULL;
  545. HCAINFO hCACurrent = NULL;
  546. DWORD iCAIndex, cCA;
  547. DWORD cbHash;
  548. struct l_timeval timeout;
  549. // Initialize LDAP session
  550. LPTSTR wszSearchUser = TEXT("(objectCategory=user)");
  551. LPTSTR wszSearchComputer = TEXT("(objectCategory=computer)");
  552. // We want the following attributes
  553. LPTSTR AttrsUser[] = {
  554. DS_ATTR_COMMON_NAME,
  555. DS_ATTR_EMAIL_ADDR,
  556. DS_ATTR_OBJECT_GUID,
  557. DS_ATTR_UPN,
  558. NULL,
  559. };
  560. LPTSTR AttrsComputer[] = {
  561. DS_ATTR_COMMON_NAME,
  562. DS_ATTR_DNS_NAME,
  563. DS_ATTR_EMAIL_ADDR,
  564. DS_ATTR_OBJECT_GUID,
  565. DS_ATTR_UPN,
  566. NULL,
  567. };
  568. AE_BEGIN(L"InitInternalInfo");
  569. pInternalInfo->fMachineEnrollment = fMachineEnrollment;
  570. pInternalInfo->hToken = hToken;
  571. if (fMachineEnrollment)
  572. {
  573. dwOpenStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE;
  574. }
  575. // open the appropriate ROOT store
  576. if (NULL == (pInternalInfo->hRootStore = CertOpenStore(
  577. CERT_STORE_PROV_SYSTEM_W, 0, 0, dwOpenStoreFlags | CERT_STORE_READONLY_FLAG, L"ROOT")))
  578. {
  579. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  580. AE_DEBUG((AE_ERROR, L"Unable to open ROOT store (%lx)\n\r", hrLocal));
  581. goto Ret;
  582. }
  583. // open the appropriate CA store
  584. if (NULL == (pInternalInfo->hCAStore = CertOpenStore(
  585. CERT_STORE_PROV_SYSTEM_W, 0, 0, dwOpenStoreFlags | CERT_STORE_READONLY_FLAG, L"CA")))
  586. {
  587. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  588. AE_DEBUG((AE_ERROR, L"Unable to open CA store (%lx)\n\r", hrLocal));
  589. goto Ret;
  590. }
  591. // open the appropriate MY store
  592. if (NULL == (pInternalInfo->hMYStore = CertOpenStore(
  593. CERT_STORE_PROV_SYSTEM_W, 0, 0, dwOpenStoreFlags, L"MY")))
  594. {
  595. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  596. AE_DEBUG((AE_ERROR, L"Unable to open MY store (%lx)\n\r", hrLocal));
  597. goto Ret;
  598. }
  599. if(!CertControlStore(pInternalInfo->hMYStore, 0, CERT_STORE_CTRL_AUTO_RESYNC, NULL))
  600. {
  601. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  602. AE_DEBUG((AE_ERROR, L"Unable configure MY store for auto-resync(%lx)\n\r", hrLocal));
  603. goto Ret;
  604. }
  605. cNameBuffer = MAX_DN_SIZE;
  606. pInternalInfo->wszDN = AEAlloc(cNameBuffer*sizeof(TCHAR));
  607. if(pInternalInfo->wszDN == NULL)
  608. {
  609. hrLocal = E_OUTOFMEMORY;
  610. goto Ret;
  611. }
  612. if(!g_pfnGetUserNameEx(NameFullyQualifiedDN, pInternalInfo->wszDN, &cNameBuffer))
  613. {
  614. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  615. AE_DEBUG((AE_ERROR, L"GetUserNameEx Failed (%lx)\n\r", hrLocal));
  616. goto Ret;
  617. }
  618. // Normalize the directory DN into a
  619. // real BER encoded name
  620. pInternalInfo->blobDN.cbData = 0;
  621. CertStrToName(X509_ASN_ENCODING,
  622. pInternalInfo->wszDN,
  623. CERT_X500_NAME_STR,
  624. NULL,
  625. NULL,
  626. &pInternalInfo->blobDN.cbData,
  627. NULL);
  628. if(pInternalInfo->blobDN.cbData == 0)
  629. {
  630. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  631. goto Ret;
  632. }
  633. pInternalInfo->blobDN.pbData = AEAlloc(pInternalInfo->blobDN.cbData);
  634. if(pInternalInfo->blobDN.pbData == NULL)
  635. {
  636. hrLocal = E_OUTOFMEMORY;
  637. goto Ret;
  638. }
  639. if(!CertStrToName(X509_ASN_ENCODING,
  640. pInternalInfo->wszDN,
  641. CERT_X500_NAME_STR,
  642. NULL,
  643. pInternalInfo->blobDN.pbData,
  644. &pInternalInfo->blobDN.cbData,
  645. NULL))
  646. {
  647. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  648. AE_DEBUG((AE_ERROR, L"Could not encode DN (%lx)\n\r", hrLocal));
  649. goto Ret;
  650. }
  651. timeout.tv_sec = csecLDAPTIMEOUT;
  652. timeout.tv_usec = 0;
  653. ldaperr = g_pfnldap_search_ext_s(pld,
  654. pInternalInfo->wszDN,
  655. LDAP_SCOPE_BASE,
  656. (fMachineEnrollment?wszSearchComputer:wszSearchUser),
  657. (fMachineEnrollment?AttrsComputer:AttrsUser),
  658. 0,
  659. NULL,
  660. NULL,
  661. &timeout,
  662. 10000,
  663. &SearchResult);
  664. if(ldaperr != LDAP_SUCCESS)
  665. {
  666. hrNetwork = HRESULT_FROM_WIN32(g_pfnLdapMapErrorToWin32(ldaperr));
  667. AE_DEBUG((AE_ERROR, L"ldap_search_ext_s failed (%lx)\n\r", hrLocal));
  668. goto Ret;
  669. }
  670. PrincipalAttributes =
  671. g_pfnldap_first_entry(pld,
  672. SearchResult);
  673. if(NULL == PrincipalAttributes)
  674. {
  675. AE_DEBUG((AE_ERROR, L"no user entity found\n\r"));
  676. hrNetwork = HRESULT_FROM_WIN32(ERROR_NO_SUCH_USER);
  677. goto Ret;
  678. }
  679. if(fMachineEnrollment)
  680. {
  681. pInternalInfo->awszldap_UPN = g_pfnldap_get_values(pld,
  682. PrincipalAttributes,
  683. DS_ATTR_DNS_NAME);
  684. if((pInternalInfo->awszldap_UPN) &&
  685. (*pInternalInfo->awszldap_UPN))
  686. {
  687. AE_DEBUG((AE_INFO, L"ldap DNS Name %ls\n\r", *pInternalInfo->awszldap_UPN));
  688. }
  689. }
  690. else
  691. {
  692. pInternalInfo->awszldap_UPN = g_pfnldap_get_values(pld,
  693. PrincipalAttributes,
  694. DS_ATTR_UPN);
  695. if((pInternalInfo->awszldap_UPN == NULL) ||
  696. (*pInternalInfo->awszldap_UPN == NULL))
  697. {
  698. LPTSTR wszUPNBuffer = NULL;
  699. DWORD cbUPNBuffer = 0;
  700. LPTSTR *awszExplodedDN, * pwszCurrent;
  701. // Build a UPN. The UPN is built from
  702. // The username (without the SAM domain),
  703. // Get a buffer that will be big enough
  704. GetUserName(NULL, &cbUPNBuffer);
  705. if(cbUPNBuffer == 0)
  706. {
  707. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  708. goto Ret;
  709. }
  710. cbUPNBuffer += _tcslen(pInternalInfo->wszDN)*sizeof(TCHAR);
  711. wszUPNBuffer = AEAlloc(cbUPNBuffer);
  712. if(wszUPNBuffer == NULL)
  713. {
  714. hrLocal = E_OUTOFMEMORY;
  715. goto Ret;
  716. }
  717. if(!GetUserName(wszUPNBuffer, &cbUPNBuffer))
  718. {
  719. hrLocal = HRESULT_FROM_WIN32(GetLastError());
  720. goto Ret;
  721. }
  722. awszExplodedDN = g_pfnldap_explode_dn(pInternalInfo->wszDN, 0);
  723. if(awszExplodedDN != NULL)
  724. {
  725. _tcscat(wszUPNBuffer, TEXT("@"));
  726. pwszCurrent = awszExplodedDN;
  727. while(*pwszCurrent)
  728. {
  729. if(0 == _tcsncmp(*pwszCurrent, TEXT("DC="), 3))
  730. {
  731. _tcscat(wszUPNBuffer, (*pwszCurrent)+3);
  732. _tcscat(wszUPNBuffer, TEXT("."));
  733. }
  734. pwszCurrent++;
  735. }
  736. // remove the trailing '.' or "@" if there were no DC=
  737. wszUPNBuffer[_tcslen(wszUPNBuffer)-1] = 0;
  738. }
  739. pInternalInfo->wszConstructedUPN = wszUPNBuffer;
  740. AE_DEBUG((AE_INFO, L"Constructed UPN %ls\n\r", pInternalInfo->wszConstructedUPN));
  741. }
  742. else
  743. {
  744. AE_DEBUG((AE_INFO, L"ldap UPN %ls\n\r", *pInternalInfo->awszldap_UPN));
  745. }
  746. }
  747. pInternalInfo->awszEmail = g_pfnldap_get_values(pld,
  748. PrincipalAttributes,
  749. DS_ATTR_EMAIL_ADDR);
  750. if((pInternalInfo->awszEmail) &&
  751. (*pInternalInfo->awszEmail))
  752. {
  753. AE_DEBUG((AE_INFO, L"E-mail name %ls\n\r", *pInternalInfo->awszEmail));
  754. }
  755. // Build up the list of CA's
  756. // Build up the list of CA's
  757. hrNetwork = CAEnumFirstCA((LPCWSTR)pld,
  758. CA_FLAG_SCOPE_IS_LDAP_HANDLE |
  759. (fMachineEnrollment?CA_FIND_LOCAL_SYSTEM:0),
  760. &hCACurrent);
  761. if(hrNetwork != S_OK)
  762. {
  763. goto Ret;
  764. }
  765. if((hCACurrent == NULL) || (0 == (cCA = CACountCAs(hCACurrent))))
  766. {
  767. pInternalInfo->ccaList = 0;
  768. AE_DEBUG((AE_WARNING, L"No CA's available for auto-enrollment\n\r"));
  769. goto Ret;
  770. }
  771. pInternalInfo->acaList = (PINTERNAL_CA_LIST)AEAlloc(sizeof(INTERNAL_CA_LIST) * cCA);
  772. if(pInternalInfo->acaList == NULL)
  773. {
  774. hrLocal = E_OUTOFMEMORY;
  775. goto Ret;
  776. }
  777. ZeroMemory(pInternalInfo->acaList, sizeof(INTERNAL_CA_LIST) * cCA);
  778. AE_DEBUG((AE_INFO, L" %d CA's in enterprise\n\r", cCA));
  779. pInternalInfo->ccaList = 0;
  780. hrLocal = S_OK;
  781. hrNetwork = S_OK;
  782. for(iCAIndex = 0; iCAIndex < cCA; iCAIndex++ )
  783. {
  784. PCCERT_CONTEXT pCert = NULL;
  785. LPWSTR *awszName = NULL;
  786. HCAINFO hCANew = NULL;
  787. if(iCAIndex > 0)
  788. {
  789. hrNetwork = CAEnumNextCA(hCACurrent, &hCANew);
  790. }
  791. // Clean up from previous
  792. if(pInternalInfo->acaList[pInternalInfo->ccaList].wszName)
  793. {
  794. AEFree(pInternalInfo->acaList[pInternalInfo->ccaList].wszName);
  795. }
  796. if(pInternalInfo->acaList[pInternalInfo->ccaList].wszDNSName)
  797. {
  798. AEFree(pInternalInfo->acaList[pInternalInfo->ccaList].wszDNSName);
  799. }
  800. if(pInternalInfo->acaList[iCAIndex].awszCertificateTemplates)
  801. {
  802. CAFreeCAProperty(pInternalInfo->acaList[pInternalInfo->ccaList].hCAInfo,
  803. pInternalInfo->acaList[iCAIndex].awszCertificateTemplates);
  804. }
  805. if(pInternalInfo->acaList[pInternalInfo->ccaList].hCAInfo)
  806. {
  807. CACloseCA(pInternalInfo->acaList[pInternalInfo->ccaList].hCAInfo);
  808. pInternalInfo->acaList[pInternalInfo->ccaList].hCAInfo = NULL;
  809. }
  810. if((hrNetwork != S_OK) ||
  811. (hrLocal != S_OK))
  812. {
  813. break;
  814. }
  815. if(iCAIndex > 0)
  816. {
  817. hCACurrent = hCANew;
  818. }
  819. if(hCACurrent == NULL)
  820. {
  821. break;
  822. }
  823. pInternalInfo->acaList[pInternalInfo->ccaList].hCAInfo = hCACurrent;
  824. hrNetwork = CAGetCAProperty(hCACurrent,
  825. CA_PROP_NAME,
  826. & awszName);
  827. if(hrNetwork != S_OK)
  828. {
  829. AE_DEBUG((AE_INFO, L"No name property for ca\n\r"));
  830. // skip to the next one.
  831. hrNetwork = S_OK;
  832. continue;
  833. }
  834. if((awszName != NULL) && (*awszName != NULL))
  835. {
  836. pInternalInfo->acaList[pInternalInfo->ccaList].wszName = AEAlloc(sizeof(WCHAR)*(wcslen(*awszName)+1));
  837. if(pInternalInfo->acaList[pInternalInfo->ccaList].wszName == NULL)
  838. {
  839. CAFreeCAProperty(hCACurrent, awszName);
  840. hrLocal = E_OUTOFMEMORY;
  841. continue;
  842. }
  843. wcscpy(pInternalInfo->acaList[pInternalInfo->ccaList].wszName, *awszName);
  844. }
  845. else
  846. {
  847. AE_DEBUG((AE_INFO, L"No name property for ca\n\r"));
  848. if(awszName != NULL)
  849. {
  850. CAFreeCAProperty(hCACurrent, awszName);
  851. }
  852. // skip to the next one
  853. continue;
  854. }
  855. CAFreeCAProperty(hCACurrent, awszName);
  856. hrNetwork = CAGetCAProperty(hCACurrent,
  857. CA_PROP_DNSNAME,
  858. & awszName);
  859. if(hrNetwork != S_OK)
  860. {
  861. AE_DEBUG((AE_INFO, L"No DNS property for CA %ls\n\r", pInternalInfo->acaList[pInternalInfo->ccaList].wszName));
  862. hrNetwork = S_OK;
  863. continue;
  864. }
  865. if((awszName != NULL) && (*awszName != NULL))
  866. {
  867. pInternalInfo->acaList[pInternalInfo->ccaList].wszDNSName = AEAlloc(sizeof(WCHAR)*(wcslen(*awszName)+1));
  868. if(pInternalInfo->acaList[pInternalInfo->ccaList].wszDNSName == NULL)
  869. {
  870. CAFreeCAProperty(hCACurrent, awszName);
  871. hrLocal = E_OUTOFMEMORY;
  872. continue;
  873. }
  874. wcscpy(pInternalInfo->acaList[pInternalInfo->ccaList].wszDNSName, *awszName);
  875. }
  876. else
  877. {
  878. AE_DEBUG((AE_INFO, L"No DNS property for CA %ls\n\r", pInternalInfo->acaList[pInternalInfo->ccaList].wszName));
  879. if(awszName != NULL)
  880. {
  881. CAFreeCAProperty(hCACurrent, awszName);
  882. }
  883. continue;
  884. }
  885. CAFreeCAProperty(hCACurrent, awszName);
  886. hrNetwork = CAGetCAProperty(hCACurrent,
  887. CA_PROP_CERT_TYPES,
  888. & pInternalInfo->acaList[pInternalInfo->ccaList].awszCertificateTemplates);
  889. if(hrNetwork != S_OK)
  890. {
  891. AE_DEBUG((AE_INFO, L"No cert type property for CA %ls\n\r", pInternalInfo->acaList[pInternalInfo->ccaList].wszName));
  892. continue;
  893. }
  894. hrNetwork = CAGetCACertificate(hCACurrent, &pCert);
  895. if(hrNetwork != S_OK)
  896. {
  897. AE_DEBUG((AE_INFO, L"No certificate property for CA %ls\n\r", pInternalInfo->acaList[pInternalInfo->ccaList].wszName));
  898. continue;
  899. }
  900. cbHash = sizeof(pInternalInfo->acaList[pInternalInfo->ccaList].CACertHash);
  901. if(!CertGetCertificateContextProperty(pCert,
  902. CERT_SHA1_HASH_PROP_ID,
  903. pInternalInfo->acaList[pInternalInfo->ccaList].CACertHash,
  904. &cbHash))
  905. {
  906. continue;
  907. }
  908. CertFreeCertificateContext(pCert);
  909. AE_DEBUG((AE_INFO, L"CA %ls\\%ls available\n\r",
  910. pInternalInfo->acaList[pInternalInfo->ccaList].wszName,
  911. pInternalInfo->acaList[pInternalInfo->ccaList].wszDNSName));
  912. pInternalInfo->ccaList++;
  913. }
  914. if(pInternalInfo->ccaList == 0)
  915. {
  916. AE_DEBUG((AE_WARNING, L"No CA's available for auto-enrollment\n\r"));
  917. }
  918. fRet = TRUE;
  919. Ret:
  920. if (hrLocal != S_OK)
  921. {
  922. LogAutoEnrollmentError(hrLocal,
  923. EVENT_AE_LOCAL_CYCLE_INIT_FAILED,
  924. pInternalInfo->fMachineEnrollment,
  925. pInternalInfo->hToken,
  926. NULL, NULL);
  927. }
  928. if (hrNetwork != S_OK)
  929. {
  930. LogAutoEnrollmentError(hrNetwork,
  931. EVENT_AE_NETWORK_CYCLE_INIT_FAILED,
  932. pInternalInfo->fMachineEnrollment,
  933. pInternalInfo->hToken,
  934. NULL, NULL);
  935. }
  936. if(SearchResult)
  937. {
  938. g_pfnldap_msgfree(SearchResult);
  939. }
  940. AE_END();
  941. if(hrLocal != S_OK)
  942. {
  943. return hrLocal;
  944. }
  945. return hrNetwork;
  946. }
  947. //
  948. // Name: FreeInternalInfo
  949. //
  950. // Description: This function frees and resources which were needed for
  951. // auto enrollment.
  952. //
  953. void FreeInternalInfo(
  954. IN PINTERNAL_INFO pInternalInfo
  955. )
  956. {
  957. DWORD i;
  958. if (pInternalInfo->hRootStore)
  959. CertCloseStore(pInternalInfo->hRootStore, 0);
  960. if (pInternalInfo->hCAStore)
  961. CertCloseStore(pInternalInfo->hCAStore, 0);
  962. if (pInternalInfo->hMYStore)
  963. CertCloseStore(pInternalInfo->hMYStore, 0);
  964. if(pInternalInfo->awszldap_UPN)
  965. {
  966. g_pfnldap_value_free(pInternalInfo->awszldap_UPN);
  967. }
  968. if(pInternalInfo->awszEmail)
  969. {
  970. g_pfnldap_value_free(pInternalInfo->awszEmail);
  971. }
  972. if(pInternalInfo->wszDN)
  973. {
  974. AEFree(pInternalInfo->wszDN);
  975. }
  976. if(pInternalInfo->blobDN.pbData)
  977. {
  978. AEFree(pInternalInfo->blobDN.pbData);
  979. }
  980. if(pInternalInfo->wszConstructedUPN)
  981. {
  982. AEFree(pInternalInfo->wszConstructedUPN);
  983. }
  984. if( pInternalInfo->acaList )
  985. {
  986. for(i=0; i <pInternalInfo->ccaList; i++)
  987. {
  988. if(pInternalInfo->acaList[i].wszName)
  989. {
  990. AEFree(pInternalInfo->acaList[i].wszName);
  991. }
  992. if(pInternalInfo->acaList[i].wszDNSName)
  993. {
  994. AEFree(pInternalInfo->acaList[i].wszDNSName);
  995. }
  996. if(pInternalInfo->acaList[i].awszCertificateTemplates)
  997. {
  998. CAFreeCAProperty(pInternalInfo->acaList[i].hCAInfo,
  999. pInternalInfo->acaList[i].awszCertificateTemplates);
  1000. }
  1001. if(pInternalInfo->acaList[i].hCAInfo)
  1002. {
  1003. CACloseCA(pInternalInfo->acaList[i].hCAInfo);
  1004. }
  1005. }
  1006. AEFree(pInternalInfo->acaList);
  1007. }
  1008. }
  1009. //
  1010. // Name: InitInstance
  1011. //
  1012. // Description: This function initializes information needed to proceed with
  1013. // auto enrollment.
  1014. //
  1015. BOOL InitInstance(
  1016. IN PCCTL_CONTEXT pCTLContext,
  1017. IN PINTERNAL_INFO pInternalInfo,
  1018. OUT PAE_INSTANCE_INFO pInstance
  1019. )
  1020. {
  1021. FILETIME ft;
  1022. pInstance->pCTLContext = CertDuplicateCTLContext(pCTLContext);
  1023. pInstance->pInternalInfo = pInternalInfo;
  1024. // choose a random CA order
  1025. // Get the current time
  1026. GetSystemTimeAsFileTime(&ft);
  1027. // use mod to get something marginally random
  1028. // It's an index into the main list of ca's
  1029. if(pInternalInfo->ccaList)
  1030. {
  1031. pInstance->dwRandomIndex = ft.dwLowDateTime %
  1032. pInternalInfo->ccaList;
  1033. }
  1034. else
  1035. {
  1036. pInstance->dwRandomIndex = 0;
  1037. }
  1038. return TRUE;
  1039. }
  1040. //
  1041. // Name: FreeInstance
  1042. //
  1043. // Description: This function frees and resources which were needed for
  1044. // auto enrollment.
  1045. //
  1046. void FreeInstance(
  1047. IN PAE_INSTANCE_INFO pInstance
  1048. )
  1049. {
  1050. if (pInstance->pOldCert)
  1051. CertFreeCertificateContext(pInstance->pOldCert);
  1052. if (pInstance->pwszCertType)
  1053. AEFree(pInstance->pwszCertType);
  1054. if (pInstance->pwszAEIdentifier)
  1055. AEFree(pInstance->pwszAEIdentifier);
  1056. if (pInstance->pCertTypeExtensions) // use LocalFree b/c certcli.dll
  1057. LocalFree(pInstance->pCertTypeExtensions); // uses LocalAlloc to alloc
  1058. if(pInstance->pCTLContext)
  1059. {
  1060. CertFreeCTLContext(pInstance->pCTLContext);
  1061. }
  1062. }
  1063. // Name: SetEnrollmentType
  1064. //
  1065. // Description: This function retrieves additional enrollment information
  1066. // needed to enroll for a cert.
  1067. //
  1068. BOOL SetEnrollmentCertType(
  1069. IN PAE_INSTANCE_INFO pInstance,
  1070. OUT PAUTO_ENROLL_INFO pEnrollmentInfo
  1071. )
  1072. {
  1073. BOOL fRet = FALSE;
  1074. // copy over the cert extensions, this is freed by the FreeInternalInfo
  1075. // function, but after being used in the EnrollmentInfo struct
  1076. pEnrollmentInfo->CertExtensions.cExtension =
  1077. pInstance->pCertTypeExtensions->cExtension;
  1078. pEnrollmentInfo->CertExtensions.rgExtension =
  1079. pInstance->pCertTypeExtensions->rgExtension;
  1080. // copy over the cert type name, this is freed by the FreeInternalInfo
  1081. // function, but after being used in the EnrollmentInfo struct
  1082. pEnrollmentInfo->pwszCertType = pInstance->pwszCertType;
  1083. // The auto enrollment ID is used to uniquely tie an autoenrolled cert to
  1084. // it's autoenrollment object.
  1085. pEnrollmentInfo->pwszAutoEnrollmentID = pInstance->pwszAEIdentifier;
  1086. // copy over the handle to the MY store, this is freed by the
  1087. // FreeInternalInfo function, but after being used in the
  1088. // EnrollmentInfo struct
  1089. pEnrollmentInfo->hMYStore = pInstance->pInternalInfo->hMYStore;
  1090. // copy over the pointer to the cert context to be renewed, this
  1091. // is freed by the FreeInternalInfo function, but after being used in the
  1092. // EnrollmentInfo struct
  1093. if ((pInstance->pOldCert) && (pInstance->fRenewalOK))
  1094. {
  1095. pEnrollmentInfo->pOldCert = pInstance->pOldCert;
  1096. }
  1097. // Enrollment controll chooses provider type based on cert type
  1098. pEnrollmentInfo->dwProvType = 0;
  1099. // Enrollment controll chooses key spec based on cert type
  1100. pEnrollmentInfo->dwKeySpec = 0;
  1101. // UNDONE - currently the gen key flags is hard coded to 0x0
  1102. pEnrollmentInfo->dwGenKeyFlags = 0;
  1103. fRet = TRUE;
  1104. //Ret:
  1105. return fRet;
  1106. }
  1107. // Name: GetCertTypeInfo
  1108. //
  1109. // Description: This function retrieves information (the extensions) for the
  1110. // cert type specified in the ListIdentifier field of the auto enrollment
  1111. // object (CTL) in the internal info structure. In addition the
  1112. // function makes a call to check if the current entity has permission
  1113. // to enroll for this cert type.
  1114. //
  1115. BOOL GetCertTypeInfo(
  1116. IN OUT PAE_INSTANCE_INFO pInstance,
  1117. IN LDAP * pld,
  1118. OUT BOOL *pfPermissionToEnroll
  1119. )
  1120. {
  1121. HRESULT hr = S_OK;
  1122. HCERTTYPE hCertType = 0;
  1123. DWORD dwErr = 0;
  1124. BOOL fRet = FALSE;
  1125. LPWSTR *awszName = NULL;
  1126. LPWSTR wszCertTypeName = NULL;
  1127. CERT_EXTENSIONS CertTypeExtensions;
  1128. AE_BEGIN(L"GetCertTypeInfo");
  1129. *pfPermissionToEnroll = FALSE;
  1130. AE_DEBUG((AE_INFO, L"Found auto-enrollment object with cert type: %ls\n\r",
  1131. pInstance->pCTLContext->pCtlInfo->ListIdentifier.pbData));
  1132. wszCertTypeName = wcschr((LPWSTR)pInstance->pCTLContext->pCtlInfo->ListIdentifier.pbData, L'|');
  1133. if(wszCertTypeName)
  1134. {
  1135. wszCertTypeName++;
  1136. }
  1137. else
  1138. {
  1139. wszCertTypeName = (LPWSTR)pInstance->pCTLContext->pCtlInfo->ListIdentifier.pbData;
  1140. }
  1141. // get a handle to the cert type
  1142. if (S_OK != (hr = CAFindCertTypeByName(wszCertTypeName,
  1143. (HCAINFO)pld, // special optimization, ldap handle passed as scope
  1144. CT_FLAG_SCOPE_IS_LDAP_HANDLE |
  1145. (pInstance->pInternalInfo->fMachineEnrollment?
  1146. CT_ENUM_MACHINE_TYPES | CT_FIND_LOCAL_SYSTEM :
  1147. CT_ENUM_USER_TYPES),
  1148. &hCertType)))
  1149. {
  1150. AE_DEBUG((AE_WARNING, L"Unknown cert type: %ls\n\r", pInstance->pwszCertType));
  1151. goto Ret;
  1152. }
  1153. // get the extensions for the cert type
  1154. if (S_OK != (hr = CAGetCertTypeProperty(hCertType,
  1155. CERTTYPE_PROP_DN,
  1156. &awszName)))
  1157. {
  1158. AE_DEBUG((AE_WARNING, L"Could not get cert type full name: %ls\n\r",
  1159. pInstance->pCTLContext->pCtlInfo->ListIdentifier.pbData));
  1160. goto Ret;
  1161. }
  1162. if((awszName == NULL) || (*awszName == NULL))
  1163. {
  1164. AE_DEBUG((AE_WARNING, L"Could not get cert type full name: %ls\n\r",
  1165. pInstance->pCTLContext->pCtlInfo->ListIdentifier.pbData));
  1166. hr = CERTSRV_E_PROPERTY_EMPTY;
  1167. goto Ret;
  1168. }
  1169. if (NULL == (pInstance->pwszCertType = (LPWSTR)AEAlloc(
  1170. (wcslen(*awszName) + 1)*sizeof(WCHAR))))
  1171. {
  1172. hr = E_OUTOFMEMORY;
  1173. goto Ret;
  1174. }
  1175. wcscpy(pInstance->pwszCertType, *awszName);
  1176. if (NULL == (pInstance->pwszAEIdentifier = (LPWSTR)AEAlloc(
  1177. (wcslen((LPWSTR)pInstance->pCTLContext->pCtlInfo->ListIdentifier.pbData) + 1)*sizeof(WCHAR))))
  1178. {
  1179. hr = E_OUTOFMEMORY;
  1180. goto Ret;
  1181. }
  1182. wcscpy(pInstance->pwszAEIdentifier, (LPWSTR)pInstance->pCTLContext->pCtlInfo->ListIdentifier.pbData);
  1183. // get the extensions for the cert type
  1184. if (S_OK != (hr = CAGetCertTypeExtensions(hCertType,
  1185. &pInstance->pCertTypeExtensions)))
  1186. {
  1187. AE_DEBUG((AE_WARNING, L"Could not get cert type extensions: %ls\n\r", pInstance->pwszCertType));
  1188. goto Ret;
  1189. }
  1190. // get the extensions for the cert type
  1191. if (S_OK != (hr = CAGetCertTypeFlags(hCertType,
  1192. &pInstance->dwCertTypeFlags)))
  1193. {
  1194. AE_DEBUG((AE_WARNING, L"Could not get cert type flags: %ls\n\r", pInstance->pwszCertType));
  1195. goto Ret;
  1196. }
  1197. // get the expiration offset
  1198. if (S_OK != (hr = CAGetCertTypeExpiration(hCertType,
  1199. NULL,
  1200. (LPFILETIME)&pInstance->ftExpirationOffset)))
  1201. {
  1202. AE_DEBUG((AE_WARNING, L"Could not get cert type expirations: %ls\n\r", pInstance->pwszCertType));
  1203. goto Ret;
  1204. }
  1205. *pfPermissionToEnroll = (S_OK == CACertTypeAccessCheck(hCertType, pInstance->pInternalInfo->hToken));
  1206. fRet = TRUE;
  1207. Ret:
  1208. if (hr != S_OK)
  1209. {
  1210. LogAutoEnrollmentError(hr,
  1211. EVENT_UAE_UNKNOWN_CERT_TYPE,
  1212. pInstance->pInternalInfo->fMachineEnrollment,
  1213. pInstance->pInternalInfo->hToken,
  1214. (LPWSTR)pInstance->pCTLContext->pCtlInfo->ListIdentifier.pbData, NULL);
  1215. }
  1216. // close the handle to the cert type
  1217. if (hCertType)
  1218. {
  1219. if(awszName)
  1220. {
  1221. CAFreeCertTypeProperty(hCertType, awszName);
  1222. }
  1223. CACloseCertType(hCertType);
  1224. }
  1225. AE_END();
  1226. return fRet;
  1227. }
  1228. //
  1229. // Name: CompareEnhancedKeyUsageExtensions
  1230. //
  1231. // Description: This function checks if a the enhanced key usage extensions
  1232. // in a certificate contain the enhanced key usage extensions
  1233. // from the auto enrollment object (CTL),
  1234. //
  1235. HRESULT CompareEnhancedKeyUsageExtensions(
  1236. IN PAE_INSTANCE_INFO pInstance,
  1237. IN PCCERT_CONTEXT pCertContext,
  1238. IN OUT PAE_CERT_TEST_ARRAY *ppAEData
  1239. )
  1240. {
  1241. HRESULT hr = S_OK;
  1242. PCERT_ENHKEY_USAGE pCertUsage = NULL;
  1243. DWORD cbCertUsage;
  1244. PCERT_ENHKEY_USAGE pAEObjUsage = NULL;
  1245. DWORD cbAEObjUsage;
  1246. PCERT_EXTENSION pAEObjUsageExt;
  1247. PCERT_EXTENSION pCertUsageExt;
  1248. DWORD i;
  1249. DWORD j;
  1250. LPWSTR wszCertEKU = NULL;
  1251. LPWSTR wszTemplateEKU = NULL;
  1252. // get the enhanced key usages from the auto enrollment obj extensions
  1253. pCertUsageExt = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
  1254. pCertContext->pCertInfo->cExtension,
  1255. pCertContext->pCertInfo->rgExtension);
  1256. if(pCertUsageExt)
  1257. {
  1258. if (!CryptDecodeObject(CRYPT_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE,
  1259. pCertUsageExt->Value.pbData,
  1260. pCertUsageExt->Value.cbData,
  1261. 0, NULL, &cbCertUsage))
  1262. {
  1263. hr = HRESULT_FROM_WIN32(GetLastError());
  1264. goto Ret;
  1265. }
  1266. if (NULL == (pCertUsage = (PCERT_ENHKEY_USAGE)AEAlloc(cbCertUsage)))
  1267. {
  1268. hr = E_OUTOFMEMORY;
  1269. goto Ret;
  1270. }
  1271. if (!CryptDecodeObject(CRYPT_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE,
  1272. pCertUsageExt->Value.pbData,
  1273. pCertUsageExt->Value.cbData,
  1274. 0, pCertUsage, &cbCertUsage))
  1275. {
  1276. hr = HRESULT_FROM_WIN32(GetLastError());
  1277. goto Ret;
  1278. }
  1279. }
  1280. else
  1281. {
  1282. // No usage, so this cert is good for everything
  1283. goto Ret;
  1284. }
  1285. // get the enhanced key usages from the auto enrollment obj extensions
  1286. pAEObjUsageExt = CertFindExtension(szOID_ENHANCED_KEY_USAGE,
  1287. pInstance->pCertTypeExtensions->cExtension,
  1288. pInstance->pCertTypeExtensions->rgExtension);
  1289. if(pAEObjUsageExt)
  1290. {
  1291. if (!CryptDecodeObject(CRYPT_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE,
  1292. pAEObjUsageExt->Value.pbData,
  1293. pAEObjUsageExt->Value.cbData,
  1294. 0, NULL, &cbAEObjUsage))
  1295. {
  1296. hr = HRESULT_FROM_WIN32(GetLastError());
  1297. goto Ret;
  1298. }
  1299. if (NULL == (pAEObjUsage = (PCERT_ENHKEY_USAGE)AEAlloc(cbAEObjUsage)))
  1300. {
  1301. hr = E_OUTOFMEMORY;
  1302. goto Ret;
  1303. }
  1304. if (!CryptDecodeObject(CRYPT_ASN_ENCODING, szOID_ENHANCED_KEY_USAGE,
  1305. pAEObjUsageExt->Value.pbData,
  1306. pAEObjUsageExt->Value.cbData,
  1307. 0, pAEObjUsage, &cbAEObjUsage))
  1308. {
  1309. hr = HRESULT_FROM_WIN32(GetLastError());
  1310. goto Ret;
  1311. }
  1312. }
  1313. else
  1314. {
  1315. // The template requires no usage extension, so
  1316. // because the cert has a usage extension, we fail
  1317. // the test.
  1318. goto Failed;
  1319. }
  1320. // check if the number of usages is smaller in the cert then in the
  1321. // auto enrollment object
  1322. if (pCertUsage->cUsageIdentifier < pAEObjUsage->cUsageIdentifier)
  1323. {
  1324. goto Failed;
  1325. }
  1326. // check if all the usages found in the auto enrollment object are in
  1327. // the cert
  1328. for (i=0;i<pAEObjUsage->cUsageIdentifier;i++)
  1329. {
  1330. for (j=0;j<pCertUsage->cUsageIdentifier;j++)
  1331. {
  1332. if (0 == strcmp(pCertUsage->rgpszUsageIdentifier[j],
  1333. pAEObjUsage->rgpszUsageIdentifier[i]))
  1334. {
  1335. break;
  1336. }
  1337. }
  1338. if (j == pCertUsage->cUsageIdentifier)
  1339. {
  1340. goto Failed;
  1341. }
  1342. }
  1343. Ret:
  1344. if(wszCertEKU)
  1345. {
  1346. AEFree(wszCertEKU);
  1347. }
  1348. if(wszTemplateEKU)
  1349. {
  1350. AEFree(wszTemplateEKU);
  1351. }
  1352. if (pCertUsage)
  1353. AEFree(pCertUsage);
  1354. if (pAEObjUsage)
  1355. AEFree(pAEObjUsage);
  1356. return hr;
  1357. Failed:
  1358. // Log a failure of this test
  1359. // Build extension strings
  1360. wszCertEKU = HelperExtensionToString(pCertUsageExt);
  1361. /* if(wszCertEKU == NULL)
  1362. {
  1363. hr = E_OUTOFMEMORY;
  1364. goto Ret;
  1365. }*/
  1366. wszTemplateEKU = HelperExtensionToString(pAEObjUsageExt);
  1367. /* if(wszTemplateEKU == NULL)
  1368. {
  1369. hr = E_OUTOFMEMORY;
  1370. goto Ret;
  1371. }*/
  1372. AELogTestResult(ppAEData,
  1373. AE_TEST_EXTENSION_EKU,
  1374. wszCertEKU ? wszCertEKU : g_wszEmptyExtension,
  1375. wszTemplateEKU ? wszTemplateEKU : g_wszEmptyExtension);
  1376. goto Ret;
  1377. }
  1378. #define MAX_KEY_USAGE_SIZE 20 // sizeof(CRYPT_BIT_BLOB) for 64bit + sizeof(DWORD)
  1379. //
  1380. // Name: CompareKeyUsageExtensions
  1381. //
  1382. // Description: This function checks if the key usages
  1383. // in a certificate are a superset of the key usages
  1384. // from the auto enrollment object (CTL),
  1385. //
  1386. HRESULT CompareKeyUsageExtensions(
  1387. IN PAE_INSTANCE_INFO pInstance,
  1388. IN PCCERT_CONTEXT pCertContext,
  1389. IN OUT PAE_CERT_TEST_ARRAY *ppAEData
  1390. )
  1391. {
  1392. HRESULT hr = S_OK;
  1393. PCERT_EXTENSION pCertUsageExt;
  1394. PCERT_EXTENSION pAEObjUsageExt;
  1395. DWORD i;
  1396. DWORD dwMask = (DWORD)-1;
  1397. BYTE bCertUsageBuffer[MAX_KEY_USAGE_SIZE];
  1398. BYTE bAEObjUsageBuffer[MAX_KEY_USAGE_SIZE];
  1399. PCRYPT_BIT_BLOB pCertUsage = (PCRYPT_BIT_BLOB)bCertUsageBuffer;
  1400. PCRYPT_BIT_BLOB pAEObjUsage = (PCRYPT_BIT_BLOB)bAEObjUsageBuffer;
  1401. DWORD dwKeyUsage;
  1402. LPWSTR wszCertKU = NULL;
  1403. LPWSTR wszTemplateKU = NULL;
  1404. // get the key usages from the cert
  1405. pCertUsageExt = CertFindExtension(szOID_KEY_USAGE,
  1406. pCertContext->pCertInfo->cExtension,
  1407. pCertContext->pCertInfo->rgExtension);
  1408. // get the key usages from the auto enrollment obj extensions
  1409. pAEObjUsageExt = CertFindExtension(szOID_KEY_USAGE,
  1410. pInstance->pCertTypeExtensions->cExtension,
  1411. pInstance->pCertTypeExtensions->rgExtension);
  1412. // If the cert has no key usage extension, then it's good in general
  1413. if (NULL == pCertUsageExt)
  1414. {
  1415. goto Ret;
  1416. }
  1417. // If the type requires no extension, and the cert has one,
  1418. // then the cert is too limited.
  1419. if(pAEObjUsageExt == NULL)
  1420. {
  1421. goto Failed;
  1422. }
  1423. // Decode the key usage into their basic bit's
  1424. dwKeyUsage = MAX_KEY_USAGE_SIZE;
  1425. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1426. X509_KEY_USAGE,
  1427. pCertUsageExt->Value.pbData,
  1428. pCertUsageExt->Value.cbData,
  1429. 0,
  1430. (PVOID *)pCertUsage,
  1431. &dwKeyUsage))
  1432. {
  1433. hr = HRESULT_FROM_WIN32(GetLastError());
  1434. goto Ret;
  1435. }
  1436. // Decode the key usage into their basic bit's
  1437. dwKeyUsage = MAX_KEY_USAGE_SIZE;
  1438. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1439. X509_KEY_USAGE,
  1440. pAEObjUsageExt->Value.pbData,
  1441. pAEObjUsageExt->Value.cbData,
  1442. 0,
  1443. (PVOID *)pAEObjUsage,
  1444. &dwKeyUsage))
  1445. {
  1446. hr = HRESULT_FROM_WIN32(GetLastError());
  1447. goto Ret;
  1448. }
  1449. // Get the mask based on algs
  1450. for(i=0; i < g_cKUMasks; i++)
  1451. {
  1452. if(strcmp(pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, g_aKUMasks[i].pszAlg) == 0)
  1453. {
  1454. dwMask = g_aKUMasks[i].dwMask;
  1455. break;
  1456. }
  1457. }
  1458. // see if auto enroll obj keys usages are a sub set of cert's
  1459. if (pAEObjUsage->cbData > pCertUsage->cbData)
  1460. {
  1461. goto Failed;
  1462. }
  1463. for (i=0;i<pAEObjUsage->cbData;i++)
  1464. {
  1465. BYTE bMask = 0xff;
  1466. if(i < sizeof(DWORD))
  1467. {
  1468. bMask = ((PBYTE)&dwMask)[i];
  1469. }
  1470. if ((pAEObjUsage->pbData[i] & bMask ) !=
  1471. ((pAEObjUsage->pbData[i] & bMask ) &
  1472. pCertUsage->pbData[i]))
  1473. {
  1474. goto Failed;
  1475. }
  1476. }
  1477. Ret:
  1478. if(wszCertKU)
  1479. {
  1480. AEFree(wszCertKU);
  1481. }
  1482. if(wszTemplateKU)
  1483. {
  1484. AEFree(wszTemplateKU);
  1485. }
  1486. return hr;
  1487. Failed:
  1488. // Log a failure of this test
  1489. // Build extension strings
  1490. wszCertKU = HelperExtensionToString(pCertUsageExt);
  1491. /* if(wszCertKU == NULL)
  1492. {
  1493. hr = E_OUTOFMEMORY;
  1494. goto Ret;
  1495. }*/
  1496. wszTemplateKU = HelperExtensionToString(pAEObjUsageExt);
  1497. /* if(wszTemplateKU == NULL)
  1498. {
  1499. hr = E_OUTOFMEMORY;
  1500. goto Ret;
  1501. }*/
  1502. AELogTestResult(ppAEData,
  1503. AE_TEST_EXTENSION_KU,
  1504. wszCertKU ? wszCertKU : g_wszEmptyExtension,
  1505. wszTemplateKU ? wszTemplateKU : g_wszEmptyExtension);
  1506. goto Ret;
  1507. }
  1508. //
  1509. // Name: CompareBasicConstraints
  1510. //
  1511. // Description: This function checks if the basic constraints
  1512. // in a certificate are a superset of the basic
  1513. // constraints from the auto enrollment object (CTL),
  1514. //
  1515. HRESULT CompareBasicConstraints(
  1516. IN PAE_INSTANCE_INFO pInstance,
  1517. IN PCCERT_CONTEXT pCertContext,
  1518. IN OUT PAE_CERT_TEST_ARRAY *ppAEData
  1519. )
  1520. {
  1521. HRESULT hr = S_OK;
  1522. PCERT_EXTENSION pCertConstraints;
  1523. CERT_BASIC_CONSTRAINTS2_INFO CertConstraintInfo = {FALSE, FALSE, 0};
  1524. PCERT_EXTENSION pAEObjConstraints;
  1525. CERT_BASIC_CONSTRAINTS2_INFO AEObjConstraintInfo = {FALSE, FALSE, 0};
  1526. DWORD cb;
  1527. DWORD i;
  1528. LPWSTR wszCertBC = NULL;
  1529. LPWSTR wszTemplateBC = NULL;
  1530. // get the basic constraints from the cert
  1531. pCertConstraints = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
  1532. pCertContext->pCertInfo->cExtension,
  1533. pCertContext->pCertInfo->rgExtension);
  1534. // get the basic constraints from the auto enrollment obj extensions
  1535. pAEObjConstraints = CertFindExtension(szOID_BASIC_CONSTRAINTS2,
  1536. pInstance->pCertTypeExtensions->cExtension,
  1537. pInstance->pCertTypeExtensions->rgExtension);
  1538. // decode the objects
  1539. if(pCertConstraints)
  1540. {
  1541. cb = sizeof(CertConstraintInfo);
  1542. if (!CryptDecodeObject(CRYPT_ASN_ENCODING, szOID_BASIC_CONSTRAINTS2,
  1543. pCertConstraints->Value.pbData,
  1544. pCertConstraints->Value.cbData,
  1545. 0, &CertConstraintInfo, &cb))
  1546. {
  1547. hr = HRESULT_FROM_WIN32(GetLastError());
  1548. goto Ret;
  1549. }
  1550. }
  1551. if(pAEObjConstraints)
  1552. {
  1553. cb = sizeof(AEObjConstraintInfo);
  1554. if (!CryptDecodeObject(CRYPT_ASN_ENCODING, szOID_BASIC_CONSTRAINTS2,
  1555. pAEObjConstraints->Value.pbData,
  1556. pAEObjConstraints->Value.cbData,
  1557. 0, &AEObjConstraintInfo, &cb))
  1558. {
  1559. hr = HRESULT_FROM_WIN32(GetLastError());
  1560. goto Ret;
  1561. }
  1562. }
  1563. // see if auto enroll obj constraints are the same as the cert's
  1564. if (AEObjConstraintInfo.fCA != CertConstraintInfo.fCA)
  1565. {
  1566. goto Failed;
  1567. }
  1568. if (CertConstraintInfo.fCA)
  1569. {
  1570. if (CertConstraintInfo.fPathLenConstraint !=
  1571. AEObjConstraintInfo.fPathLenConstraint)
  1572. {
  1573. goto Failed;
  1574. }
  1575. if (CertConstraintInfo.fPathLenConstraint)
  1576. {
  1577. if (CertConstraintInfo.dwPathLenConstraint >
  1578. AEObjConstraintInfo.dwPathLenConstraint)
  1579. {
  1580. goto Failed;
  1581. }
  1582. }
  1583. }
  1584. Ret:
  1585. // Build extension strings
  1586. if(wszCertBC)
  1587. {
  1588. AEFree(wszCertBC);
  1589. }
  1590. if(wszTemplateBC)
  1591. {
  1592. AEFree(wszTemplateBC);
  1593. }
  1594. return hr;
  1595. Failed:
  1596. // Log a failure of this test
  1597. // Build extension strings
  1598. wszCertBC = HelperExtensionToString(pCertConstraints);
  1599. /* if(wszCertBC == NULL)
  1600. {
  1601. hr = E_OUTOFMEMORY;
  1602. goto Ret;
  1603. }*/
  1604. wszTemplateBC = HelperExtensionToString(pAEObjConstraints);
  1605. /* if(wszTemplateBC == NULL)
  1606. {
  1607. hr = E_OUTOFMEMORY;
  1608. goto Ret;
  1609. }*/
  1610. AELogTestResult(ppAEData,
  1611. AE_TEST_EXTENSION_BC,
  1612. wszCertBC ? wszCertBC : g_wszEmptyExtension,
  1613. wszTemplateBC ? wszTemplateBC : g_wszEmptyExtension);
  1614. goto Ret;
  1615. }
  1616. //
  1617. // Name: VerifyTemplateName
  1618. //
  1619. // Description:
  1620. //
  1621. HRESULT VerifyTemplateName(
  1622. IN PAE_INSTANCE_INFO pInstance,
  1623. IN PCCERT_CONTEXT pCertContext,
  1624. IN OUT PAE_CERT_TEST_ARRAY *ppAEData
  1625. )
  1626. {
  1627. HRESULT hr = S_OK;
  1628. BOOL fMatch = FALSE;
  1629. PCERT_NAME_VALUE pTemplateName = NULL;
  1630. if(pInstance->dwCertTypeFlags & CT_FLAG_ADD_TEMPLATE_NAME)
  1631. {
  1632. DWORD cbTemplateName = MAX_TEMPLATE_NAME_VALUE_SIZE;
  1633. BYTE pbName[MAX_TEMPLATE_NAME_VALUE_SIZE]; // Only needs to be as big as wszDomainController
  1634. PCERT_EXTENSION pCertType = CertFindExtension(szOID_ENROLL_CERTTYPE_EXTENSION,
  1635. pCertContext->pCertInfo->cExtension,
  1636. pCertContext->pCertInfo->rgExtension);
  1637. if(pCertType == NULL)
  1638. {
  1639. goto Failed;
  1640. }
  1641. if(!CryptDecodeObject(X509_ASN_ENCODING,
  1642. X509_UNICODE_ANY_STRING,
  1643. pCertType->Value.pbData,
  1644. pCertType->Value.cbData,
  1645. 0,
  1646. pbName,
  1647. &cbTemplateName))
  1648. {
  1649. hr = HRESULT_FROM_WIN32(GetLastError());
  1650. goto Ret;
  1651. }
  1652. pTemplateName = (PCERT_NAME_VALUE)pbName;
  1653. if(pTemplateName->Value.pbData == NULL)
  1654. {
  1655. goto Failed;
  1656. }
  1657. if(wcscmp((LPWSTR) pTemplateName->Value.pbData, pInstance->pwszCertType) != 0)
  1658. {
  1659. goto Failed;
  1660. }
  1661. }
  1662. Ret:
  1663. return hr;
  1664. Failed:
  1665. {
  1666. WCHAR wszTemplateName[MAX_PATH];
  1667. if(pTemplateName)
  1668. {
  1669. wcscpy(wszTemplateName, (LPWSTR) pTemplateName->Value.pbData);
  1670. }
  1671. else
  1672. {
  1673. if(!LoadString(g_hInstance, IDS_AUTOENROLL_TEMPLATE_EXT, wszTemplateName, MAX_PATH))
  1674. {
  1675. wcscpy(wszTemplateName, L"No template name");
  1676. }
  1677. }
  1678. AELogTestResult(ppAEData,
  1679. AE_TEST_EXTENSION_TEMPLATE,
  1680. wszTemplateName,
  1681. pInstance->pwszCertType);
  1682. }
  1683. goto Ret;
  1684. }
  1685. //
  1686. // Name: VerifyCommonExtensions
  1687. //
  1688. // Description: This function checks if a the extensions in a certificate
  1689. // contain the appropriate extensions from the certificate template
  1690. //
  1691. HRESULT VerifyCommonExtensions(
  1692. IN PAE_INSTANCE_INFO pInstance,
  1693. IN PCCERT_CONTEXT pCertContext,
  1694. IN OUT PAE_CERT_TEST_ARRAY *ppAEData
  1695. )
  1696. {
  1697. HRESULT hr = S_OK;
  1698. AE_BEGIN(L"VerifyCommonExtensions");
  1699. if (S_OK != (hr = CompareEnhancedKeyUsageExtensions(pInstance,
  1700. pCertContext,
  1701. ppAEData)))
  1702. {
  1703. goto Ret;
  1704. }
  1705. // check key usages
  1706. if (S_OK != (hr = CompareKeyUsageExtensions(pInstance,
  1707. pCertContext,
  1708. ppAEData)))
  1709. {
  1710. goto Ret;
  1711. }
  1712. // check basic constraints
  1713. if (S_OK != (hr = CompareBasicConstraints(pInstance,
  1714. pCertContext,
  1715. ppAEData)))
  1716. {
  1717. goto Ret;
  1718. }
  1719. // Check to see if the cert extension should be there, and if it matches.
  1720. // check basic constraints
  1721. if (S_OK != (hr = VerifyTemplateName(pInstance,
  1722. pCertContext,
  1723. ppAEData)))
  1724. {
  1725. goto Ret;
  1726. }
  1727. Ret:
  1728. AE_END();
  1729. return hr;
  1730. }
  1731. //
  1732. // Name: VerifyCertificateNaming
  1733. //
  1734. // Description: Determine whether the acutal naming information
  1735. // for the user matches that in the certificate.
  1736. //
  1737. HRESULT VerifyCertificateNaming(
  1738. IN PAE_INSTANCE_INFO pInstance,
  1739. IN PCCERT_CONTEXT pCert,
  1740. IN OUT PAE_CERT_TEST_ARRAY * ppAEData
  1741. )
  1742. {
  1743. HRESULT hr = S_OK;
  1744. PCERT_NAME_INFO pInfo = NULL;
  1745. DWORD cbInfo = 0;
  1746. DWORD iRDN, iATTR;
  1747. DWORD iExtension;
  1748. BOOL fSubjectUPNMatch = FALSE;
  1749. BOOL fSubjectEmailMatch = FALSE;
  1750. BOOL fAltSubjectEmailMatch = FALSE;
  1751. BOOL fDNMatch = FALSE;
  1752. BOOL fDNSMatch = FALSE;
  1753. BOOL fObjIDMatch = FALSE;
  1754. BOOL fAltSubjectUPNMatch = FALSE;
  1755. BOOL fDisplaySubjectName = FALSE;
  1756. BOOL fDisplayAltSubjectName = FALSE;
  1757. AE_BEGIN(L"VerifyCertificateNaming");
  1758. // First, check if the cert type specifies enrollee supplied subject name
  1759. if(0 != (pInstance->dwCertTypeFlags & CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT))
  1760. {
  1761. // We don't care what's in the cert, so return.
  1762. goto Ret;
  1763. }
  1764. fSubjectEmailMatch = fAltSubjectEmailMatch = ((pInstance->pInternalInfo->awszEmail == NULL) ||
  1765. (*pInstance->pInternalInfo->awszEmail == NULL));
  1766. fObjIDMatch = (0 == (pInstance->dwCertTypeFlags & CT_FLAG_ADD_OBJ_GUID));
  1767. // Verify the names in the Subject Name
  1768. if(!CryptDecodeObjectEx(pCert->dwCertEncodingType,
  1769. X509_NAME,
  1770. pCert->pCertInfo->Subject.pbData,
  1771. pCert->pCertInfo->Subject.cbData,
  1772. CRYPT_ENCODE_ALLOC_FLAG,
  1773. NULL,
  1774. &pInfo,
  1775. &cbInfo))
  1776. {
  1777. hr = HRESULT_FROM_WIN32(GetLastError());
  1778. AE_DEBUG((AE_ERROR, L"Could not decode certificate name (%lx)\n\r", hr));
  1779. goto Ret;
  1780. }
  1781. AE_DEBUG((AE_TRACE, L"Comparing Subject Name\n\r"));
  1782. for(iRDN = 0; iRDN < pInfo->cRDN; iRDN++)
  1783. {
  1784. for(iATTR = 0; iATTR < pInfo->rgRDN[iRDN].cRDNAttr; iATTR++)
  1785. {
  1786. LPTSTR wszRDNAttr = NULL;
  1787. DWORD cszRDNAttr = 0;
  1788. // Get this name string
  1789. cszRDNAttr = CertRDNValueToStr(pInfo->rgRDN[iRDN].rgRDNAttr[iATTR].dwValueType,
  1790. &pInfo->rgRDN[iRDN].rgRDNAttr[iATTR].Value,
  1791. NULL,
  1792. 0);
  1793. if(cszRDNAttr == 0)
  1794. {
  1795. continue;
  1796. }
  1797. wszRDNAttr = AEAlloc(cszRDNAttr * sizeof(TCHAR));
  1798. if(wszRDNAttr == NULL)
  1799. {
  1800. hr = E_OUTOFMEMORY;
  1801. goto Ret;
  1802. }
  1803. cszRDNAttr = CertRDNValueToStr(pInfo->rgRDN[iRDN].rgRDNAttr[iATTR].dwValueType,
  1804. &pInfo->rgRDN[iRDN].rgRDNAttr[iATTR].Value,
  1805. wszRDNAttr,
  1806. cszRDNAttr);
  1807. if(cszRDNAttr == 0)
  1808. {
  1809. // We couldn't convert the name for some reason
  1810. AEFree(wszRDNAttr);
  1811. continue;
  1812. }
  1813. if(strcmp(szOID_COMMON_NAME, pInfo->rgRDN[iRDN].rgRDNAttr[iATTR].pszObjId) == 0)
  1814. {
  1815. // If there are published UPN's, then
  1816. // we should check against those for a match,
  1817. // otherwise, we check against the generated UPN
  1818. if((pInstance->pInternalInfo->awszldap_UPN != NULL) &&
  1819. (*pInstance->pInternalInfo->awszldap_UPN != NULL))
  1820. {
  1821. LPTSTR *pwszCurrentName = pInstance->pInternalInfo->awszldap_UPN;
  1822. while(*pwszCurrentName)
  1823. {
  1824. if(_tcscmp(*pwszCurrentName, wszRDNAttr) == 0)
  1825. {
  1826. fSubjectUPNMatch = TRUE;
  1827. break;
  1828. }
  1829. pwszCurrentName++;
  1830. }
  1831. }
  1832. else if(pInstance->pInternalInfo->wszConstructedUPN != NULL)
  1833. {
  1834. if(_tcscmp(pInstance->pInternalInfo->wszConstructedUPN, wszRDNAttr) == 0)
  1835. {
  1836. fSubjectUPNMatch = TRUE;
  1837. }
  1838. }
  1839. }
  1840. if(strcmp(szOID_RSA_emailAddr, pInfo->rgRDN[iRDN].rgRDNAttr[iATTR].pszObjId) == 0)
  1841. {
  1842. // If there are published e-mails, then
  1843. // we should check against those for a match
  1844. if((pInstance->pInternalInfo->awszEmail != NULL) &&
  1845. (*pInstance->pInternalInfo->awszEmail != NULL))
  1846. {
  1847. LPTSTR *pwszCurrentEmail = pInstance->pInternalInfo->awszEmail;
  1848. while(*pwszCurrentEmail)
  1849. {
  1850. if(_tcscmp(*pwszCurrentEmail, wszRDNAttr) == 0)
  1851. {
  1852. fSubjectEmailMatch = TRUE;
  1853. break;
  1854. }
  1855. pwszCurrentEmail++;
  1856. }
  1857. }
  1858. else
  1859. {
  1860. // We have no e-mail name for this subject, yet there
  1861. // was one in the cert.
  1862. fSubjectEmailMatch = FALSE;
  1863. }
  1864. }
  1865. AEFree(wszRDNAttr);
  1866. }
  1867. }
  1868. // Now check the extensions
  1869. for(iExtension = 0; iExtension < pCert->pCertInfo->cExtension; iExtension++)
  1870. {
  1871. if((strcmp(pCert->pCertInfo->rgExtension[iExtension].pszObjId, szOID_SUBJECT_ALT_NAME) == 0) ||
  1872. (strcmp(pCert->pCertInfo->rgExtension[iExtension].pszObjId, szOID_SUBJECT_ALT_NAME2) == 0))
  1873. {
  1874. PCERT_ALT_NAME_INFO pAltName = NULL;
  1875. DWORD cbAltName = 0;
  1876. DWORD iAltName;
  1877. // Now, check the AltSubjectName fields.
  1878. if(!CryptDecodeObjectEx(pCert->dwCertEncodingType,
  1879. X509_ALTERNATE_NAME,
  1880. pCert->pCertInfo->rgExtension[iExtension].Value.pbData,
  1881. pCert->pCertInfo->rgExtension[iExtension].Value.cbData,
  1882. CRYPT_ENCODE_ALLOC_FLAG,
  1883. NULL,
  1884. &pAltName,
  1885. &cbAltName))
  1886. {
  1887. continue;
  1888. }
  1889. for(iAltName = 0; iAltName < pAltName->cAltEntry; iAltName++)
  1890. {
  1891. switch(pAltName->rgAltEntry[iAltName].dwAltNameChoice)
  1892. {
  1893. case CERT_ALT_NAME_RFC822_NAME:
  1894. {
  1895. // If there are published e-mails, then
  1896. // we should check against those for a match
  1897. if((pInstance->pInternalInfo->awszEmail != NULL) &&
  1898. (*pInstance->pInternalInfo->awszEmail != NULL))
  1899. {
  1900. LPTSTR *pwszCurrentEmail = pInstance->pInternalInfo->awszEmail;
  1901. while(*pwszCurrentEmail)
  1902. {
  1903. if(_tcscmp(*pwszCurrentEmail, pAltName->rgAltEntry[iAltName].pwszRfc822Name) == 0)
  1904. {
  1905. fAltSubjectEmailMatch = TRUE;
  1906. break;
  1907. }
  1908. pwszCurrentEmail++;
  1909. }
  1910. }
  1911. else
  1912. {
  1913. fAltSubjectEmailMatch = FALSE;
  1914. }
  1915. }
  1916. break;
  1917. case CERT_ALT_NAME_DIRECTORY_NAME:
  1918. {
  1919. if(CertCompareCertificateName(pCert->dwCertEncodingType,
  1920. &pInstance->pInternalInfo->blobDN,
  1921. &pAltName->rgAltEntry[iAltName].DirectoryName))
  1922. {
  1923. fDNMatch = TRUE;
  1924. }
  1925. }
  1926. break;
  1927. case CERT_ALT_NAME_DNS_NAME:
  1928. {
  1929. if(pInstance->pInternalInfo->fMachineEnrollment)
  1930. {
  1931. if((pInstance->pInternalInfo->awszldap_UPN != NULL) &&
  1932. (*pInstance->pInternalInfo->awszldap_UPN != NULL))
  1933. {
  1934. LPTSTR *pwszCurrentName = pInstance->pInternalInfo->awszldap_UPN;
  1935. while(*pwszCurrentName)
  1936. {
  1937. if(_tcscmp(*pwszCurrentName, pAltName->rgAltEntry[iAltName].pwszDNSName) == 0)
  1938. {
  1939. fDNSMatch = TRUE;
  1940. break;
  1941. }
  1942. pwszCurrentName++;
  1943. }
  1944. }
  1945. }
  1946. else
  1947. {
  1948. fDNSMatch = FALSE;
  1949. }
  1950. }
  1951. break;
  1952. case CERT_ALT_NAME_OTHER_NAME:
  1953. if(strcmp(pAltName->rgAltEntry[iAltName].pOtherName->pszObjId,
  1954. szOID_NTDS_REPLICATION) == 0)
  1955. {
  1956. if(pInstance->dwCertTypeFlags & CT_FLAG_ADD_OBJ_GUID)
  1957. {
  1958. // Object ID's should always be the same, so don't compare them
  1959. // for now.
  1960. fObjIDMatch = TRUE;
  1961. }
  1962. else
  1963. {
  1964. // We had an obj-id, but we shouldn't
  1965. fObjIDMatch = FALSE;
  1966. }
  1967. } else if (strcmp(pAltName->rgAltEntry[iAltName].pOtherName->pszObjId,
  1968. szOID_NT_PRINCIPAL_NAME) == 0)
  1969. {
  1970. PCERT_NAME_VALUE PrincipalNameBlob = NULL;
  1971. DWORD PrincipalNameBlobSize = 0;
  1972. if(CryptDecodeObjectEx(pCert->dwCertEncodingType,
  1973. X509_UNICODE_ANY_STRING,
  1974. pAltName->rgAltEntry[iAltName].pOtherName->Value.pbData,
  1975. pAltName->rgAltEntry[iAltName].pOtherName->Value.cbData,
  1976. CRYPT_DECODE_ALLOC_FLAG,
  1977. NULL,
  1978. (PVOID)&PrincipalNameBlob,
  1979. &PrincipalNameBlobSize))
  1980. {
  1981. // If there are published UPN's, then
  1982. // we should check against those for a match,
  1983. // otherwise, we check against the generated UPN
  1984. if((pInstance->pInternalInfo->awszldap_UPN != NULL) &&
  1985. (*pInstance->pInternalInfo->awszldap_UPN != NULL))
  1986. {
  1987. LPTSTR *pwszCurrentName = pInstance->pInternalInfo->awszldap_UPN;
  1988. while(*pwszCurrentName)
  1989. {
  1990. if(_tcscmp(*pwszCurrentName,
  1991. (LPWSTR)PrincipalNameBlob->Value.pbData) == 0)
  1992. {
  1993. fAltSubjectUPNMatch = TRUE;
  1994. break;
  1995. }
  1996. pwszCurrentName++;
  1997. }
  1998. }
  1999. else if(pInstance->pInternalInfo->wszConstructedUPN != NULL)
  2000. {
  2001. if(_tcscmp(pInstance->pInternalInfo->wszConstructedUPN,
  2002. (LPWSTR)PrincipalNameBlob->Value.pbData) == 0)
  2003. {
  2004. fAltSubjectUPNMatch = TRUE;
  2005. }
  2006. }
  2007. LocalFree(PrincipalNameBlob);
  2008. }
  2009. }
  2010. break;
  2011. default:
  2012. break;
  2013. }
  2014. }
  2015. LocalFree(pAltName);
  2016. }
  2017. }
  2018. if(((pInstance->pInternalInfo->fMachineEnrollment)?
  2019. ((!fSubjectUPNMatch)||(!fDNSMatch)):
  2020. ((!fSubjectUPNMatch) && (!fAltSubjectUPNMatch))))
  2021. {
  2022. // We didn't find an appropriate UPN in either the subject or alt subject
  2023. DWORD cUPNChars = 0;
  2024. LPWSTR wszUPN = NULL;
  2025. LPTSTR *pwszCurrentName = pInstance->pInternalInfo->awszldap_UPN;
  2026. if(pInstance->pInternalInfo->wszConstructedUPN)
  2027. {
  2028. cUPNChars += wcslen(pInstance->pInternalInfo->wszConstructedUPN)+1;
  2029. }
  2030. while((NULL != pwszCurrentName) && (NULL != *pwszCurrentName))
  2031. {
  2032. cUPNChars += wcslen(*pwszCurrentName++)+1;
  2033. }
  2034. wszUPN = AEAlloc((cUPNChars+1)*sizeof(WCHAR));
  2035. if(wszUPN == NULL)
  2036. {
  2037. hr = E_OUTOFMEMORY;
  2038. goto Ret;
  2039. }
  2040. wszUPN[0] = 0;
  2041. if(pInstance->pInternalInfo->wszConstructedUPN)
  2042. {
  2043. wcscat(wszUPN, pInstance->pInternalInfo->wszConstructedUPN);
  2044. wcscat(wszUPN, L",");
  2045. }
  2046. pwszCurrentName = pInstance->pInternalInfo->awszldap_UPN;
  2047. while((NULL != pwszCurrentName) && (NULL != *pwszCurrentName))
  2048. {
  2049. wcscat(wszUPN, *pwszCurrentName++);
  2050. wcscat(wszUPN, L",");
  2051. }
  2052. // Kill the last ','
  2053. wszUPN[cUPNChars-1] = 0;
  2054. AELogTestResult(ppAEData,
  2055. pInstance->pInternalInfo->fMachineEnrollment?AE_TEST_NAME_SUBJECT_DNS:AE_TEST_NAME_UPN,
  2056. wszUPN);
  2057. AEFree(wszUPN);
  2058. fDisplaySubjectName = TRUE;
  2059. fDisplayAltSubjectName = TRUE;
  2060. }
  2061. if((pInstance->dwCertTypeFlags & CT_FLAG_ADD_EMAIL) &&
  2062. ((!fSubjectEmailMatch) ||
  2063. (!fAltSubjectEmailMatch)))
  2064. {
  2065. // We didn't find an appropriate UPN in either the subject or alt subject
  2066. DWORD cEmailChars = 0;
  2067. LPWSTR wszEmail = NULL;
  2068. LPTSTR *pwszCurrentEmail = pInstance->pInternalInfo->awszEmail;
  2069. while((NULL != pwszCurrentEmail) && (NULL != *pwszCurrentEmail))
  2070. {
  2071. cEmailChars += wcslen(*pwszCurrentEmail++)+1;
  2072. }
  2073. wszEmail = AEAlloc((cEmailChars+1)*sizeof(WCHAR));
  2074. if(wszEmail == NULL)
  2075. {
  2076. hr = E_OUTOFMEMORY;
  2077. goto Ret;
  2078. }
  2079. wszEmail[0] = 0;
  2080. pwszCurrentEmail = pInstance->pInternalInfo->awszEmail;
  2081. while((NULL != pwszCurrentEmail) && (NULL != *pwszCurrentEmail))
  2082. {
  2083. wcscat(wszEmail, *pwszCurrentEmail++);
  2084. wcscat(wszEmail, L",");
  2085. }
  2086. // Kill the last ','
  2087. wszEmail[cEmailChars-1] = 0;
  2088. if(!fSubjectEmailMatch && fAltSubjectEmailMatch)
  2089. {
  2090. AELogTestResult(ppAEData,
  2091. AE_TEST_NAME_SUBJECT_EMAIL,
  2092. wszEmail);
  2093. }
  2094. else if(!fAltSubjectEmailMatch && fSubjectEmailMatch)
  2095. {
  2096. AELogTestResult(ppAEData,
  2097. AE_TEST_NAME_ALT_SUBJECT_EMAIL,
  2098. wszEmail);
  2099. }
  2100. else if((!fAltSubjectEmailMatch) && (!fSubjectEmailMatch))
  2101. {
  2102. AELogTestResult(ppAEData,
  2103. AE_TEST_NAME_BOTH_SUBJECT_EMAIL,
  2104. wszEmail);
  2105. }
  2106. AEFree(wszEmail);
  2107. if(!fSubjectEmailMatch)
  2108. {
  2109. fDisplaySubjectName = TRUE;
  2110. }
  2111. if(!fAltSubjectEmailMatch)
  2112. {
  2113. fDisplayAltSubjectName = TRUE;
  2114. }
  2115. }
  2116. if((pInstance->dwCertTypeFlags & CT_FLAG_ADD_DIRECTORY_PATH) &&
  2117. (!fDNMatch))
  2118. {
  2119. AELogTestResult(ppAEData,
  2120. AE_TEST_NAME_DIRECTORY_NAME,
  2121. pInstance->pInternalInfo->wszDN);
  2122. fDisplayAltSubjectName = TRUE;
  2123. }
  2124. if(!fObjIDMatch)
  2125. {
  2126. AELogTestResult(ppAEData,
  2127. (pInstance->dwCertTypeFlags & CT_FLAG_ADD_OBJ_GUID)?AE_TEST_NAME_NO_OBJID:AE_TEST_NAME_OBJID);
  2128. fDisplayAltSubjectName = TRUE;
  2129. }
  2130. if(fDisplaySubjectName)
  2131. {
  2132. DWORD cNameStr = 0;
  2133. LPWSTR wszNameStr = NULL;
  2134. cNameStr = CertNameToStr(X509_ASN_ENCODING,
  2135. &pCert->pCertInfo->Subject,
  2136. CERT_X500_NAME_STR,
  2137. NULL,
  2138. 0);
  2139. if(cNameStr)
  2140. {
  2141. wszNameStr = (LPWSTR)AEAlloc(cNameStr*sizeof(WCHAR));
  2142. if(wszNameStr == NULL)
  2143. {
  2144. hr = E_OUTOFMEMORY;
  2145. goto Ret;
  2146. }
  2147. cNameStr = CertNameToStr(X509_ASN_ENCODING,
  2148. &pCert->pCertInfo->Subject,
  2149. CERT_X500_NAME_STR,
  2150. wszNameStr,
  2151. cNameStr);
  2152. AELogTestResult(ppAEData,
  2153. AT_TEST_SUBJECT_NAME,
  2154. wszNameStr);
  2155. AEFree(wszNameStr);
  2156. }
  2157. }
  2158. if(fDisplayAltSubjectName)
  2159. {
  2160. DWORD cbFormat = 0;
  2161. LPWSTR wszFormat = NULL;
  2162. for(iExtension = 0; iExtension < pCert->pCertInfo->cExtension; iExtension++)
  2163. {
  2164. if((strcmp(pCert->pCertInfo->rgExtension[iExtension].pszObjId, szOID_SUBJECT_ALT_NAME) == 0) ||
  2165. (strcmp(pCert->pCertInfo->rgExtension[iExtension].pszObjId, szOID_SUBJECT_ALT_NAME2) == 0))
  2166. {
  2167. wszFormat = HelperExtensionToString(&pCert->pCertInfo->rgExtension[iExtension]);
  2168. if(wszFormat == NULL)
  2169. {
  2170. hr = E_OUTOFMEMORY;
  2171. goto Ret;
  2172. }
  2173. AELogTestResult(ppAEData,
  2174. AT_TEST_ALT_SUBJECT_NAME,
  2175. wszFormat);
  2176. LocalFree(wszFormat);
  2177. }
  2178. }
  2179. }
  2180. Ret:
  2181. if(pInfo)
  2182. {
  2183. LocalFree(pInfo);
  2184. }
  2185. return hr;
  2186. }
  2187. //
  2188. // Name: VerifyCertificateChaining
  2189. //
  2190. // Description: This function checks if if the certificate has expired, or has been revoked
  2191. //
  2192. HRESULT VerifyCertificateChaining(
  2193. IN PAE_INSTANCE_INFO pInstance,
  2194. IN PCCERT_CONTEXT pCert,
  2195. IN OUT PAE_CERT_TEST_ARRAY * ppAEData
  2196. )
  2197. {
  2198. HRESULT hr = S_OK;
  2199. HRESULT hrChainStatus = S_OK;
  2200. CERT_CHAIN_PARA ChainParams;
  2201. CERT_CHAIN_POLICY_PARA ChainPolicy;
  2202. CERT_CHAIN_POLICY_STATUS PolicyStatus;
  2203. PCCERT_CHAIN_CONTEXT pChainContext = NULL;
  2204. PCTL_INFO pCTLInfo = NULL;
  2205. LARGE_INTEGER ftTime;
  2206. AE_BEGIN(L"VerifyCertificateChaining");
  2207. if(*ppAEData)
  2208. {
  2209. (*ppAEData)->fRenewalOK = FALSE;
  2210. }
  2211. pCTLInfo = pInstance->pCTLContext->pCtlInfo;
  2212. // Build the certificate chain for trust
  2213. // operations
  2214. ChainParams.cbSize = sizeof(ChainParams);
  2215. ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  2216. ChainParams.RequestedUsage.Usage.cUsageIdentifier = 0;
  2217. ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
  2218. ChainPolicy.cbSize = sizeof(ChainPolicy);
  2219. ChainPolicy.dwFlags = 0; // ignore nothing
  2220. ChainPolicy.pvExtraPolicyPara = NULL;
  2221. PolicyStatus.cbSize = sizeof(PolicyStatus);
  2222. PolicyStatus.dwError = 0;
  2223. PolicyStatus.lChainIndex = -1;
  2224. PolicyStatus.lElementIndex = -1;
  2225. PolicyStatus.pvExtraPolicyStatus = NULL;
  2226. // Build a small time skew into the chain building in order to deal
  2227. // with servers that may skew slightly fast.
  2228. GetSystemTimeAsFileTime((LPFILETIME)&ftTime);
  2229. ftTime.QuadPart += Int32x32To64(FILETIME_TICKS_PER_SECOND, DEFAULT_AUTOENROLL_SKEW);
  2230. // Build a cert chain for the current status of the cert..
  2231. if(!CertGetCertificateChain(pInstance->pInternalInfo->fMachineEnrollment?HCCE_LOCAL_MACHINE:HCCE_CURRENT_USER,
  2232. pCert,
  2233. (LPFILETIME)&ftTime,
  2234. NULL,
  2235. &ChainParams,
  2236. CERT_CHAIN_REVOCATION_CHECK_END_CERT |
  2237. CERT_CHAIN_REVOCATION_CHECK_CHAIN,
  2238. NULL,
  2239. &pChainContext))
  2240. {
  2241. hr = HRESULT_FROM_WIN32(GetLastError());
  2242. AE_DEBUG((AE_WARNING, L"Could not build certificate chain (%lx)\n\r", hr));
  2243. goto Ret;
  2244. }
  2245. if(!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
  2246. pChainContext,
  2247. &ChainPolicy,
  2248. &PolicyStatus))
  2249. {
  2250. hrChainStatus = HRESULT_FROM_WIN32(GetLastError());
  2251. AE_DEBUG((AE_WARNING, L"Base Chain Policy failed (%lx) - must get new cert\n\r", PolicyStatus.dwError));
  2252. }
  2253. else
  2254. {
  2255. hrChainStatus = PolicyStatus.dwError;
  2256. }
  2257. if((S_OK == hrChainStatus) ||
  2258. (CRYPT_E_NO_REVOCATION_CHECK == hrChainStatus) ||
  2259. (CRYPT_E_REVOCATION_OFFLINE == hrChainStatus))
  2260. {
  2261. // The cert is still currently acceptable by trust standards,
  2262. // so we can renew it.
  2263. if(NULL == (*ppAEData))
  2264. {
  2265. (*ppAEData) = (PAE_CERT_TEST_ARRAY)LocalAlloc(LMEM_FIXED, sizeof(AE_CERT_TEST_ARRAY) +
  2266. (AE_CERT_TEST_SIZE_INCREMENT - ANYSIZE_ARRAY)*sizeof(AE_CERT_TEST));
  2267. if((*ppAEData) == NULL)
  2268. {
  2269. hr = E_OUTOFMEMORY;
  2270. goto Ret;
  2271. }
  2272. (*ppAEData)->dwVersion = AE_CERT_TEST_ARRAY_VERSION;
  2273. (*ppAEData)->cTests = 0;
  2274. (*ppAEData)->cMaxTests = AE_CERT_TEST_SIZE_INCREMENT;
  2275. }
  2276. (*ppAEData)->fRenewalOK = TRUE;
  2277. hrChainStatus = S_OK;
  2278. }
  2279. else
  2280. {
  2281. LPWSTR wszChainStatus = NULL;
  2282. if(0 == FormatMessage(
  2283. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  2284. NULL,
  2285. hrChainStatus,
  2286. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  2287. (WCHAR *) &wszChainStatus,
  2288. 0,
  2289. NULL))
  2290. {
  2291. hr = HRESULT_FROM_WIN32(GetLastError());
  2292. goto Ret;
  2293. }
  2294. // The cert has expired or has been revoked or something,
  2295. // we must re-enroll
  2296. AELogTestResult(ppAEData,
  2297. AE_TEST_CHAIN_FAIL,
  2298. hrChainStatus,
  2299. wszChainStatus);
  2300. AEFree(wszChainStatus);
  2301. }
  2302. // Verify that the immediate CA of the cert exists in the
  2303. // Autoenrollment Object. Empty ctl's imply any CA is
  2304. // ok.
  2305. if(pCTLInfo->cCTLEntry)
  2306. {
  2307. DWORD i;
  2308. BYTE pHash[20];
  2309. DWORD cbHash;
  2310. cbHash = sizeof(pHash);
  2311. AE_DEBUG((AE_TRACE, L"Verifying Issuer presence in auto-enrollment object\n\r"));
  2312. if((pChainContext == NULL) ||
  2313. (pChainContext->rgpChain == NULL) ||
  2314. (pChainContext->cChain < 1) ||
  2315. (pChainContext->rgpChain[0]->rgpElement == NULL) ||
  2316. (pChainContext->rgpChain[0]->cElement < 2))
  2317. {
  2318. hr = E_POINTER;
  2319. goto Ret;
  2320. }
  2321. if(!CertGetCertificateContextProperty(pChainContext->rgpChain[0]->rgpElement[1]->pCertContext,
  2322. CERT_SHA1_HASH_PROP_ID,
  2323. pHash,
  2324. &cbHash))
  2325. {
  2326. hr = HRESULT_FROM_WIN32(GetLastError());
  2327. AE_DEBUG((AE_ERROR, L"Could not get certificate Hash (%lx)\n\r",hr));
  2328. goto Ret;
  2329. }
  2330. for(i=0; i < pCTLInfo->cCTLEntry; i++)
  2331. {
  2332. if(pCTLInfo->rgCTLEntry[i].SubjectIdentifier.pbData == NULL)
  2333. continue;
  2334. if(pCTLInfo->rgCTLEntry[i].SubjectIdentifier.cbData != cbHash)
  2335. continue;
  2336. if(memcmp(pCTLInfo->rgCTLEntry[i].SubjectIdentifier.pbData,
  2337. pHash,
  2338. cbHash) == 0)
  2339. {
  2340. break;
  2341. }
  2342. }
  2343. if(i == pCTLInfo->cCTLEntry)
  2344. {
  2345. AE_DEBUG((AE_WARNING, L"Issuer not in auto-enrollment list - must renew\n\r"));
  2346. AELogTestResult(ppAEData,
  2347. AE_TEST_ISSUER_FAIL);
  2348. }
  2349. }
  2350. if(pChainContext)
  2351. {
  2352. CertFreeCertificateChain(pChainContext);
  2353. pChainContext = NULL;
  2354. }
  2355. // only check expiration status if the cert is otherwise ok
  2356. if(hrChainStatus == S_OK)
  2357. {
  2358. // Nudge the evaluation of the cert chain by the expiration
  2359. // offset so we know if is expired by that time in the future.
  2360. GetSystemTimeAsFileTime((LPFILETIME)&ftTime);
  2361. // Build the certificate chain for trust
  2362. // operations
  2363. ChainParams.cbSize = sizeof(ChainParams);
  2364. ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
  2365. ChainParams.RequestedUsage.Usage.cUsageIdentifier = 0;
  2366. ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
  2367. if(pInstance->ftExpirationOffset.QuadPart < 0)
  2368. {
  2369. LARGE_INTEGER ftHalfLife;
  2370. ftHalfLife.QuadPart = (((LARGE_INTEGER *)&pCert->pCertInfo->NotAfter)->QuadPart -
  2371. ((LARGE_INTEGER *)&pCert->pCertInfo->NotBefore)->QuadPart)/2;
  2372. if(ftHalfLife.QuadPart > (- pInstance->ftExpirationOffset.QuadPart))
  2373. {
  2374. // Assume that the old cert is not time nesting invalid
  2375. ftTime.QuadPart -= pInstance->ftExpirationOffset.QuadPart;
  2376. }
  2377. else
  2378. {
  2379. ftTime.QuadPart += ftHalfLife.QuadPart;
  2380. }
  2381. }
  2382. else
  2383. {
  2384. ftTime = pInstance->ftExpirationOffset;
  2385. }
  2386. // Is this a renewal, or an enroll on behalf of...
  2387. if(!CertGetCertificateChain(pInstance->pInternalInfo->fMachineEnrollment?HCCE_LOCAL_MACHINE:HCCE_CURRENT_USER,
  2388. pCert,
  2389. (LPFILETIME)&ftTime,
  2390. NULL,
  2391. &ChainParams,
  2392. 0,
  2393. NULL,
  2394. &pChainContext))
  2395. {
  2396. hr = HRESULT_FROM_WIN32(GetLastError());
  2397. AE_DEBUG((AE_WARNING, L"Could not build certificate chain (%lx)\n\r", hr));
  2398. goto Ret;
  2399. }
  2400. // Verify revocation and expiration of the certificate
  2401. ChainPolicy.cbSize = sizeof(ChainPolicy);
  2402. ChainPolicy.dwFlags = 0; // ignore nothing
  2403. ChainPolicy.pvExtraPolicyPara = NULL;
  2404. PolicyStatus.cbSize = sizeof(PolicyStatus);
  2405. PolicyStatus.dwError = 0;
  2406. PolicyStatus.lChainIndex = -1;
  2407. PolicyStatus.lElementIndex = -1;
  2408. PolicyStatus.pvExtraPolicyStatus = NULL;
  2409. if(!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_BASE,
  2410. pChainContext,
  2411. &ChainPolicy,
  2412. &PolicyStatus))
  2413. {
  2414. hrChainStatus = HRESULT_FROM_WIN32(GetLastError());
  2415. AE_DEBUG((AE_WARNING, L"Base Chain Policy failed (%lx) - must get new cert\n\r", hr));
  2416. }
  2417. else
  2418. {
  2419. hrChainStatus = PolicyStatus.dwError;
  2420. }
  2421. if((S_OK != hrChainStatus) &&
  2422. (CRYPT_E_NO_REVOCATION_CHECK != hrChainStatus) &&
  2423. (CRYPT_E_REVOCATION_OFFLINE != hrChainStatus))
  2424. {
  2425. // The cert has expired or has been revoked or something,
  2426. // we must re-enroll
  2427. AELogTestResult(ppAEData,
  2428. AT_TEST_PENDING_EXPIRATION);
  2429. }
  2430. }
  2431. Ret:
  2432. if(pChainContext)
  2433. {
  2434. CertFreeCertificateChain(pChainContext);
  2435. }
  2436. AE_END();
  2437. return hr;
  2438. }
  2439. HRESULT VerifyAutoenrolledCertificate(
  2440. IN PAE_INSTANCE_INFO pInstance,
  2441. IN PCCERT_CONTEXT pCert,
  2442. IN OUT PAE_CERT_TEST_ARRAY * ppAEData
  2443. )
  2444. {
  2445. HRESULT hr = S_OK;
  2446. hr = VerifyCommonExtensions(pInstance, pCert, ppAEData);
  2447. if(FAILED(hr))
  2448. {
  2449. return hr;
  2450. }
  2451. hr = VerifyCertificateNaming(pInstance, pCert, ppAEData);
  2452. if(FAILED(hr))
  2453. {
  2454. return hr;
  2455. }
  2456. hr = VerifyCertificateChaining(pInstance, pCert, ppAEData);
  2457. return hr;
  2458. }
  2459. //
  2460. // Name: IsOldCertificateValid
  2461. //
  2462. // Description: This function checks if the certificate in the pOldCert
  2463. // member is valid to satisfy this auto-enrollment request,
  2464. // or if it should be renewed.
  2465. //
  2466. HRESULT IsOldCertificateValid(
  2467. IN PAE_INSTANCE_INFO pInstance,
  2468. OUT BOOL *pfNeedNewCert
  2469. )
  2470. {
  2471. HRESULT hr = S_OK;
  2472. PAE_CERT_TEST_ARRAY pAEData = NULL;
  2473. AE_BEGIN(L"IsOldCertificateValid");
  2474. *pfNeedNewCert = TRUE;
  2475. if((pInstance == NULL) ||
  2476. (pInstance->pCTLContext == NULL) ||
  2477. (pInstance->pCTLContext->pCtlInfo == NULL))
  2478. {
  2479. goto Ret;
  2480. }
  2481. pInstance->fRenewalOK = FALSE;
  2482. hr = VerifyAutoenrolledCertificate(pInstance,
  2483. pInstance->pOldCert,
  2484. &pAEData);
  2485. if(FAILED(hr))
  2486. {
  2487. goto Ret;
  2488. }
  2489. if(pAEData)
  2490. {
  2491. pInstance->fRenewalOK = pAEData->fRenewalOK;
  2492. }
  2493. // Scan the verification results
  2494. if((pAEData) && (pAEData->cTests > 0))
  2495. {
  2496. BOOL fFailed = FALSE;
  2497. DWORD cFailureMessage= 0;
  2498. DWORD iFailure;
  2499. LPWSTR wszFailureMessage = NULL;
  2500. LPWSTR wszCurrent;
  2501. DWORD cTestArray = 0;
  2502. DWORD cbTestArray = 0;
  2503. DWORD * aidTestArray = NULL;
  2504. DWORD iTest;
  2505. if(CertGetCertificateContextProperty(pInstance->pOldCert,
  2506. AE_CERT_TEST_ARRAY_PROPID,
  2507. NULL,
  2508. &cbTestArray))
  2509. {
  2510. aidTestArray = (DWORD *)AEAlloc(cbTestArray);
  2511. CertGetCertificateContextProperty(pInstance->pOldCert,
  2512. AE_CERT_TEST_ARRAY_PROPID,
  2513. aidTestArray,
  2514. &cbTestArray);
  2515. cTestArray = cbTestArray/sizeof(aidTestArray[0]);
  2516. }
  2517. // Check to see of these are ignored failures.
  2518. for(iFailure=0; iFailure < pAEData->cTests; iFailure++)
  2519. {
  2520. if(FAILED(pAEData->Test[iFailure].idTest))
  2521. {
  2522. // Are we ignoring this test?
  2523. for(iTest = 0; iTest < cTestArray; iTest++)
  2524. {
  2525. if(aidTestArray[iTest] == pAEData->Test[iFailure].idTest)
  2526. break;
  2527. }
  2528. if(iTest != cTestArray)
  2529. {
  2530. if(pAEData->Test[iFailure].pwszReason)
  2531. {
  2532. LocalFree(pAEData->Test[iFailure].pwszReason);
  2533. }
  2534. pAEData->Test[iFailure].pwszReason = NULL;
  2535. pAEData->Test[iFailure].idTest = S_OK;
  2536. continue;
  2537. }
  2538. fFailed = TRUE;
  2539. }
  2540. if(pAEData->Test[iFailure].pwszReason)
  2541. {
  2542. cFailureMessage += wcslen(pAEData->Test[iFailure].pwszReason);
  2543. }
  2544. }
  2545. cFailureMessage += 5;
  2546. if(aidTestArray)
  2547. {
  2548. AEFree(aidTestArray);
  2549. }
  2550. if(fFailed)
  2551. {
  2552. wszFailureMessage = (LPWSTR)AEAlloc(cFailureMessage*sizeof(WCHAR));
  2553. if(wszFailureMessage == NULL)
  2554. {
  2555. hr = E_OUTOFMEMORY;
  2556. goto Ret;
  2557. }
  2558. wcscpy(wszFailureMessage, L"\n\r\n\r");
  2559. wszCurrent = wszFailureMessage+2;
  2560. for(iFailure=0; iFailure < pAEData->cTests; iFailure++)
  2561. {
  2562. if(pAEData->Test[iFailure].pwszReason)
  2563. {
  2564. wcscpy(wszCurrent, pAEData->Test[iFailure].pwszReason);
  2565. wszCurrent += wcslen(pAEData->Test[iFailure].pwszReason);
  2566. }
  2567. }
  2568. LogAutoEnrollmentEvent(pInstance->fRenewalOK?
  2569. EVENT_OLD_CERT_VERIFY_RENEW_WARNING:
  2570. EVENT_OLD_CERT_VERIFY_REENROLL_WARNING,
  2571. pInstance->pInternalInfo->hToken,
  2572. pInstance->pwszCertType,
  2573. wszFailureMessage,
  2574. NULL);
  2575. AEFree(wszFailureMessage);
  2576. // Report the event here
  2577. goto Ret;
  2578. }
  2579. }
  2580. *pfNeedNewCert = FALSE;
  2581. Ret:
  2582. if(pAEData)
  2583. {
  2584. AEFreeTestResult(&pAEData);
  2585. }
  2586. if(hr != S_OK)
  2587. {
  2588. LogAutoEnrollmentError(hr,
  2589. EVENT_UAE_VERIFICATION_FAILURE,
  2590. pInstance->pInternalInfo->fMachineEnrollment,
  2591. pInstance->pInternalInfo->hToken,
  2592. pInstance->pwszCertType, NULL);
  2593. }
  2594. AE_END();
  2595. return hr;
  2596. }
  2597. //
  2598. // Name: IsOldCertificateValid
  2599. //
  2600. // Description: This function checks if the certificate in the pOldCert
  2601. // member is valid to satisfy this auto-enrollment request,
  2602. // or if it should be renewed.
  2603. //
  2604. HRESULT VerifyEnrolledCertificate(
  2605. IN PAE_INSTANCE_INFO pInstance,
  2606. IN PCCERT_CONTEXT pCert
  2607. )
  2608. {
  2609. HRESULT hr = S_OK;
  2610. PAE_CERT_TEST_ARRAY pAEData = NULL;
  2611. CRYPT_DATA_BLOB AETestArray = {0, NULL};
  2612. AE_BEGIN(L"IsOldCertificateValid");
  2613. AETestArray.cbData = 0;
  2614. AETestArray.pbData = NULL;
  2615. if((pInstance == NULL) ||
  2616. (pInstance->pCTLContext == NULL) ||
  2617. (pInstance->pCTLContext->pCtlInfo == NULL))
  2618. {
  2619. goto Ret;
  2620. }
  2621. pInstance->fRenewalOK = FALSE;
  2622. hr = VerifyAutoenrolledCertificate(pInstance,
  2623. pCert,
  2624. &pAEData);
  2625. if(FAILED(hr))
  2626. {
  2627. goto Ret;
  2628. }
  2629. // Scan the verification results
  2630. if((pAEData) && (pAEData->cTests > 0))
  2631. {
  2632. BOOL fFailed = FALSE;
  2633. DWORD cFailureMessage= 0;
  2634. DWORD iFailure;
  2635. LPWSTR wszFailureMessage = NULL;
  2636. LPWSTR wszCurrent;
  2637. DWORD cTestArray = 0;
  2638. DWORD iTestArray = 0;
  2639. cTestArray = pAEData->cTests;
  2640. AETestArray.cbData = cTestArray*sizeof(DWORD);
  2641. if(AETestArray.cbData)
  2642. {
  2643. AETestArray.pbData = AEAlloc(AETestArray.cbData);
  2644. }
  2645. else
  2646. {
  2647. AETestArray.pbData = NULL;
  2648. }
  2649. // Check to see of these are ignored failures.
  2650. for(iFailure=0; iFailure < pAEData->cTests; iFailure++)
  2651. {
  2652. if(FAILED(pAEData->Test[iFailure].idTest))
  2653. {
  2654. fFailed = TRUE;
  2655. if(AETestArray.pbData)
  2656. {
  2657. ((DWORD *)AETestArray.pbData)[iTestArray++] = pAEData->Test[iFailure].idTest;
  2658. }
  2659. }
  2660. if(pAEData->Test[iFailure].pwszReason)
  2661. {
  2662. cFailureMessage += wcslen(pAEData->Test[iFailure].pwszReason);
  2663. }
  2664. }
  2665. cFailureMessage += 5;
  2666. wszFailureMessage = (LPWSTR)AEAlloc(cFailureMessage*sizeof(WCHAR));
  2667. if(wszFailureMessage == NULL)
  2668. {
  2669. hr = E_OUTOFMEMORY;
  2670. goto Ret;
  2671. }
  2672. wcscpy(wszFailureMessage, L"\n\r\n\r");
  2673. wszCurrent = wszFailureMessage+2;
  2674. for(iFailure=0; iFailure < pAEData->cTests; iFailure++)
  2675. {
  2676. if(pAEData->Test[iFailure].pwszReason)
  2677. {
  2678. wcscpy(wszCurrent, pAEData->Test[iFailure].pwszReason);
  2679. wszCurrent += wcslen(pAEData->Test[iFailure].pwszReason);
  2680. }
  2681. }
  2682. LogAutoEnrollmentEvent(EVENT_ENROLLED_CERT_VERIFY_WARNING,
  2683. pInstance->pInternalInfo->hToken,
  2684. pInstance->pwszCertType,
  2685. wszFailureMessage,
  2686. NULL);
  2687. AEFree(wszFailureMessage);
  2688. // Report the event here
  2689. }
  2690. CertSetCertificateContextProperty(pCert,
  2691. AE_CERT_TEST_ARRAY_PROPID,
  2692. 0,
  2693. AETestArray.pbData?&AETestArray:NULL);
  2694. Ret:
  2695. if(pAEData)
  2696. {
  2697. AEFreeTestResult(&pAEData);
  2698. }
  2699. if(hr != S_OK)
  2700. {
  2701. LogAutoEnrollmentError(hr,
  2702. EVENT_UAE_VERIFICATION_FAILURE,
  2703. pInstance->pInternalInfo->fMachineEnrollment,
  2704. pInstance->pInternalInfo->hToken,
  2705. pInstance->pwszCertType, NULL);
  2706. }
  2707. AE_END();
  2708. return hr;
  2709. }
  2710. //
  2711. // Name: FindExistingEnrolledCertificate
  2712. //
  2713. // Description: This function searches for an existing certificate
  2714. // enrolled with this auto-enrollment object.
  2715. //
  2716. BOOL FindExistingEnrolledCertificate(IN PAE_INSTANCE_INFO pInstance,
  2717. OUT PCCERT_CONTEXT *ppCert)
  2718. {
  2719. PCCERT_CONTEXT pCertContext = NULL;
  2720. PCCERT_CONTEXT pPrevContext = NULL;
  2721. DWORD i;
  2722. BOOL fRet = FALSE;
  2723. DWORD dwEnrollPropId = CERT_AUTO_ENROLL_PROP_ID;
  2724. LPWSTR wszEnrollmentId = NULL;
  2725. DWORD cbEnrollmentId = 0;
  2726. DWORD cbCurrentId=0;
  2727. AE_BEGIN(L"FindExistingEnrolledCertificate");
  2728. if(pInstance->pwszCertType == NULL)
  2729. {
  2730. return FALSE;
  2731. }
  2732. cbEnrollmentId = sizeof(WCHAR) * (wcslen(pInstance->pwszAEIdentifier) + 1);
  2733. wszEnrollmentId = (WCHAR *)AEAlloc(cbEnrollmentId);
  2734. if(wszEnrollmentId == NULL)
  2735. {
  2736. return FALSE;
  2737. }
  2738. if(*ppCert)
  2739. {
  2740. CertFreeCertificateContext(*ppCert);
  2741. }
  2742. *ppCert = NULL;
  2743. // check if cert from CA is in the MY store
  2744. while(pCertContext = CertFindCertificateInStore(
  2745. pInstance->pInternalInfo->hMYStore,
  2746. X509_ASN_ENCODING,
  2747. 0,
  2748. CERT_FIND_PROPERTY,
  2749. &dwEnrollPropId,
  2750. pPrevContext))
  2751. {
  2752. pPrevContext = pCertContext;
  2753. // check if this is an auto enroll cert and
  2754. // if the cert type is correct
  2755. cbCurrentId = cbEnrollmentId;
  2756. if(!CertGetCertificateContextProperty(pCertContext,
  2757. CERT_AUTO_ENROLL_PROP_ID,
  2758. wszEnrollmentId,
  2759. &cbCurrentId))
  2760. {
  2761. continue;
  2762. }
  2763. if(wcscmp(wszEnrollmentId, pInstance->pwszAEIdentifier) != 0)
  2764. {
  2765. continue;
  2766. }
  2767. AE_DEBUG((AE_INFO, L"Found auto-enrolled certificate for %ls cert\n\r", pInstance->pwszCertType));
  2768. *ppCert = pCertContext;
  2769. pCertContext = NULL;
  2770. break;
  2771. }
  2772. fRet = TRUE;
  2773. if (pCertContext)
  2774. CertFreeCertificateContext(pCertContext);
  2775. if(wszEnrollmentId)
  2776. {
  2777. AEFree(wszEnrollmentId);
  2778. }
  2779. AE_END();
  2780. return fRet;
  2781. }
  2782. //
  2783. // Name:
  2784. //
  2785. // Description: This function calls a function to determine if an auto
  2786. // enrollment is to occur and if so it trys to enroll with
  2787. // different CAs until either an enrollment is successful or
  2788. // the list of CAs is exhausted.
  2789. //
  2790. void EnrollmentWithCTL(
  2791. IN PAE_INSTANCE_INFO pInstance,
  2792. IN LDAP * pld
  2793. )
  2794. {
  2795. INTERNAL_INFO pInternalInfo;
  2796. BOOL fNeedToEnroll = FALSE;
  2797. AUTO_ENROLL_INFO EnrollmentInfo;
  2798. DWORD *pdwCAEntries = NULL;
  2799. DWORD i;
  2800. BOOL fPermitted;
  2801. BOOL fAnyAcceptableCAs = FALSE;
  2802. DWORD dwFailureCode = E_FAIL;
  2803. AE_BEGIN(L"EnrollmentWithCTL");
  2804. if(!GetCertTypeInfo(pInstance,
  2805. pld,
  2806. &fPermitted))
  2807. {
  2808. goto Ret;
  2809. }
  2810. if(!fPermitted)
  2811. {
  2812. AE_DEBUG((AE_INFO, L"Not permitted to enroll for %ls cert type\n", pInstance->pwszCertType));
  2813. goto Ret;
  2814. }
  2815. if(!FindExistingEnrolledCertificate(pInstance, &pInstance->pOldCert))
  2816. {
  2817. goto Ret;
  2818. }
  2819. if(pInstance->pOldCert)
  2820. {
  2821. if(FAILED(IsOldCertificateValid(pInstance, &fNeedToEnroll)))
  2822. {
  2823. goto Ret;
  2824. }
  2825. if(!fNeedToEnroll)
  2826. {
  2827. goto Ret;
  2828. }
  2829. if(!pInstance->fRenewalOK)
  2830. {
  2831. CRYPT_DATA_BLOB Archived;
  2832. Archived.cbData = 0;
  2833. Archived.pbData = NULL;
  2834. // We force an archive on the old cert and close it.
  2835. CertSetCertificateContextProperty(pInstance->pOldCert,
  2836. CERT_ARCHIVED_PROP_ID,
  2837. 0,
  2838. &Archived);
  2839. }
  2840. }
  2841. // It looks like we need to enroll
  2842. // for a cert.
  2843. do
  2844. {
  2845. // Loop through all avaialble ca's to find one
  2846. // that supports this cert type, and is in our CTL
  2847. for (i=0;i<pInstance->pInternalInfo->ccaList;i++)
  2848. {
  2849. DWORD dwIndex;
  2850. LPWSTR *pwszCertType;
  2851. DWORD iCTL;
  2852. dwIndex = (i + pInstance->dwRandomIndex) % pInstance->pInternalInfo->ccaList;
  2853. AE_DEBUG((AE_TRACE, L"Trying CA %ws\\%ws\n\r", pInstance->pInternalInfo->acaList[dwIndex].wszDNSName, pInstance->pInternalInfo->acaList[dwIndex].wszName));
  2854. // Does this CA support our cert type.
  2855. pwszCertType = pInstance->pInternalInfo->acaList[dwIndex].awszCertificateTemplates;
  2856. if(pwszCertType == NULL)
  2857. {
  2858. AE_DEBUG((AE_TRACE, L"There are no cert types supported on this CA\n\r"));
  2859. continue;
  2860. }
  2861. while(*pwszCertType)
  2862. {
  2863. if(wcscmp(*pwszCertType, pInstance->pwszCertType) == 0)
  2864. {
  2865. break;
  2866. }
  2867. pwszCertType++;
  2868. }
  2869. if(*pwszCertType == NULL)
  2870. {
  2871. AE_DEBUG((AE_TRACE, L"The cert type %ws is not supported on this CA\n\r", pInstance->pwszCertType));
  2872. continue;
  2873. }
  2874. // Is this CA in our CTL List
  2875. if(pInstance->pCTLContext->pCtlInfo->cCTLEntry > 0)
  2876. {
  2877. for(iCTL = 0; iCTL < pInstance->pCTLContext->pCtlInfo->cCTLEntry; iCTL++)
  2878. {
  2879. PCTL_ENTRY pEntry= &pInstance->pCTLContext->pCtlInfo->rgCTLEntry[iCTL];
  2880. if(pEntry->SubjectIdentifier.cbData != sizeof(pInstance->pInternalInfo->acaList[dwIndex].CACertHash))
  2881. {
  2882. continue;
  2883. }
  2884. if(memcmp(pEntry->SubjectIdentifier.pbData,
  2885. pInstance->pInternalInfo->acaList[dwIndex].CACertHash,
  2886. pEntry->SubjectIdentifier.cbData) == 0)
  2887. {
  2888. break;
  2889. }
  2890. }
  2891. if(iCTL == pInstance->pCTLContext->pCtlInfo->cCTLEntry)
  2892. {
  2893. AE_DEBUG((AE_TRACE, L"The CA is not supported by the auto-enrollment object\n\r"));
  2894. continue;
  2895. }
  2896. }
  2897. ZeroMemory(&EnrollmentInfo, sizeof(EnrollmentInfo));
  2898. // Yes, we may enroll at this CA!
  2899. fAnyAcceptableCAs = TRUE;
  2900. EnrollmentInfo.pwszCAMachine = pInstance->pInternalInfo->acaList[dwIndex].wszDNSName;
  2901. EnrollmentInfo.pwszCAAuthority = pInstance->pInternalInfo->acaList[dwIndex].wszName;
  2902. EnrollmentInfo.pszAutoEnrollProvider = DEFAULT_AUTO_ENROLL_PROV;
  2903. EnrollmentInfo.fRenewal = pInstance->fRenewalOK && (pInstance->pOldCert != NULL);
  2904. if(!SetEnrollmentCertType(pInstance, &EnrollmentInfo))
  2905. {
  2906. AE_DEBUG((AE_TRACE, L"SetEnrollmentCertType failed\n\r"));
  2907. continue;
  2908. }
  2909. // load the provider and call the entry point
  2910. if (LoadAndCallEnrollmentProvider(pInstance->pInternalInfo->fMachineEnrollment,
  2911. &EnrollmentInfo))
  2912. {
  2913. PCCERT_CONTEXT pNewCert = NULL;
  2914. // Succeeded,
  2915. // verify the cert that was retrieved
  2916. if(!FindExistingEnrolledCertificate(pInstance, &pNewCert))
  2917. {
  2918. continue;
  2919. }
  2920. VerifyEnrolledCertificate(pInstance, pNewCert);
  2921. CertFreeCertificateContext(pNewCert);
  2922. break;
  2923. }
  2924. }
  2925. if(i == pInstance->pInternalInfo->ccaList)
  2926. {
  2927. //
  2928. // If we have a preexisting cert, then we may need to try twice, first
  2929. // to renew, and then to re-enroll
  2930. if(pInstance->pOldCert)
  2931. {
  2932. // Try again, but re-enrolling this time
  2933. CRYPT_DATA_BLOB Archived;
  2934. Archived.cbData = 0;
  2935. Archived.pbData = NULL;
  2936. // We force an archive on the old cert and close it.
  2937. CertSetCertificateContextProperty(pInstance->pOldCert,
  2938. CERT_ARCHIVED_PROP_ID,
  2939. 0,
  2940. &Archived);
  2941. CertFreeCertificateContext(pInstance->pOldCert);
  2942. pInstance->pOldCert = NULL;
  2943. pInstance->fRenewalOK = FALSE;
  2944. continue;
  2945. }
  2946. AE_DEBUG((AE_WARNING, L"Auto-enrollment not performed\n\r"));
  2947. break;
  2948. // failed
  2949. }
  2950. else
  2951. {
  2952. break;
  2953. }
  2954. } while (TRUE);
  2955. Ret:
  2956. AE_END();
  2957. return;
  2958. }
  2959. #define SHA1_HASH_LENGTH 20
  2960. PCCERT_CONTEXT FindCertificateInOtherStore(
  2961. IN HCERTSTORE hOtherStore,
  2962. IN PCCERT_CONTEXT pCert
  2963. )
  2964. {
  2965. BYTE rgbHash[SHA1_HASH_LENGTH];
  2966. CRYPT_DATA_BLOB HashBlob;
  2967. HashBlob.pbData = rgbHash;
  2968. HashBlob.cbData = SHA1_HASH_LENGTH;
  2969. if (!CertGetCertificateContextProperty(
  2970. pCert,
  2971. CERT_SHA1_HASH_PROP_ID,
  2972. rgbHash,
  2973. &HashBlob.cbData
  2974. ) || SHA1_HASH_LENGTH != HashBlob.cbData)
  2975. return NULL;
  2976. return CertFindCertificateInStore(
  2977. hOtherStore,
  2978. 0, // dwCertEncodingType
  2979. 0, // dwFindFlags
  2980. CERT_FIND_SHA1_HASH,
  2981. (const void *) &HashBlob,
  2982. NULL //pPrevCertContext
  2983. );
  2984. }
  2985. //
  2986. // Name: UpdateEnterpriseRoots
  2987. //
  2988. // Description: This function enumerates all of the roots in the DS based
  2989. // enterprise root store, and moves them into the local machine root store.
  2990. //
  2991. HRESULT WINAPI UpdateEnterpriseRoots(LDAP *pld)
  2992. {
  2993. HRESULT hr = S_OK;
  2994. LPWSTR wszLdapRootStore = NULL;
  2995. LPWSTR wszConfig = NULL;
  2996. HCERTSTORE hEnterpriseRoots = NULL,
  2997. hRootStore = NULL;
  2998. PCCERT_CONTEXT pContext = NULL,
  2999. pOtherCert = NULL;
  3000. static LPWSTR s_wszEnterpriseRoots = L"ldap:///CN=Certification Authorities,CN=Public Key Services,CN=Services,%ws?cACertificate?one?objectCategory=certificationAuthority";
  3001. hr = myGetConfigDN(pld, &wszConfig);
  3002. if(hr != S_OK)
  3003. {
  3004. goto error;
  3005. }
  3006. wszLdapRootStore = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(wcslen(wszConfig)+wcslen(s_wszEnterpriseRoots)));
  3007. if(wszLdapRootStore == NULL)
  3008. {
  3009. hr = E_OUTOFMEMORY;
  3010. goto error;
  3011. }
  3012. wsprintf(wszLdapRootStore,
  3013. s_wszEnterpriseRoots,
  3014. wszConfig);
  3015. hRootStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  3016. 0,
  3017. 0,
  3018. CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
  3019. L"ROOT");
  3020. if(hRootStore == NULL)
  3021. {
  3022. hr = HRESULT_FROM_WIN32(GetLastError());
  3023. AE_DEBUG((AE_ERROR, L"Unable to open ROOT store (%lx)\n\r", hr));
  3024. goto error;
  3025. }
  3026. hEnterpriseRoots = CertOpenStore(CERT_STORE_PROV_LDAP,
  3027. 0,
  3028. 0,
  3029. CERT_STORE_READONLY_FLAG,
  3030. wszLdapRootStore);
  3031. if(hEnterpriseRoots == NULL)
  3032. {
  3033. DWORD err = GetLastError();
  3034. // Checking against NO_SUCH_OBJECT
  3035. // is a workaround for the fact that
  3036. // the ldap provider returns LDAP errors
  3037. if((err == LDAP_NO_SUCH_OBJECT) ||
  3038. (err == ERROR_FILE_NOT_FOUND))
  3039. {
  3040. // There was no store, so there are no certs
  3041. hr = S_OK;
  3042. goto error;
  3043. }
  3044. hr = HRESULT_FROM_WIN32(err);
  3045. AE_DEBUG((AE_ERROR, L"Unable to open ROOT store (%lx)\n\r", hr));
  3046. goto error;
  3047. }
  3048. while(pContext = CertEnumCertificatesInStore(hEnterpriseRoots, pContext))
  3049. {
  3050. if (pOtherCert = FindCertificateInOtherStore(hRootStore, pContext)) {
  3051. CertFreeCertificateContext(pOtherCert);
  3052. }
  3053. else
  3054. {
  3055. CertAddCertificateContextToStore(hRootStore,
  3056. pContext,
  3057. CERT_STORE_ADD_ALWAYS,
  3058. NULL);
  3059. }
  3060. }
  3061. while(pContext = CertEnumCertificatesInStore(hRootStore, pContext))
  3062. {
  3063. if (pOtherCert = FindCertificateInOtherStore(hEnterpriseRoots, pContext)) {
  3064. CertFreeCertificateContext(pOtherCert);
  3065. }
  3066. else
  3067. {
  3068. CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pContext));
  3069. }
  3070. }
  3071. error:
  3072. if(hr != S_OK)
  3073. {
  3074. LogAutoEnrollmentError(hr,
  3075. EVENT_UPDATE_ENTERPRISE_ROOT_FAILURE,
  3076. TRUE,
  3077. NULL,
  3078. NULL, NULL);
  3079. }
  3080. if(wszLdapRootStore)
  3081. {
  3082. LocalFree(wszLdapRootStore);
  3083. }
  3084. if(wszConfig)
  3085. {
  3086. LocalFree(wszConfig);
  3087. }
  3088. if(hEnterpriseRoots)
  3089. {
  3090. CertCloseStore(hEnterpriseRoots,0);
  3091. }
  3092. if(hRootStore)
  3093. {
  3094. CertCloseStore(hRootStore,0);
  3095. }
  3096. return hr;
  3097. }
  3098. //
  3099. // Name: UpdateNTAuthTrust
  3100. //
  3101. // Description: This function enumerates all of the roots in the DS based
  3102. // NTAuth store, and moves them into the local machine NTAuth.
  3103. //
  3104. HRESULT WINAPI UpdateNTAuthTrust(LDAP *pld)
  3105. {
  3106. HRESULT hr = S_OK;
  3107. LPWSTR wszNTAuth = NULL;
  3108. LPWSTR wszConfig = NULL;
  3109. HCERTSTORE hDSAuthRoots = NULL,
  3110. hAuthStore = NULL;
  3111. PCCERT_CONTEXT pContext = NULL,
  3112. pOtherCert = NULL;
  3113. static LPWSTR s_wszNTAuthRoots = L"ldap:///CN=Public Key Services,CN=Services,%ws?cACertificate?one?cn=NTAuthCertificates";
  3114. hr = myGetConfigDN(pld, &wszConfig);
  3115. if(hr != S_OK)
  3116. {
  3117. goto error;
  3118. }
  3119. wszNTAuth = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(wcslen(wszConfig)+wcslen(s_wszNTAuthRoots)));
  3120. if(wszNTAuth == NULL)
  3121. {
  3122. hr = E_OUTOFMEMORY;
  3123. goto error;
  3124. }
  3125. wsprintf(wszNTAuth,
  3126. s_wszNTAuthRoots,
  3127. wszConfig);
  3128. hAuthStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_REGISTRY_W,
  3129. 0,
  3130. 0,
  3131. CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE,
  3132. L"NTAuth");
  3133. if(hAuthStore == NULL)
  3134. {
  3135. hr = HRESULT_FROM_WIN32(GetLastError());
  3136. AE_DEBUG((AE_ERROR, L"Unable to open NTAuth store (%lx)\n\r", hr));
  3137. goto error;
  3138. }
  3139. hDSAuthRoots = CertOpenStore(CERT_STORE_PROV_LDAP,
  3140. 0,
  3141. 0,
  3142. CERT_STORE_READONLY_FLAG,
  3143. wszNTAuth);
  3144. if(hDSAuthRoots == NULL)
  3145. {
  3146. DWORD err = GetLastError();
  3147. // Checking against NO_SUCH_OBJECT
  3148. // is a workaround for the fact that
  3149. // the ldap provider returns LDAP errors
  3150. if((err == LDAP_NO_SUCH_OBJECT) ||
  3151. (err == ERROR_FILE_NOT_FOUND))
  3152. {
  3153. // There was no store, so there are no certs
  3154. hr = S_OK;
  3155. goto error;
  3156. }
  3157. hr = HRESULT_FROM_WIN32(err);
  3158. AE_DEBUG((AE_ERROR, L"Unable to open ROOT store (%lx)\n\r", hr));
  3159. goto error;
  3160. }
  3161. while(pContext = CertEnumCertificatesInStore(hDSAuthRoots, pContext))
  3162. {
  3163. if (pOtherCert = FindCertificateInOtherStore(hAuthStore, pContext)) {
  3164. CertFreeCertificateContext(pOtherCert);
  3165. }
  3166. else
  3167. {
  3168. CertAddCertificateContextToStore(hAuthStore,
  3169. pContext,
  3170. CERT_STORE_ADD_ALWAYS,
  3171. NULL);
  3172. }
  3173. }
  3174. while(pContext = CertEnumCertificatesInStore(hAuthStore, pContext))
  3175. {
  3176. if (pOtherCert = FindCertificateInOtherStore(hDSAuthRoots, pContext)) {
  3177. CertFreeCertificateContext(pOtherCert);
  3178. }
  3179. else
  3180. {
  3181. CertDeleteCertificateFromStore(CertDuplicateCertificateContext(pContext));
  3182. }
  3183. }
  3184. error:
  3185. if(hr != S_OK)
  3186. {
  3187. LogAutoEnrollmentError(hr,
  3188. EVENT_UPDATE_NTAUTH_FAILURE,
  3189. TRUE,
  3190. NULL,
  3191. NULL, NULL);
  3192. }
  3193. if(wszNTAuth)
  3194. {
  3195. LocalFree(wszNTAuth);
  3196. }
  3197. if(wszConfig)
  3198. {
  3199. LocalFree(wszConfig);
  3200. }
  3201. if(hDSAuthRoots)
  3202. {
  3203. CertCloseStore(hDSAuthRoots,0);
  3204. }
  3205. if(hAuthStore)
  3206. {
  3207. CertCloseStore(hAuthStore,0);
  3208. }
  3209. return hr;
  3210. }
  3211. //
  3212. // Name: ProcessAutoEnrollment
  3213. //
  3214. // Description: This function retrieves the appropriate auto enrollment
  3215. // objects (CTLs) and then calls a function to proceed with
  3216. // auto enrollment for each of the objects.
  3217. //
  3218. DWORD WINAPI ProcessAutoEnrollment(
  3219. BOOL fMachineEnrollment,
  3220. HANDLE hToken
  3221. )
  3222. {
  3223. DWORD i;
  3224. DWORD dwOpenStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG;
  3225. HCERTSTORE hACRSStore = 0;
  3226. PCCTL_CONTEXT pCTLContext = NULL;
  3227. PCCTL_CONTEXT pPrevCTLContext = NULL;
  3228. CTL_FIND_USAGE_PARA CTLFindUsage;
  3229. LPSTR pszCTLUsageOID;
  3230. CERT_PHYSICAL_STORE_INFO PhysicalStoreInfo;
  3231. DWORD dwRet = 0;
  3232. INTERNAL_INFO InternalInfo;
  3233. BOOL fInitialized = FALSE;
  3234. LDAP *pld = NULL;
  3235. __try
  3236. {
  3237. AE_DEBUG((AE_TRACE, L"ProcessAutoEnrollment:%ls\n\r", fMachineEnrollment?L"Machine":L"User"));
  3238. memset(&InternalInfo, 0, sizeof(InternalInfo));
  3239. memset(&PhysicalStoreInfo, 0, sizeof(PhysicalStoreInfo));
  3240. memset(&CTLFindUsage, 0, sizeof(CTLFindUsage));
  3241. CTLFindUsage.cbSize = sizeof(CTLFindUsage);
  3242. // since this is a user we need to impersonate the user
  3243. if (!fMachineEnrollment)
  3244. {
  3245. if (hToken)
  3246. {
  3247. if (!ImpersonateLoggedOnUser(hToken))
  3248. {
  3249. dwRet = GetLastError();
  3250. AE_DEBUG((AE_ERROR, L"Could not impersonate user: (%lx)\n\r", dwRet));
  3251. LogAutoEnrollmentError(HRESULT_FROM_WIN32(dwRet),
  3252. EVENT_AE_SECURITY_INIT_FAILED,
  3253. fMachineEnrollment,
  3254. hToken,
  3255. NULL, NULL);
  3256. goto Ret;
  3257. }
  3258. }
  3259. }
  3260. if(fMachineEnrollment)
  3261. {
  3262. dwRet = aeRobustLdapBind(&pld, FALSE);
  3263. if(dwRet != S_OK)
  3264. {
  3265. goto Ret;
  3266. }
  3267. UpdateEnterpriseRoots(pld);
  3268. UpdateNTAuthTrust(pld);
  3269. }
  3270. // if the auto enrollment is for a user then we need to shut off inheritance
  3271. // from the local machine store so that we don't try and enroll for certs
  3272. // which are meant to be for the machine
  3273. if (!fMachineEnrollment)
  3274. {
  3275. dwOpenStoreFlags = CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_READONLY_FLAG;
  3276. PhysicalStoreInfo.cbSize = sizeof(PhysicalStoreInfo);
  3277. PhysicalStoreInfo.dwFlags = CERT_PHYSICAL_STORE_OPEN_DISABLE_FLAG;
  3278. if (!CertRegisterPhysicalStore(L"ACRS",
  3279. CERT_SYSTEM_STORE_CURRENT_USER,
  3280. CERT_PHYSICAL_STORE_LOCAL_MACHINE_NAME,
  3281. &PhysicalStoreInfo,
  3282. NULL))
  3283. {
  3284. dwRet = GetLastError();
  3285. AE_DEBUG((AE_ERROR, L"Could not register ACRS store: (%lx)\n\r", dwRet ));
  3286. LogAutoEnrollmentError(HRESULT_FROM_WIN32(dwRet),
  3287. EVENT_AE_LOCAL_CYCLE_INIT_FAILED,
  3288. fMachineEnrollment,
  3289. hToken,
  3290. NULL, NULL);
  3291. goto Ret;
  3292. }
  3293. }
  3294. // open the ACRS store and fine the CTL based on the auto enrollment usage
  3295. if (0 == (hACRSStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
  3296. 0, 0, dwOpenStoreFlags, L"ACRS")))
  3297. {
  3298. dwRet = GetLastError();
  3299. AE_DEBUG((AE_ERROR, L"Could not open ACRS store: (%lx)\n\r", dwRet ));
  3300. LogAutoEnrollmentError(HRESULT_FROM_WIN32(dwRet),
  3301. EVENT_AE_LOCAL_CYCLE_INIT_FAILED,
  3302. fMachineEnrollment,
  3303. hToken,
  3304. NULL, NULL);
  3305. goto Ret;
  3306. }
  3307. // look for the Auto Enrollment usage
  3308. CTLFindUsage.SubjectUsage.cUsageIdentifier = 1;
  3309. pszCTLUsageOID = szOID_AUTO_ENROLL_CTL_USAGE;
  3310. CTLFindUsage.SubjectUsage.rgpszUsageIdentifier = &pszCTLUsageOID;
  3311. for (i=0;;i++)
  3312. {
  3313. AE_INSTANCE_INFO Instance;
  3314. memset(&Instance, 0, sizeof(Instance));
  3315. if (NULL == (pCTLContext = CertFindCTLInStore(hACRSStore,
  3316. X509_ASN_ENCODING,
  3317. CTL_FIND_SAME_USAGE_FLAG,
  3318. CTL_FIND_USAGE,
  3319. &CTLFindUsage,
  3320. pPrevCTLContext)))
  3321. {
  3322. // Freed by CertFindCTLInStore.
  3323. pPrevCTLContext = NULL;
  3324. break;
  3325. }
  3326. pPrevCTLContext = pCTLContext;
  3327. if(!fInitialized)
  3328. {
  3329. if(pld == NULL)
  3330. { dwRet = aeRobustLdapBind(&pld, FALSE);
  3331. if(dwRet != S_OK)
  3332. {
  3333. goto Ret;
  3334. }
  3335. }
  3336. // Initialize the internal information needed for an auto enrollment
  3337. if (S_OK != (dwRet = InitInternalInfo(pld,
  3338. fMachineEnrollment,
  3339. hToken,
  3340. &InternalInfo)))
  3341. {
  3342. break;
  3343. }
  3344. if(InternalInfo.ccaList == 0)
  3345. {
  3346. // No CA's
  3347. break;
  3348. }
  3349. fInitialized = TRUE;
  3350. }
  3351. if(!InitInstance(pPrevCTLContext,
  3352. &InternalInfo,
  3353. &Instance))
  3354. {
  3355. dwRet = E_FAIL;
  3356. break;
  3357. }
  3358. // UNDONE - perform a WinVerifyTrust check on this auto
  3359. // enrollment object (CTL) to make sure it is trusted
  3360. // have a CTL so do the Enrollment
  3361. EnrollmentWithCTL(&Instance, pld);
  3362. FreeInstance(&Instance);
  3363. }
  3364. }
  3365. __except ( dwRet = GetExceptionError(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER )
  3366. {
  3367. AE_DEBUG((AE_ERROR, L"Exception Caught (%lx)\n\r", dwRet ));
  3368. goto Ret;
  3369. }
  3370. Ret:
  3371. __try
  3372. {
  3373. FreeInternalInfo(&InternalInfo);
  3374. if(pPrevCTLContext)
  3375. {
  3376. CertFreeCTLContext(pPrevCTLContext);
  3377. }
  3378. if (hACRSStore)
  3379. CertCloseStore(hACRSStore, 0);
  3380. if (hToken)
  3381. {
  3382. if (!fMachineEnrollment)
  3383. {
  3384. RevertToSelf();
  3385. }
  3386. }
  3387. if(pld != NULL)
  3388. {
  3389. g_pfnldap_unbind(pld);
  3390. }
  3391. AE_END();
  3392. }
  3393. __except ( dwRet = GetExceptionError(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER )
  3394. {
  3395. return dwRet;
  3396. }
  3397. return dwRet;
  3398. }
  3399. //*************************************************************
  3400. //
  3401. // AutoEnrollmentThread()
  3402. //
  3403. // Purpose: Background thread for AutoEnrollment.
  3404. //
  3405. // Parameters: pInfo - AutoEnrollment info
  3406. //
  3407. // Return: 0
  3408. //
  3409. //*************************************************************
  3410. VOID AutoEnrollmentThread (PVOID pVoid, BOOLEAN fTimeout)
  3411. {
  3412. HINSTANCE hInst;
  3413. HKEY hKey;
  3414. HKEY hCurrent ;
  3415. DWORD dwType, dwSize, dwResult;
  3416. LONG lTimeout;
  3417. LARGE_INTEGER DueTime;
  3418. PAUTO_ENROLL_THREAD_INFO pInfo = pVoid;
  3419. DWORD dwWaitResult;
  3420. // This is executed in a worker thread, so we need to be safe.
  3421. AE_BEGIN(L"AutoEnrollmentThread");
  3422. if(fTimeout)
  3423. {
  3424. AE_END();
  3425. return ;
  3426. }
  3427. dwWaitResult = WaitForSingleObject(pInfo->fMachineEnrollment?g_hMachineMutex:g_hUserMutex, 0);
  3428. if((dwWaitResult == WAIT_FAILED) ||
  3429. (dwWaitResult == WAIT_TIMEOUT))
  3430. {
  3431. AE_DEBUG((AE_ERROR, L"Mutex Contention\n\r" ));
  3432. AE_END();
  3433. return;
  3434. }
  3435. __try
  3436. {
  3437. // Process the auto-enrollment.
  3438. ProcessAutoEnrollment(
  3439. pInfo->fMachineEnrollment,
  3440. pInfo->hToken
  3441. );
  3442. //
  3443. // Build a timer event to ping us
  3444. // in about 8 hours if we don't get
  3445. // notified.
  3446. lTimeout = AE_DEFAULT_REFRESH_RATE;
  3447. //
  3448. // Query for the refresh timer value
  3449. //
  3450. hCurrent = HKEY_LOCAL_MACHINE ;
  3451. if (pInfo->fMachineEnrollment || NT_SUCCESS( RtlOpenCurrentUser( KEY_READ, &hCurrent ) ) )
  3452. {
  3453. if (RegOpenKeyEx (hCurrent,
  3454. SYSTEM_POLICIES_KEY,
  3455. 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  3456. dwSize = sizeof(lTimeout);
  3457. RegQueryValueEx (hKey,
  3458. TEXT("AutoEnrollmentRefreshTime"),
  3459. NULL,
  3460. &dwType,
  3461. (LPBYTE) &lTimeout,
  3462. &dwSize);
  3463. RegCloseKey (hKey);
  3464. }
  3465. if (!pInfo->fMachineEnrollment)
  3466. {
  3467. RegCloseKey( hCurrent );
  3468. }
  3469. }
  3470. //
  3471. // Limit the timeout to once every 1080 hours (45 days)
  3472. //
  3473. if (lTimeout >= 1080) {
  3474. lTimeout = 1080;
  3475. }
  3476. if (lTimeout < 0) {
  3477. lTimeout = 0;
  3478. }
  3479. //
  3480. // Convert hours to milliseconds
  3481. //
  3482. lTimeout = lTimeout * 60 * 60 * 1000;
  3483. //
  3484. // Special case 0 milliseconds to be 7 seconds
  3485. //
  3486. if (lTimeout == 0) {
  3487. lTimeout = 7000;
  3488. }
  3489. DueTime.QuadPart = Int32x32To64(-10000, lTimeout);
  3490. if(!SetWaitableTimer (pInfo->hTimer, &DueTime, 0, NULL, 0, FALSE))
  3491. {
  3492. AE_DEBUG((AE_WARNING, L"Could not reset timer (%lx)\n\r", GetLastError()));
  3493. }
  3494. }
  3495. __except ( EXCEPTION_EXECUTE_HANDLER )
  3496. {
  3497. }
  3498. ReleaseMutex(pInfo->fMachineEnrollment?g_hMachineMutex:g_hUserMutex);
  3499. AE_END();
  3500. return ;
  3501. }
  3502. //*************************************************************
  3503. //
  3504. // AutoEnrollmentWorker()
  3505. //
  3506. // Purpose: Called by the worker thread mechanism to launch an auto-enrollment thread.
  3507. //
  3508. // Parameters: pInfo - AutoEnrollment info
  3509. //
  3510. // Return: 0
  3511. //
  3512. //*************************************************************
  3513. /*VOID AutoEnrollmentWorker (PVOID pVoid, BOOLEAN fTimeout)
  3514. {
  3515. if(fTimeout)
  3516. {
  3517. return ;
  3518. }
  3519. }*/
  3520. //+---------------------------------------------------------------------------
  3521. //
  3522. // Function: StartAutoEnrollThread
  3523. //
  3524. // Synopsis: Starts a thread which causes Autoenrollment
  3525. //
  3526. // Arguments:
  3527. // fMachineEnrollment - indicates if enrolling for a machine
  3528. //
  3529. // History: 01-11-98 jeffspel Created
  3530. //
  3531. // Notes:
  3532. //
  3533. //----------------------------------------------------------------------------
  3534. HANDLE RegisterAutoEnrollmentProcessing(
  3535. IN BOOL fMachineEnrollment,
  3536. IN HANDLE hToken
  3537. )
  3538. {
  3539. DWORD dwThreadId;
  3540. HANDLE hWait = 0;
  3541. PAUTO_ENROLL_THREAD_INFO pThreadInfo = NULL;
  3542. TCHAR szEventName[60];
  3543. LARGE_INTEGER DueTime;
  3544. HKEY hKeySafeBoot = NULL;
  3545. DWORD dwStatus = ERROR_SUCCESS;
  3546. SECURITY_ATTRIBUTES sa = {0,NULL, FALSE};
  3547. AE_DEBUG((AE_TRACE, L"RegisterAutoEnrollmentProcessing:%ls\n\r",fMachineEnrollment?L"Machine":L"User"));
  3548. __try
  3549. {
  3550. //
  3551. // We don't do autoenrollment in safe boot
  3552. //
  3553. // copied from the service controller code
  3554. dwStatus = RegOpenKey(HKEY_LOCAL_MACHINE,
  3555. L"system\\currentcontrolset\\control\\safeboot\\option",
  3556. &hKeySafeBoot);
  3557. if (dwStatus == ERROR_SUCCESS) {
  3558. DWORD dwSafeBoot = 0;
  3559. DWORD cbSafeBoot = sizeof(dwSafeBoot);
  3560. //
  3561. // we did in fact boot under safeboot control
  3562. //
  3563. dwStatus = RegQueryValueEx(hKeySafeBoot,
  3564. L"OptionValue",
  3565. NULL,
  3566. NULL,
  3567. (LPBYTE)&dwSafeBoot,
  3568. &cbSafeBoot);
  3569. if (dwStatus != ERROR_SUCCESS)
  3570. {
  3571. dwSafeBoot = 0;
  3572. }
  3573. RegCloseKey(hKeySafeBoot);
  3574. if(dwSafeBoot)
  3575. {
  3576. goto error;
  3577. }
  3578. }
  3579. if((g_hInstSecur32 == NULL) ||
  3580. (g_hInstWldap32 == NULL))
  3581. {
  3582. goto error;
  3583. }
  3584. if (NULL == (pThreadInfo = AEAlloc(sizeof(AUTO_ENROLL_THREAD_INFO))))
  3585. {
  3586. goto error;
  3587. }
  3588. ZeroMemory(pThreadInfo, sizeof(AUTO_ENROLL_THREAD_INFO));
  3589. pThreadInfo->fMachineEnrollment = fMachineEnrollment;
  3590. // if this is a user auto enrollment then duplicate the thread token
  3591. if (!pThreadInfo->fMachineEnrollment)
  3592. {
  3593. if (!DuplicateToken(hToken, SecurityImpersonation,
  3594. &pThreadInfo->hToken))
  3595. {
  3596. AE_DEBUG((AE_ERROR, L"Could not acquire user token: (%lx)\n\r", GetLastError()));
  3597. goto error;
  3598. }
  3599. }
  3600. sa.nLength = sizeof(sa);
  3601. sa.bInheritHandle = FALSE;
  3602. sa.lpSecurityDescriptor = AEMakeGenericSecurityDesc();
  3603. pThreadInfo->hNotifyEvent = CreateEvent(&sa, FALSE, FALSE, fMachineEnrollment?
  3604. MACHINE_AUTOENROLLMENT_TRIGGER_EVENT:
  3605. USER_AUTOENROLLMENT_TRIGGER_EVENT);
  3606. if(sa.lpSecurityDescriptor)
  3607. {
  3608. LocalFree(sa.lpSecurityDescriptor);
  3609. }
  3610. if(pThreadInfo->hNotifyEvent == NULL)
  3611. {
  3612. AE_DEBUG((AE_ERROR, L"Could not create GPO Notification Event: (%lx)\n\r", GetLastError()));
  3613. goto error;
  3614. }
  3615. if(!RegisterGPNotification(pThreadInfo->hNotifyEvent,
  3616. pThreadInfo->fMachineEnrollment))
  3617. {
  3618. AE_DEBUG((AE_ERROR, L"Could not register for GPO Notification: (%lx)\n\r", GetLastError()));
  3619. goto error;
  3620. }
  3621. if(pThreadInfo->fMachineEnrollment)
  3622. {
  3623. wsprintf (szEventName, TEXT("AUTOENRL: machine refresh timer for %d:%d"),
  3624. GetCurrentProcessId(), GetCurrentThreadId());
  3625. }
  3626. else
  3627. {
  3628. wsprintf (szEventName, TEXT("AUTOENRL: user refresh timer for %d:%d"),
  3629. GetCurrentProcessId(), GetCurrentThreadId());
  3630. }
  3631. pThreadInfo->hTimer = CreateWaitableTimer (NULL, FALSE, szEventName);
  3632. if(pThreadInfo->hTimer == NULL)
  3633. {
  3634. goto error;
  3635. }
  3636. if (! RegisterWaitForSingleObject(&pThreadInfo->hNotifyWait,
  3637. pThreadInfo->hNotifyEvent,
  3638. AutoEnrollmentThread,
  3639. (PVOID)pThreadInfo,
  3640. INFINITE,
  3641. 0))
  3642. {
  3643. AE_DEBUG((AE_ERROR, L"RegisterWait failed: (%lx)\n\r", GetLastError() ));
  3644. goto error;
  3645. }
  3646. if (! RegisterWaitForSingleObject(&pThreadInfo->hTimerWait,
  3647. pThreadInfo->hTimer,
  3648. AutoEnrollmentThread,
  3649. (void*)pThreadInfo,
  3650. INFINITE,
  3651. 0))
  3652. {
  3653. AE_DEBUG((AE_ERROR, L"RegisterWait failed: (%lx)\n\r", GetLastError()));
  3654. goto error;
  3655. }
  3656. // Seed the timer with about 5 minutes, so we can come back
  3657. // and run an auto-enroll later without blocking this thread.
  3658. DueTime.QuadPart = Int32x32To64(-10000,
  3659. (fMachineEnrollment?MACHINE_AUTOENROLL_INITIAL_DELAY:
  3660. USER_AUTOENROLL_INITIAL_DELAY)
  3661. * 1000);
  3662. if(!SetWaitableTimer (pThreadInfo->hTimer, &DueTime, 0, NULL, 0, FALSE))
  3663. {
  3664. AE_DEBUG((AE_WARNING, L"Could not reset timer (%lx)\n\r", GetLastError()));
  3665. }
  3666. }
  3667. __except ( EXCEPTION_EXECUTE_HANDLER )
  3668. {
  3669. goto error;
  3670. }
  3671. AE_RETURN(pThreadInfo);
  3672. error:
  3673. if(pThreadInfo)
  3674. {
  3675. if(pThreadInfo->hTimerWait)
  3676. {
  3677. UnregisterWaitEx(pThreadInfo->hTimerWait, INVALID_HANDLE_VALUE );
  3678. }
  3679. if(pThreadInfo->hTimer)
  3680. {
  3681. CloseHandle(pThreadInfo->hTimer);
  3682. }
  3683. if(pThreadInfo->hNotifyWait)
  3684. {
  3685. UnregisterWaitEx(pThreadInfo->hNotifyWait, INVALID_HANDLE_VALUE);
  3686. }
  3687. if(pThreadInfo->hNotifyEvent)
  3688. {
  3689. CloseHandle(pThreadInfo->hNotifyEvent);
  3690. }
  3691. if(pThreadInfo->hToken)
  3692. {
  3693. CloseHandle(pThreadInfo->hToken);
  3694. }
  3695. AEFree(pThreadInfo);
  3696. }
  3697. AE_RETURN(NULL);
  3698. }
  3699. BOOL DeRegisterAutoEnrollment(HANDLE hAuto)
  3700. {
  3701. PAUTO_ENROLL_THREAD_INFO pThreadInfo = (PAUTO_ENROLL_THREAD_INFO)hAuto;
  3702. if(pThreadInfo == NULL)
  3703. {
  3704. return FALSE;
  3705. }
  3706. if(pThreadInfo->hTimerWait)
  3707. {
  3708. UnregisterWaitEx(pThreadInfo->hTimerWait, INVALID_HANDLE_VALUE);
  3709. }
  3710. if(pThreadInfo->hTimer)
  3711. {
  3712. CloseHandle(pThreadInfo->hTimer);
  3713. }
  3714. if(pThreadInfo->hNotifyWait)
  3715. {
  3716. UnregisterWaitEx(pThreadInfo->hNotifyWait, INVALID_HANDLE_VALUE );
  3717. }
  3718. if(pThreadInfo->hNotifyEvent)
  3719. {
  3720. UnregisterGPNotification(pThreadInfo->hNotifyEvent);
  3721. CloseHandle(pThreadInfo->hNotifyEvent);
  3722. }
  3723. if(pThreadInfo->hToken)
  3724. {
  3725. CloseHandle(pThreadInfo->hToken);
  3726. }
  3727. AEFree(pThreadInfo);
  3728. return TRUE;
  3729. }
  3730. VOID InitializeAutoEnrollmentSupport (VOID)
  3731. {
  3732. // NOTE, auto-enrollment is registered by
  3733. // the GPO download startup code.
  3734. AE_BEGIN(L"InitializeAutoEnrollmentSupport");
  3735. g_hUserMutex = CreateMutex(NULL, FALSE, NULL);
  3736. if(g_hUserMutex)
  3737. {
  3738. g_hMachineMutex = CreateMutex(NULL, FALSE, NULL);
  3739. }
  3740. if((g_hUserMutex == NULL) || (g_hMachineMutex == NULL))
  3741. {
  3742. AE_DEBUG((AE_ERROR, L"Could not create enrollment mutex (%lx)\n\r", GetLastError()));
  3743. AE_END();
  3744. return;
  3745. }
  3746. //
  3747. // Load some functions we need
  3748. //
  3749. g_hInstWldap32 = LoadLibrary (TEXT("wldap32.dll"));
  3750. if (!g_hInstWldap32) {
  3751. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3752. goto Exit;
  3753. }
  3754. g_pfnldap_init = (PFNLDAP_INIT) GetProcAddress (g_hInstWldap32,
  3755. #ifdef UNICODE
  3756. "ldap_initW");
  3757. #else
  3758. "ldap_initA");
  3759. #endif
  3760. if (!g_pfnldap_init) {
  3761. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3762. goto Exit;
  3763. }
  3764. g_pfnldap_bind_s = (PFNLDAP_BIND_S) GetProcAddress (g_hInstWldap32,
  3765. #ifdef UNICODE
  3766. "ldap_bind_sW");
  3767. #else
  3768. "ldap_bind_sA");
  3769. #endif
  3770. if (!g_pfnldap_bind_s) {
  3771. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3772. goto Exit;
  3773. }
  3774. g_pfnldap_set_option= (PFNLDAP_SET_OPTION) GetProcAddress (g_hInstWldap32,
  3775. "ldap_set_option");
  3776. if (!g_pfnldap_set_option) {
  3777. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3778. goto Exit;
  3779. }
  3780. g_pfnldap_search_ext_s = (PFNLDAP_SEARCH_EXT_S) GetProcAddress (g_hInstWldap32,
  3781. #ifdef UNICODE
  3782. "ldap_search_ext_sW");
  3783. #else
  3784. "ldap_search_ext_sA");
  3785. #endif
  3786. if (!g_pfnldap_search_ext_s) {
  3787. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3788. goto Exit;
  3789. }
  3790. g_pfnldap_explode_dn = (PFNLDAP_EXPLODE_DN) GetProcAddress (g_hInstWldap32,
  3791. #ifdef UNICODE
  3792. "ldap_explode_dnW");
  3793. #else
  3794. "ldap_explode_dnA");
  3795. #endif
  3796. if (!g_pfnldap_explode_dn) {
  3797. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3798. goto Exit;
  3799. }
  3800. g_pfnldap_first_entry = (PFNLDAP_FIRST_ENTRY) GetProcAddress (g_hInstWldap32,
  3801. "ldap_first_entry");
  3802. if (!g_pfnldap_first_entry) {
  3803. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3804. goto Exit;
  3805. }
  3806. g_pfnldap_get_values = (PFNLDAP_GET_VALUES) GetProcAddress (g_hInstWldap32,
  3807. #ifdef UNICODE
  3808. "ldap_get_valuesW");
  3809. #else
  3810. "ldap_get_valuesA");
  3811. #endif
  3812. if (!g_pfnldap_get_values) {
  3813. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3814. goto Exit;
  3815. }
  3816. g_pfnldap_value_free = (PFNLDAP_VALUE_FREE) GetProcAddress (g_hInstWldap32,
  3817. #ifdef UNICODE
  3818. "ldap_value_freeW");
  3819. #else
  3820. "ldap_value_freeA");
  3821. #endif
  3822. if (!g_pfnldap_value_free) {
  3823. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3824. goto Exit;
  3825. }
  3826. g_pfnldap_msgfree = (PFNLDAP_MSGFREE) GetProcAddress (g_hInstWldap32,
  3827. "ldap_msgfree");
  3828. if (!g_pfnldap_msgfree) {
  3829. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3830. goto Exit;
  3831. }
  3832. g_pfnldap_unbind = (PFNLDAP_UNBIND) GetProcAddress (g_hInstWldap32,
  3833. "ldap_unbind");
  3834. if (!g_pfnldap_unbind) {
  3835. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3836. goto Exit;
  3837. }
  3838. g_pfnLdapGetLastError = (PFNLDAPGETLASTERROR) GetProcAddress (g_hInstWldap32,
  3839. "LdapGetLastError");
  3840. if (!g_pfnLdapGetLastError) {
  3841. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3842. goto Exit;
  3843. }
  3844. g_pfnLdapMapErrorToWin32 = (PFNLDAPMAPERRORTOWIN32) GetProcAddress (g_hInstWldap32,
  3845. "LdapMapErrorToWin32");
  3846. if (!g_pfnLdapMapErrorToWin32) {
  3847. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3848. goto Exit;
  3849. }
  3850. g_hInstSecur32 = LoadLibrary (TEXT("secur32.dll"));
  3851. if (!g_hInstSecur32) {
  3852. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3853. goto Exit;
  3854. }
  3855. g_pfnGetUserNameEx = (PFNGETUSERNAMEEX)GetProcAddress (g_hInstSecur32,
  3856. #ifdef UNICODE
  3857. "GetUserNameExW");
  3858. #else
  3859. "GetUserNameExA");
  3860. #endif
  3861. if (!g_pfnGetUserNameEx) {
  3862. LogAutoEnrollmentError(GetLastError(), EVENT_AE_INITIALIZATION_FAILED, TRUE, NULL, NULL, NULL);
  3863. goto Exit;
  3864. }
  3865. AE_END();
  3866. return;
  3867. Exit:
  3868. if(g_hInstSecur32)
  3869. {
  3870. FreeLibrary(g_hInstSecur32);
  3871. g_hInstSecur32 = NULL;
  3872. }
  3873. if(g_hInstWldap32)
  3874. {
  3875. FreeLibrary(g_hInstWldap32);
  3876. g_hInstWldap32 = NULL;
  3877. }
  3878. AE_END();
  3879. return;
  3880. }
  3881. #if DBG
  3882. void
  3883. AEDebugLog(long Mask, LPCWSTR Format, ...)
  3884. {
  3885. va_list ArgList;
  3886. int Level = 0;
  3887. int PrefixSize = 0;
  3888. int iOut;
  3889. WCHAR wszOutString[MAX_DEBUG_BUFFER];
  3890. long OriginalMask = Mask;
  3891. if (Mask & g_AutoenrollDebugLevel)
  3892. {
  3893. // Make the prefix first: "Process.Thread> GINA-XXX"
  3894. iOut = wsprintfW(
  3895. wszOutString,
  3896. L"%3d.%3d> AUTOENRL: ",
  3897. GetCurrentProcessId(),
  3898. GetCurrentThreadId());
  3899. va_start(ArgList, Format);
  3900. if (wvsprintf(&wszOutString[iOut], Format, ArgList) < 0)
  3901. {
  3902. static WCHAR wszOverFlow[] = L"\n<256 byte OVERFLOW!>\n";
  3903. // Less than zero indicates that the string would not fit into the
  3904. // buffer. Output a special message indicating overflow.
  3905. wcscpy(
  3906. &wszOutString[(sizeof(wszOutString) - sizeof(wszOverFlow))/sizeof(WCHAR)],
  3907. wszOverFlow);
  3908. }
  3909. va_end(ArgList);
  3910. OutputDebugStringW(wszOutString);
  3911. }
  3912. }
  3913. #endif
  3914. HRESULT
  3915. myGetConfigDN(
  3916. IN LDAP *pld,
  3917. OUT LPWSTR *pwszConfigDn
  3918. )
  3919. {
  3920. HRESULT hr;
  3921. ULONG LdapError;
  3922. LDAPMessage *SearchResult = NULL;
  3923. LDAPMessage *Entry = NULL;
  3924. WCHAR *Attr = NULL;
  3925. BerElement *BerElement;
  3926. WCHAR **Values = NULL;
  3927. WCHAR *AttrArray[3];
  3928. struct l_timeval timeout;
  3929. WCHAR *ConfigurationNamingContext = L"configurationNamingContext";
  3930. WCHAR *ObjectClassFilter = L"objectCategory=*";
  3931. //
  3932. // Set the out parameters to null
  3933. //
  3934. if(pwszConfigDn)
  3935. {
  3936. *pwszConfigDn = NULL;
  3937. }
  3938. timeout.tv_sec = csecLDAPTIMEOUT;
  3939. timeout.tv_usec = 0;
  3940. //
  3941. // Query for the ldap server oerational attributes to obtain the default
  3942. // naming context.
  3943. //
  3944. AttrArray[0] = ConfigurationNamingContext;
  3945. AttrArray[1] = NULL; // this is the sentinel
  3946. LdapError = g_pfnldap_search_ext_s(pld,
  3947. NULL,
  3948. LDAP_SCOPE_BASE,
  3949. ObjectClassFilter,
  3950. AttrArray,
  3951. FALSE,
  3952. NULL,
  3953. NULL,
  3954. &timeout,
  3955. 10000,
  3956. &SearchResult);
  3957. hr = HRESULT_FROM_WIN32(g_pfnLdapMapErrorToWin32(LdapError));
  3958. if (S_OK == hr) {
  3959. Entry = g_pfnldap_first_entry(pld, SearchResult);
  3960. if (Entry) {
  3961. Values = g_pfnldap_get_values(pld,
  3962. Entry,
  3963. ConfigurationNamingContext);
  3964. if (Values && Values[0]) {
  3965. (*pwszConfigDn) = (LPWSTR)LocalAlloc(LMEM_FIXED, sizeof(WCHAR)*(wcslen(Values[0])+1));
  3966. if(NULL==(*pwszConfigDn))
  3967. hr=E_OUTOFMEMORY;
  3968. else
  3969. wcscpy((*pwszConfigDn), Values[0]);
  3970. }
  3971. g_pfnldap_value_free(Values);
  3972. }
  3973. if (pwszConfigDn && (!(*pwszConfigDn))) {
  3974. //
  3975. // We could not get the default domain or out of memory - bail out
  3976. //
  3977. if(E_OUTOFMEMORY != hr)
  3978. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  3979. }
  3980. if(SearchResult)
  3981. {
  3982. g_pfnldap_msgfree(SearchResult);
  3983. }
  3984. }
  3985. return hr;
  3986. }
  3987. LPWSTR HelperExtensionToString(PCERT_EXTENSION Extension)
  3988. {
  3989. LPWSTR wszFormat = NULL;
  3990. DWORD cbFormat = 0;
  3991. if(NULL==Extension)
  3992. return NULL;
  3993. CryptFormatObject(X509_ASN_ENCODING,
  3994. 0,
  3995. 0,
  3996. NULL,
  3997. Extension->pszObjId,
  3998. Extension->Value.pbData,
  3999. Extension->Value.cbData,
  4000. NULL,
  4001. &cbFormat);
  4002. if(cbFormat)
  4003. {
  4004. wszFormat = (LPWSTR)AEAlloc(cbFormat);
  4005. if(wszFormat == NULL)
  4006. {
  4007. return NULL;
  4008. }
  4009. CryptFormatObject(X509_ASN_ENCODING,
  4010. 0,
  4011. 0,
  4012. NULL,
  4013. Extension->pszObjId,
  4014. Extension->Value.pbData,
  4015. Extension->Value.cbData,
  4016. wszFormat,
  4017. &cbFormat);
  4018. }
  4019. return wszFormat;
  4020. }
  4021. //*************************************************************
  4022. //
  4023. // MakeGenericSecurityDesc()
  4024. //
  4025. // Purpose: manufacture a security descriptor with generic
  4026. // access
  4027. //
  4028. // Parameters:
  4029. //
  4030. // Return: pointer to SECURITY_DESCRIPTOR or NULL on error
  4031. //
  4032. // Comments:
  4033. //
  4034. // History: Date Author Comment
  4035. // 4/12/99 NishadM Created
  4036. //
  4037. //*************************************************************
  4038. PISECURITY_DESCRIPTOR AEMakeGenericSecurityDesc()
  4039. {
  4040. PISECURITY_DESCRIPTOR psd = 0;
  4041. SID_IDENTIFIER_AUTHORITY authNT = SECURITY_NT_AUTHORITY;
  4042. SID_IDENTIFIER_AUTHORITY authWORLD = SECURITY_WORLD_SID_AUTHORITY;
  4043. PACL pAcl = 0;
  4044. PSID psidSystem = 0,
  4045. psidAdmin = 0,
  4046. psidEveryOne = 0;
  4047. DWORD cbMemSize;
  4048. DWORD cbAcl;
  4049. DWORD aceIndex;
  4050. BOOL bSuccess = FALSE;
  4051. //
  4052. // Get the system sid
  4053. //
  4054. if (!AllocateAndInitializeSid(&authNT, 1, SECURITY_LOCAL_SYSTEM_RID,
  4055. 0, 0, 0, 0, 0, 0, 0, &psidSystem)) {
  4056. goto Exit;
  4057. }
  4058. //
  4059. // Get the Admin sid
  4060. //
  4061. if (!AllocateAndInitializeSid(&authNT, 2, SECURITY_BUILTIN_DOMAIN_RID,
  4062. DOMAIN_ALIAS_RID_ADMINS, 0, 0,
  4063. 0, 0, 0, 0, &psidAdmin)) {
  4064. goto Exit;
  4065. }
  4066. //
  4067. // Get the EveryOne sid
  4068. //
  4069. if (!AllocateAndInitializeSid(&authWORLD, 1, SECURITY_WORLD_RID,
  4070. 0, 0, 0, 0, 0, 0, 0, &psidEveryOne)) {
  4071. goto Exit;
  4072. }
  4073. cbAcl = (2 * GetLengthSid (psidSystem)) +
  4074. (2 * GetLengthSid (psidAdmin)) +
  4075. (2 * GetLengthSid (psidEveryOne)) +
  4076. sizeof(ACL) +
  4077. (6 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
  4078. //
  4079. // Allocate space for the SECURITY_DESCRIPTOR + ACL
  4080. //
  4081. cbMemSize = sizeof( SECURITY_DESCRIPTOR ) + cbAcl;
  4082. psd = (PISECURITY_DESCRIPTOR) GlobalAlloc(GMEM_FIXED, cbMemSize);
  4083. if (!psd) {
  4084. goto Exit;
  4085. }
  4086. //
  4087. // increment psd by sizeof SECURITY_DESCRIPTOR
  4088. //
  4089. pAcl = (PACL) ( ( (unsigned char*)(psd) ) + sizeof(SECURITY_DESCRIPTOR) );
  4090. if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) {
  4091. goto Exit;
  4092. }
  4093. //
  4094. // GENERIC_ALL for local system
  4095. //
  4096. aceIndex = 0;
  4097. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidSystem)) {
  4098. goto Exit;
  4099. }
  4100. //
  4101. // GENERIC_ALL for Administrators
  4102. //
  4103. aceIndex++;
  4104. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin)) {
  4105. goto Exit;
  4106. }
  4107. //
  4108. // GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | SYNCHRONIZE for world
  4109. //
  4110. aceIndex++;
  4111. if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | SYNCHRONIZE, psidEveryOne)) {
  4112. goto Exit;
  4113. }
  4114. //
  4115. // Put together the security descriptor
  4116. //
  4117. if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION)) {
  4118. goto Exit;
  4119. }
  4120. if (!SetSecurityDescriptorDacl(psd, TRUE, pAcl, FALSE)) {
  4121. goto Exit;
  4122. }
  4123. bSuccess = TRUE;
  4124. Exit:
  4125. if (psidSystem) {
  4126. FreeSid(psidSystem);
  4127. }
  4128. if (psidAdmin) {
  4129. FreeSid(psidAdmin);
  4130. }
  4131. if (psidEveryOne) {
  4132. FreeSid(psidEveryOne);
  4133. }
  4134. if (!bSuccess && psd) {
  4135. GlobalFree(psd);
  4136. psd = 0;
  4137. }
  4138. return psd;
  4139. }
  4140. HRESULT
  4141. aeRobustLdapBind(
  4142. OUT LDAP ** ppldap,
  4143. IN BOOL fGC)
  4144. {
  4145. DWORD dwErr = ERROR_SUCCESS;
  4146. HRESULT hr = S_OK;
  4147. BOOL fForceRediscovery = FALSE;
  4148. DWORD dwGetDCFlags = DS_RETURN_DNS_NAME | DS_BACKGROUND_ONLY;
  4149. PDOMAIN_CONTROLLER_INFO pDomainInfo = NULL;
  4150. LDAP *pld = NULL;
  4151. LPWSTR wszDomainControllerName = NULL;
  4152. ULONG ldaperr;
  4153. if(fGC)
  4154. {
  4155. dwGetDCFlags |= DS_GC_SERVER_REQUIRED;
  4156. }
  4157. do {
  4158. // netapi32!DsGetDcName is delay loaded, so wrap
  4159. if(fForceRediscovery)
  4160. {
  4161. dwGetDCFlags |= DS_FORCE_REDISCOVERY;
  4162. }
  4163. ldaperr = LDAP_SERVER_DOWN;
  4164. __try
  4165. {
  4166. // Get the GC location
  4167. dwErr = DsGetDcName(NULL, // Delayload wrapped
  4168. NULL,
  4169. NULL,
  4170. NULL,
  4171. dwGetDCFlags,
  4172. &pDomainInfo);
  4173. }
  4174. __except(dwErr = GetExceptionError(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER)
  4175. {
  4176. }
  4177. if(dwErr != ERROR_SUCCESS)
  4178. {
  4179. hr = HRESULT_FROM_WIN32(dwErr);
  4180. goto error;
  4181. }
  4182. if((pDomainInfo == NULL) ||
  4183. ((pDomainInfo->Flags & DS_GC_FLAG) == 0) ||
  4184. ((pDomainInfo->Flags & DS_DNS_CONTROLLER_FLAG) == 0) ||
  4185. (pDomainInfo->DomainControllerName == NULL))
  4186. {
  4187. if(!fForceRediscovery)
  4188. {
  4189. fForceRediscovery = TRUE;
  4190. continue;
  4191. }
  4192. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  4193. goto error;
  4194. }
  4195. wszDomainControllerName = pDomainInfo->DomainControllerName;
  4196. // skip past forward slashes (why are they there?)
  4197. while(*wszDomainControllerName == L'\\')
  4198. {
  4199. wszDomainControllerName++;
  4200. }
  4201. // bind to ds
  4202. if((pld = g_pfnldap_init(wszDomainControllerName, fGC?LDAP_GC_PORT:LDAP_PORT)) == NULL)
  4203. {
  4204. ldaperr = g_pfnLdapGetLastError();
  4205. }
  4206. else
  4207. {
  4208. ldaperr = g_pfnldap_bind_s(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  4209. }
  4210. hr = HRESULT_FROM_WIN32(g_pfnLdapMapErrorToWin32(ldaperr));
  4211. if(fForceRediscovery)
  4212. {
  4213. break;
  4214. }
  4215. fForceRediscovery = TRUE;
  4216. } while(ldaperr == LDAP_SERVER_DOWN);
  4217. if(hr == S_OK)
  4218. {
  4219. *ppldap = pld;
  4220. pld = NULL;
  4221. }
  4222. error:
  4223. if(pld)
  4224. {
  4225. g_pfnldap_unbind(pld);
  4226. }
  4227. // we know netapi32 was already loaded safely (that's where we got pDomainInfo), so no need to wrap
  4228. if(pDomainInfo)
  4229. {
  4230. NetApiBufferFree(pDomainInfo); // Delayload wrapped
  4231. }
  4232. return hr;
  4233. }