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.

1013 lines
28 KiB

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