Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1003 lines
26 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 2001
  6. //
  7. // File: tinstall.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <windows.h>
  14. #include <stdio.h>
  15. #include <certca.h>
  16. #include <winldap.h>
  17. #include <ntldap.h>
  18. #include <dsrole.h>
  19. #include <dsgetdc.h>
  20. #include <accctrl.h>
  21. #include <lmaccess.h>
  22. #include <lmapibuf.h>
  23. #include <lmerr.h>
  24. //--------------------------------------------------------------------------
  25. //
  26. // Defines
  27. //
  28. //--------------------------------------------------------------------------
  29. #define DS_RETEST_SECONDS 3
  30. #define CVT_BASE (1000 * 1000 * 10)
  31. #define CVT_SECONDS (1)
  32. #define CERTTYPE_SECURITY_DESCRIPTOR_NAME L"NTSecurityDescriptor"
  33. #define TEMPLATE_CONTAINER_NAME L"CN=Certificate Templates,CN=Public Key Services,CN=Services,"
  34. #define SCHEMA_CONTAINER_NAME L"CN=Schema,"
  35. typedef WCHAR *CERTSTR;
  36. bool g_bSchemaIsW2K = false;
  37. //--------------------------------------------------------------------------
  38. //
  39. //
  40. // Helper Functions
  41. //
  42. //--------------------------------------------------------------------------
  43. HANDLE GetClientIdentity()
  44. {
  45. HANDLE hHandle = NULL;
  46. HANDLE hClientToken = NULL;
  47. HANDLE hProcessToken = NULL;
  48. // Step 1: attempt to acquire the thread token.
  49. hHandle = GetCurrentThread();
  50. if ( hHandle )
  51. {
  52. if ( OpenThreadToken(hHandle,
  53. TOKEN_QUERY,
  54. TRUE, // open as self
  55. &hClientToken))
  56. goto Exit;
  57. }
  58. if (hHandle != NULL)
  59. {
  60. CloseHandle(hHandle);
  61. hHandle=NULL;
  62. }
  63. // We failed to get the thread token, now try to acquire the process token:
  64. hHandle = GetCurrentProcess();
  65. if (NULL == hHandle)
  66. goto Exit;
  67. if (!OpenProcessToken(hHandle,
  68. TOKEN_DUPLICATE,
  69. &hProcessToken))
  70. goto Exit;
  71. if(!DuplicateToken(hProcessToken,
  72. SecurityImpersonation,
  73. &hClientToken))
  74. goto Exit;
  75. Exit:
  76. if (NULL != hHandle)
  77. CloseHandle(hHandle);
  78. if (NULL != hProcessToken)
  79. CloseHandle(hProcessToken);
  80. return hClientToken;
  81. }
  82. HRESULT myHError(HRESULT hr)
  83. {
  84. if (S_OK != hr && S_FALSE != hr && !FAILED(hr))
  85. {
  86. hr = HRESULT_FROM_WIN32(hr);
  87. if ( SUCCEEDED (hr) )
  88. {
  89. // A call failed without properly setting an error condition!
  90. hr = E_UNEXPECTED;
  91. }
  92. }
  93. return(hr);
  94. }
  95. HRESULT
  96. myDupString(
  97. IN WCHAR const *pwszIn,
  98. IN WCHAR **ppwszOut)
  99. {
  100. HRESULT hr = S_OK;
  101. size_t cb = (wcslen(pwszIn) + 1) * sizeof(WCHAR);
  102. *ppwszOut = (WCHAR *) LocalAlloc(LMEM_FIXED, cb);
  103. if (NULL == *ppwszOut)
  104. {
  105. hr = E_OUTOFMEMORY;
  106. goto error;
  107. }
  108. CopyMemory(*ppwszOut, pwszIn, cb);
  109. hr = S_OK;
  110. error:
  111. return(hr);
  112. }
  113. DWORD
  114. CAGetAuthoritativeDomainDn(
  115. IN LDAP* LdapHandle,
  116. OUT CString* pszDomainDn,
  117. OUT CString* pszConfigDn
  118. )
  119. /*++
  120. Routine Description:
  121. This routine simply queries the operational attributes for the
  122. domaindn and configdn.
  123. The strings returned by this routine must be freed by the caller
  124. using RtlFreeHeap() using the process heap.
  125. Parameters:
  126. LdapHandle : a valid handle to an ldap session
  127. pszDomainDn : a pointer to a string to be allocated in this routine
  128. pszConfigDn : a pointer to a string to be allocated in this routine
  129. Return Values:
  130. An error from the win32 error space.
  131. ERROR_SUCCESS and
  132. Other operation errors.
  133. --*/
  134. {
  135. DWORD WinError = ERROR_SUCCESS;
  136. ULONG LdapError;
  137. LDAPMessage *SearchResult = NULL;
  138. LDAPMessage *Entry = NULL;
  139. WCHAR *Attr = NULL;
  140. BerElement *BerElement;
  141. WCHAR **Values = NULL;
  142. WCHAR *AttrArray[3];
  143. WCHAR *DefaultNamingContext = L"defaultNamingContext";
  144. WCHAR *ConfigNamingContext = L"configurationNamingContext";
  145. WCHAR *ObjectClassFilter = L"objectClass=*";
  146. //
  147. // These must be present
  148. //
  149. //
  150. // Set the out parameters to null
  151. //
  152. if ( pszDomainDn )
  153. *pszDomainDn = L"";
  154. if ( pszConfigDn )
  155. *pszConfigDn = L"";
  156. //
  157. // Query for the ldap server oerational attributes to obtain the default
  158. // naming context.
  159. //
  160. AttrArray[0] = DefaultNamingContext;
  161. AttrArray[1] = ConfigNamingContext; // this is the sentinel
  162. AttrArray[2] = NULL; // this is the sentinel
  163. __try
  164. {
  165. LdapError = ldap_search_sW(LdapHandle,
  166. NULL,
  167. LDAP_SCOPE_BASE,
  168. ObjectClassFilter,
  169. AttrArray,
  170. FALSE,
  171. &SearchResult);
  172. WinError = LdapMapErrorToWin32(LdapError);
  173. if (ERROR_SUCCESS == WinError) {
  174. Entry = ldap_first_entry(LdapHandle, SearchResult);
  175. if (Entry)
  176. {
  177. Attr = ldap_first_attributeW(LdapHandle, Entry, &BerElement);
  178. while (Attr)
  179. {
  180. if (!_wcsicmp(Attr, DefaultNamingContext))
  181. {
  182. if ( pszDomainDn )
  183. {
  184. Values = ldap_get_values(LdapHandle, Entry, Attr);
  185. if (Values && Values[0])
  186. {
  187. *pszDomainDn = Values[0];
  188. }
  189. ldap_value_free(Values);
  190. }
  191. }
  192. else if (!_wcsicmp(Attr, ConfigNamingContext))
  193. {
  194. if ( pszConfigDn )
  195. {
  196. Values = ldap_get_values(LdapHandle, Entry, Attr);
  197. if (Values && Values[0])
  198. {
  199. *pszConfigDn = Values[0];
  200. }
  201. ldap_value_free(Values);
  202. }
  203. }
  204. Attr = ldap_next_attribute(LdapHandle, Entry, BerElement);
  205. }
  206. }
  207. if ( pszDomainDn && pszDomainDn->IsEmpty () )
  208. {
  209. //
  210. // We could get the default domain - bail out
  211. //
  212. WinError = ERROR_CANT_ACCESS_DOMAIN_INFO;
  213. }
  214. else if ( pszConfigDn && pszConfigDn->IsEmpty () )
  215. {
  216. //
  217. // We could get the default domain - bail out
  218. //
  219. WinError = ERROR_CANT_ACCESS_DOMAIN_INFO;
  220. }
  221. }
  222. }
  223. __except(WinError = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER)
  224. {
  225. }
  226. // make sure we free this
  227. if (SearchResult)
  228. ldap_msgfree( SearchResult );
  229. return WinError;
  230. }
  231. HRESULT
  232. myDoesDSExist(
  233. IN BOOL fRetry)
  234. {
  235. HRESULT hr = S_OK;
  236. static BOOL s_fKnowDSExists = FALSE;
  237. static HRESULT s_hrDSExists = HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN);
  238. static FILETIME s_ftNextTest = {0,0};
  239. if (s_fKnowDSExists && (s_hrDSExists != S_OK) && fRetry)
  240. // s_fKnowDSExists = FALSE; // force a retry
  241. {
  242. FILETIME ftCurrent;
  243. GetSystemTimeAsFileTime(&ftCurrent);
  244. // if Compare is < 0 (next < current), force retest
  245. if (0 > CompareFileTime(&s_ftNextTest, &ftCurrent))
  246. s_fKnowDSExists = FALSE;
  247. }
  248. if (!s_fKnowDSExists)
  249. {
  250. GetSystemTimeAsFileTime(&s_ftNextTest);
  251. // set NEXT in 100ns increments
  252. ((LARGE_INTEGER *) &s_ftNextTest)->QuadPart +=
  253. (__int64) (CVT_BASE * CVT_SECONDS * 60) * DS_RETEST_SECONDS;
  254. // NetApi32 is delay loaded, so wrap to catch problems when it's not available
  255. __try
  256. {
  257. DOMAIN_CONTROLLER_INFO *pDCI;
  258. DSROLE_PRIMARY_DOMAIN_INFO_BASIC *pDsRole;
  259. // ensure we're not standalone
  260. pDsRole = NULL;
  261. hr = DsRoleGetPrimaryDomainInformation( // Delayload wrapped
  262. NULL,
  263. DsRolePrimaryDomainInfoBasic,
  264. (BYTE **) &pDsRole);
  265. if (S_OK == hr &&
  266. (pDsRole->MachineRole == DsRole_RoleStandaloneServer ||
  267. pDsRole->MachineRole == DsRole_RoleStandaloneWorkstation))
  268. {
  269. hr = HRESULT_FROM_WIN32(ERROR_NO_SUCH_DOMAIN);
  270. }
  271. if (NULL != pDsRole)
  272. {
  273. DsRoleFreeMemory(pDsRole); // Delayload wrapped
  274. }
  275. if (S_OK == hr)
  276. {
  277. // not standalone; return info on our DS
  278. pDCI = NULL;
  279. hr = DsGetDcName( // Delayload wrapped
  280. NULL,
  281. NULL,
  282. NULL,
  283. NULL,
  284. DS_DIRECTORY_SERVICE_PREFERRED,
  285. &pDCI);
  286. if (S_OK == hr && 0 == (pDCI->Flags & DS_DS_FLAG))
  287. {
  288. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  289. }
  290. if (NULL != pDCI)
  291. {
  292. NetApiBufferFree(pDCI); // Delayload wrapped
  293. }
  294. }
  295. s_fKnowDSExists = TRUE;
  296. }
  297. __except(hr = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER)
  298. {
  299. }
  300. // else just allow users without netapi flounder with timeouts
  301. // if ds not available...
  302. s_hrDSExists = myHError(hr);
  303. }
  304. return(s_hrDSExists);
  305. }
  306. HRESULT
  307. myRobustLdapBindEx(
  308. OUT LDAP ** ppldap,
  309. OPTIONAL OUT LPWSTR* ppszForestDNSName,
  310. IN BOOL fGC)
  311. {
  312. HRESULT hr = S_OK;
  313. BOOL fForceRediscovery = FALSE;
  314. DWORD dwGetDCFlags = DS_RETURN_DNS_NAME;
  315. PDOMAIN_CONTROLLER_INFO pDomainInfo = NULL;
  316. LDAP *pld = NULL;
  317. WCHAR const *pwszDomainControllerName = NULL;
  318. ULONG ldaperr = 0;
  319. if (fGC)
  320. {
  321. dwGetDCFlags |= DS_GC_SERVER_REQUIRED;
  322. }
  323. do {
  324. if (fForceRediscovery)
  325. {
  326. dwGetDCFlags |= DS_FORCE_REDISCOVERY;
  327. }
  328. ldaperr = LDAP_SERVER_DOWN;
  329. // netapi32!DsGetDcName is delay loaded, so wrap
  330. __try
  331. {
  332. // Get the GC location
  333. hr = DsGetDcName(
  334. NULL, // Delayload wrapped
  335. NULL,
  336. NULL,
  337. NULL,
  338. dwGetDCFlags,
  339. &pDomainInfo);
  340. }
  341. __except(hr = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER)
  342. {
  343. }
  344. if (S_OK != hr)
  345. {
  346. hr = HRESULT_FROM_WIN32(hr);
  347. if (fForceRediscovery)
  348. {
  349. goto error;
  350. }
  351. fForceRediscovery = TRUE;
  352. continue;
  353. }
  354. if (NULL == pDomainInfo ||
  355. (fGC && 0 == (DS_GC_FLAG & pDomainInfo->Flags)) ||
  356. 0 == (DS_DNS_CONTROLLER_FLAG & pDomainInfo->Flags) ||
  357. NULL == pDomainInfo->DomainControllerName)
  358. {
  359. if (!fForceRediscovery)
  360. {
  361. fForceRediscovery = TRUE;
  362. continue;
  363. }
  364. hr = HRESULT_FROM_WIN32(ERROR_CANT_ACCESS_DOMAIN_INFO);
  365. goto error;
  366. }
  367. pwszDomainControllerName = pDomainInfo->DomainControllerName;
  368. // skip past forward slashes (why are they there?)
  369. while (L'\\' == *pwszDomainControllerName)
  370. {
  371. pwszDomainControllerName++;
  372. }
  373. // bind to ds
  374. pld = ldap_init(
  375. const_cast<WCHAR *>(pwszDomainControllerName),
  376. fGC? LDAP_GC_PORT : LDAP_PORT);
  377. if (NULL == pld)
  378. {
  379. ldaperr = LdapGetLastError();
  380. }
  381. else
  382. {
  383. // do this because we're explicitly setting DC name
  384. ldaperr = ldap_set_option(pld, LDAP_OPT_AREC_EXCLUSIVE, LDAP_OPT_ON);
  385. ldaperr = ldap_bind_s(pld, NULL, NULL, LDAP_AUTH_NEGOTIATE);
  386. }
  387. hr = myHError(LdapMapErrorToWin32(ldaperr));
  388. if (fForceRediscovery)
  389. {
  390. break;
  391. }
  392. fForceRediscovery = TRUE;
  393. } while (LDAP_SERVER_DOWN == ldaperr);
  394. // everything's cool, party down
  395. if (S_OK == hr)
  396. {
  397. if (NULL != ppszForestDNSName)
  398. {
  399. hr = myDupString(
  400. pDomainInfo->DomainControllerName,
  401. ppszForestDNSName);
  402. if(S_OK != hr)
  403. goto error;
  404. }
  405. *ppldap = pld;
  406. pld = NULL;
  407. }
  408. error:
  409. if (NULL != pld)
  410. {
  411. ldap_unbind(pld);
  412. }
  413. // we know netapi32 was already loaded safely (that's where we got
  414. // pDomainInfo), so no need to wrap
  415. if (NULL != pDomainInfo)
  416. {
  417. NetApiBufferFree(pDomainInfo); // Delayload wrapped
  418. }
  419. return(hr);
  420. }
  421. HRESULT
  422. myRobustLdapBind(
  423. OUT LDAP ** ppldap,
  424. IN BOOL fGC)
  425. {
  426. return(myRobustLdapBindEx(ppldap, NULL, fGC));
  427. }
  428. //--------------------------------------------------------------------
  429. static HRESULT GetRootDomEntitySid(SID ** ppSid, DWORD dwEntityRid)
  430. {
  431. HRESULT hr = S_OK;
  432. NET_API_STATUS nasError = 0;
  433. unsigned int nSubAuthorities = 0;
  434. unsigned int nSubAuthIndex = 0;
  435. // must be cleaned up
  436. SID * psidRootDomEntity=NULL;
  437. USER_MODALS_INFO_2 * pumi2=NULL;
  438. DOMAIN_CONTROLLER_INFOW * pdci=NULL;
  439. DOMAIN_CONTROLLER_INFOW * pdciForest=NULL;
  440. // initialize out params
  441. *ppSid=NULL;
  442. // get the forest name
  443. nasError=DsGetDcNameW(NULL, NULL, NULL, NULL, 0, &pdciForest);
  444. if (NERR_Success!=nasError) {
  445. hr=HRESULT_FROM_WIN32(nasError);
  446. goto error;
  447. }
  448. // get the top level DC name
  449. nasError=DsGetDcNameW(NULL, pdciForest->DnsForestName, NULL, NULL, 0, &pdci);
  450. if (NERR_Success!=nasError) {
  451. hr=HRESULT_FROM_WIN32(nasError);
  452. goto error;
  453. }
  454. // get the domain Sid on the top level DC.
  455. nasError=NetUserModalsGet(pdci->DomainControllerName, 2, (LPBYTE *)&pumi2);
  456. if(NERR_Success!=nasError) {
  457. hr=HRESULT_FROM_WIN32(nasError);
  458. goto error;
  459. }
  460. nSubAuthorities=*GetSidSubAuthorityCount(pumi2->usrmod2_domain_id);
  461. // allocate storage for new Sid. account domain Sid + account Rid
  462. psidRootDomEntity=(SID *)LocalAlloc(LPTR, GetSidLengthRequired((UCHAR)(nSubAuthorities+1)));
  463. if(NULL == psidRootDomEntity)
  464. {
  465. hr=E_OUTOFMEMORY;
  466. goto error;
  467. }
  468. // copy the first few peices into the SID
  469. if (!InitializeSid(psidRootDomEntity,
  470. GetSidIdentifierAuthority(pumi2->usrmod2_domain_id),
  471. (BYTE)(nSubAuthorities+1)))
  472. {
  473. hr=HRESULT_FROM_WIN32(GetLastError());
  474. goto error;
  475. }
  476. // copy existing subauthorities from account domain Sid into new Sid
  477. for (nSubAuthIndex=0; nSubAuthIndex < nSubAuthorities ; nSubAuthIndex++) {
  478. *GetSidSubAuthority(psidRootDomEntity, nSubAuthIndex)=
  479. *GetSidSubAuthority(pumi2->usrmod2_domain_id, nSubAuthIndex);
  480. }
  481. // append Rid to new Sid
  482. *GetSidSubAuthority(psidRootDomEntity, nSubAuthorities)=dwEntityRid;
  483. *ppSid=psidRootDomEntity;
  484. psidRootDomEntity=NULL;
  485. hr=S_OK;
  486. error:
  487. if (NULL!=psidRootDomEntity) {
  488. FreeSid(psidRootDomEntity);
  489. }
  490. if (NULL!=pdci) {
  491. NetApiBufferFree(pdci);
  492. }
  493. if (NULL!=pdci) {
  494. NetApiBufferFree(pdciForest);
  495. }
  496. if (NULL!=pumi2) {
  497. NetApiBufferFree(pumi2);
  498. }
  499. return hr;
  500. }
  501. //--------------------------------------------------------------------
  502. HRESULT GetRootDomAdminSid(SID ** ppSid)
  503. {
  504. return GetRootDomEntitySid(ppSid, DOMAIN_GROUP_RID_ADMINS);
  505. }
  506. //***********************************************************************************
  507. //
  508. //
  509. // Main
  510. //
  511. // This function will install new Windows 2002 certificate template if and onlyif
  512. // the following conditions are TRUE:
  513. //
  514. // 1. Whilster Schema
  515. // 2. New certificate templates have not yet installed
  516. // 3. The caller has privilege to install templates in the directory
  517. //
  518. //
  519. //***********************************************************************************
  520. void InstallWindows2002CertTemplates ()
  521. {
  522. _TRACE (1, L"Entering InstallWindows2002CertTemplates()\n");
  523. AFX_MANAGE_STATE (AfxGetStaticModuleState ());
  524. HRESULT hr=S_OK;
  525. DWORD dwErr=0;
  526. ULONG ldaperr=0;
  527. struct l_timeval timeout;
  528. DWORD dwCount=0;
  529. LPWSTR awszAttr[2];
  530. BOOL fAccessAllowed = FALSE;
  531. DWORD grantAccess=0;
  532. GENERIC_MAPPING AccessMapping;
  533. PRIVILEGE_SET ps;
  534. DWORD dwPSSize = sizeof(ps);
  535. LDAPMessage *Entry = NULL;
  536. CHAR sdBerValue[] = {0x30, 0x03, 0x02, 0x01, DACL_SECURITY_INFORMATION |
  537. OWNER_SECURITY_INFORMATION |
  538. GROUP_SECURITY_INFORMATION };
  539. LDAPControl se_info_control =
  540. {
  541. LDAP_SERVER_SD_FLAGS_OID_W,
  542. {
  543. 5, sdBerValue
  544. },
  545. TRUE
  546. };
  547. LDAPControl permissive_modify_control =
  548. {
  549. LDAP_SERVER_PERMISSIVE_MODIFY_OID_W,
  550. {
  551. 0, NULL
  552. },
  553. FALSE
  554. };
  555. PLDAPControl server_controls[3] =
  556. {
  557. &se_info_control,
  558. &permissive_modify_control,
  559. NULL
  560. };
  561. HCERTTYPE hCertType=NULL;
  562. LDAP *pld = NULL;
  563. CString szConfig;
  564. CString szDN;
  565. LDAPMessage *SearchResult = NULL;
  566. LDAPMessage *SDResult = NULL;
  567. struct berval **apSD =NULL;
  568. PSECURITY_DESCRIPTOR pSD=NULL;
  569. HANDLE hClientToken=NULL;
  570. CString text;
  571. CString caption;
  572. SID * psidRootDomAdmins=NULL;
  573. BOOL bIsRootDomAdmin=FALSE;
  574. CThemeContextActivator activator;
  575. //*************************************************************
  576. //
  577. // check the schema version
  578. //
  579. _TRACE (0, L"Checking the schema version...\n");
  580. //retrieve the ldap handle and the config string
  581. if(S_OK != myDoesDSExist(TRUE))
  582. {
  583. _TRACE (0, L"No DS exists.\n");
  584. goto error;
  585. }
  586. if(S_OK != (hr = myRobustLdapBind(&pld, FALSE)))
  587. {
  588. _TRACE (0, L"Error: Failed to bind to the DS.\n");
  589. goto error;
  590. }
  591. dwErr = CAGetAuthoritativeDomainDn(pld, NULL, &szConfig);
  592. if(ERROR_SUCCESS != dwErr)
  593. {
  594. _TRACE (0, L"Error: Failed to get the domain name.\n");
  595. hr = HRESULT_FROM_WIN32(dwErr);
  596. goto error;
  597. }
  598. szDN = SCHEMA_CONTAINER_NAME;
  599. szDN += szConfig;
  600. timeout.tv_sec = 300;
  601. timeout.tv_usec = 0;
  602. awszAttr[0]=L"cn";
  603. awszAttr[1]=NULL;
  604. ldaperr = ldap_search_stW(
  605. pld,
  606. const_cast <PWCHAR>((PCWSTR) szDN),
  607. LDAP_SCOPE_ONELEVEL,
  608. L"(cn=ms-PKI-Enrollment-Flag)",
  609. awszAttr,
  610. 0,
  611. &timeout,
  612. &SearchResult);
  613. if ( LDAP_SUCCESS != ldaperr )
  614. {
  615. _TRACE (0, L"We have W2K Schema. Exit\n");
  616. g_bSchemaIsW2K = true;
  617. hr = S_OK;
  618. goto error;
  619. }
  620. dwCount = ldap_count_entries(pld, SearchResult);
  621. if(0 == dwCount)
  622. {
  623. _TRACE (0, L"We have W2K Schema. Exit\n");
  624. hr=S_OK;
  625. goto error;
  626. }
  627. //*************************************************************
  628. //
  629. // check if keyRecoveryAgent certificate is present and
  630. // and update to date
  631. //
  632. _TRACE (0, L"Checking if keyRecoveryAgent certificate is present...\n");
  633. hr=CAFindCertTypeByName(
  634. wszCERTTYPE_DS_EMAIL_REPLICATION,
  635. NULL,
  636. CT_ENUM_MACHINE_TYPES | CT_FLAG_NO_CACHE_LOOKUP,
  637. &hCertType);
  638. if((S_OK == hr) && (NULL!=hCertType))
  639. {
  640. _TRACE (0, L"Key Recovery Agent certificate template already exists.\n");
  641. //check if the template is update to date
  642. if(CAIsCertTypeCurrent(0, wszCERTTYPE_DS_EMAIL_REPLICATION))
  643. {
  644. _TRACE (0, L"Key Recovery Agent certificate template is current. Exit\n");
  645. goto error;
  646. }
  647. }
  648. //*************************************************************
  649. //
  650. // check the write access
  651. //
  652. //
  653. _TRACE (0, L"Checking the write access...\n");
  654. if(NULL==(hClientToken=GetClientIdentity()))
  655. {
  656. TRACE (0, L"Can not retrieve client identity.\n");
  657. hr = myHError(GetLastError());
  658. goto error;
  659. }
  660. //get the SD of the certificate template container
  661. _TRACE (0, L"Getting the SD of the certificate template container...\n");
  662. szDN = TEMPLATE_CONTAINER_NAME;
  663. szDN += szConfig;
  664. awszAttr[0]=CERTTYPE_SECURITY_DESCRIPTOR_NAME;
  665. awszAttr[1]=NULL;
  666. ldaperr = ldap_search_ext_sW(
  667. pld,
  668. const_cast <PWCHAR>((PCWSTR) szDN),
  669. LDAP_SCOPE_BASE,
  670. L"(objectclass=*)",
  671. awszAttr,
  672. 0,
  673. (PLDAPControl *)&server_controls,
  674. NULL,
  675. &timeout,
  676. 10,
  677. &SDResult);
  678. if(LDAP_SUCCESS != ldaperr)
  679. {
  680. _TRACE (0, L"Fail to locate the template container.\n");
  681. hr = myHError(LdapMapErrorToWin32(ldaperr));
  682. goto error;
  683. }
  684. if(NULL == (Entry = ldap_first_entry(pld, SDResult)))
  685. {
  686. _TRACE (0, L"Can not find first entry for template container.\n");
  687. hr = E_UNEXPECTED;
  688. goto error;
  689. }
  690. apSD = ldap_get_values_len(pld, Entry, CERTTYPE_SECURITY_DESCRIPTOR_NAME);
  691. if(apSD == NULL)
  692. {
  693. _TRACE (0, L"Can not retrieve security descriptor.\n");
  694. hr = E_FAIL;
  695. goto error;
  696. }
  697. pSD = LocalAlloc(LMEM_FIXED, (*apSD)->bv_len);
  698. if(pSD == NULL)
  699. {
  700. _TRACE (0, L"Error: No more memory.\n");
  701. hr = E_OUTOFMEMORY;
  702. goto error;
  703. }
  704. CopyMemory(pSD, (*apSD)->bv_val, (*apSD)->bv_len);
  705. //check the write access
  706. _TRACE (0, L"Checking the write access...\n");
  707. if(!AccessCheckByType(
  708. pSD, // security descriptor
  709. NULL, // SID of object being checked
  710. hClientToken, // handle to client access token
  711. ACTRL_DS_CREATE_CHILD |
  712. ACTRL_DS_LIST, // requested access rights
  713. NULL, // array of object types
  714. 0, // number of object type elements
  715. &AccessMapping, // map generic to specific rights
  716. &ps, // receives privileges used
  717. &dwPSSize, // size of privilege-set buffer
  718. &grantAccess, // retrieves mask of granted rights
  719. &fAccessAllowed)) // retrieves results of access check);
  720. {
  721. _TRACE (0, L"Error: Fail to check the write access.\n");
  722. hr = myHError(GetLastError());
  723. goto error;
  724. }
  725. if(!fAccessAllowed)
  726. {
  727. _TRACE (0, L"No previlege to create certificate template. Exit\n");
  728. hr = S_OK;
  729. goto error;
  730. }
  731. //*************************************************************
  732. //
  733. // check the root domain admin rights
  734. //
  735. //
  736. hr=GetRootDomAdminSid(&psidRootDomAdmins);
  737. if( FAILED (hr) )
  738. {
  739. _TRACE (0, L"Error: GetRootDomAdminSid.\n");
  740. goto error;
  741. }
  742. // check for membership
  743. if (!CheckTokenMembership(NULL, psidRootDomAdmins, &bIsRootDomAdmin))
  744. {
  745. hr=HRESULT_FROM_WIN32(GetLastError());
  746. _TRACE (0, L"Error: CheckTokenMembership.\n");
  747. goto error;
  748. }
  749. if(FALSE == bIsRootDomAdmin)
  750. {
  751. VERIFY (caption.LoadString (IDS_CERTTMPL));
  752. VERIFY (text.LoadString (IDS_MUST_HAVE_DOMAIN_ADMIN_RIGHTS_TO_INSTALL_CERT_TEMPLATES));
  753. MessageBoxW (NULL,
  754. text,
  755. caption,
  756. MB_ICONWARNING | MB_OK);
  757. _TRACE (0, L"No domain admin rights to create certificate template. Exit\n");
  758. hr = S_OK;
  759. goto error;
  760. }
  761. //*************************************************************
  762. //
  763. // everything looks good. Install the certificate templates
  764. //
  765. //
  766. _TRACE (0, L"Everything looks good. Installing the certificate templates...\n");
  767. VERIFY (caption.LoadString (IDS_CERTTMPL));
  768. VERIFY (text.LoadString (IDS_INSTALL_WINDOWS2002_CERT_TEMPLATES));
  769. if ( IDYES == MessageBoxW (
  770. NULL,
  771. text,
  772. caption,
  773. MB_YESNO) )
  774. {
  775. hr=CAInstallDefaultCertType(0);
  776. if(hr != S_OK)
  777. {
  778. VERIFY (caption.LoadString (IDS_CERTTMPL));
  779. text.FormatMessage (IDS_INSTALL_FAILURE_WINDOWS2002_CERT_TEMPLATES, GetSystemMessage (hr));
  780. MessageBoxW(
  781. NULL,
  782. text,
  783. caption,
  784. MB_ICONWARNING | MB_OK);
  785. }
  786. else
  787. {
  788. VERIFY (caption.LoadString (IDS_CERTTMPL));
  789. VERIFY (text.LoadString (IDS_INSTALL_SUCCESS_WINDOWS2002_CERT_TEMPLATES));
  790. MessageBoxW(
  791. NULL,
  792. text,
  793. caption,
  794. MB_OK);
  795. }
  796. }
  797. else
  798. {
  799. hr=S_OK;
  800. }
  801. error:
  802. if (psidRootDomAdmins)
  803. FreeSid(psidRootDomAdmins);
  804. if(hClientToken)
  805. CloseHandle(hClientToken);
  806. if(pSD)
  807. LocalFree(pSD);
  808. if(apSD != NULL)
  809. ldap_value_free_len(apSD);
  810. if(SDResult)
  811. ldap_msgfree(SDResult);
  812. if(SearchResult)
  813. ldap_msgfree(SearchResult);
  814. if(hCertType)
  815. CACloseCertType(hCertType);
  816. if (pld)
  817. ldap_unbind(pld);
  818. _TRACE (1, L"Entering InstallWindows2002CertTemplates()\n");
  819. }