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.

720 lines
16 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: setup.cpp
  7. //
  8. // Contents:
  9. //
  10. //---------------------------------------------------------------------------
  11. #include "pch.cpp"
  12. #pragma hdrstop
  13. #include <assert.h>
  14. #include <accctrl.h>
  15. #include <ntldap.h>
  16. #include "certca.h"
  17. #include "cainfop.h"
  18. #include "csldap.h"
  19. #include "dssetup.h"
  20. #define __dwFILE__ __dwFILE_OCMSETUP_DSSETUP_CPP__
  21. typedef HRESULT (* LPFNDLL_INSTALL)(BOOL bInstall, LPCWSTR pszCmdLine);
  22. BOOL
  23. IsCAExistInDS(
  24. IN WCHAR const *pwszSanitizedName)
  25. {
  26. BOOL exist = FALSE;
  27. HRESULT hr;
  28. HCAINFO hCAInfo = NULL;
  29. WCHAR *pwszDSName = NULL;
  30. hr = mySanitizedNameToDSName(pwszSanitizedName, &pwszDSName);
  31. _JumpIfError(hr, error, "mySanitizedNameToDSName");
  32. hr = CAFindByName(
  33. pwszDSName,
  34. NULL,
  35. CA_FIND_INCLUDE_UNTRUSTED | CA_FIND_INCLUDE_NON_TEMPLATE_CA,
  36. &hCAInfo);
  37. _JumpIfErrorStr(hr, error, "IsCAExistInDS:CAFindByName", pwszDSName);
  38. if (NULL == hCAInfo)
  39. {
  40. hr = E_INVALIDARG;
  41. _JumpError(hr, error, "invalid CA in DS");
  42. }
  43. exist = TRUE;
  44. error:
  45. if (NULL != pwszDSName)
  46. {
  47. LocalFree(pwszDSName);
  48. }
  49. if (NULL != hCAInfo)
  50. {
  51. CACloseCA(hCAInfo);
  52. }
  53. return exist;
  54. }
  55. BOOL
  56. IsDSAvailable(VOID)
  57. {
  58. // fail out quickly if DS not present on domain
  59. if (S_OK != myDoesDSExist(FALSE))
  60. return FALSE;
  61. BOOL available = FALSE;
  62. LDAP *pldap = NULL;
  63. ULONG ldaperr;
  64. HRESULT hr;
  65. HMODULE hMod = NULL;
  66. hMod = LoadLibrary(L"wldap32.dll");
  67. if (NULL == hMod)
  68. {
  69. hr = myHLastError();
  70. _JumpErrorStr(hr, error, "LoadLibrary", L"wldap32.dll");
  71. }
  72. // bind to ds
  73. hr = myRobustLdapBind(&pldap, FALSE);
  74. _JumpIfError(hr, error, "myRobustLdapBind");
  75. available = TRUE;
  76. error:
  77. if (NULL != pldap)
  78. {
  79. ldap_unbind(pldap);
  80. }
  81. if (NULL != hMod)
  82. {
  83. FreeLibrary(hMod);
  84. }
  85. return available;
  86. }
  87. HRESULT
  88. RemoveCAInDS(
  89. IN WCHAR const *pwszSanitizedName)
  90. {
  91. HRESULT hr;
  92. HCAINFO hCAInfo = NULL;
  93. WCHAR *pwszDSName = NULL;
  94. hr = mySanitizedNameToDSName(pwszSanitizedName, &pwszDSName);
  95. _JumpIfError(hr, error, "mySanitizedNameToDSName");
  96. hr = CAFindByName(
  97. pwszDSName,
  98. NULL,
  99. CA_FIND_INCLUDE_UNTRUSTED | CA_FIND_INCLUDE_NON_TEMPLATE_CA,
  100. &hCAInfo);
  101. _JumpIfErrorStr(hr, error, "RemoveCAInDS:CAFindByName", pwszDSName);
  102. if (NULL == hCAInfo)
  103. {
  104. hr = E_INVALIDARG;
  105. _JumpError(hr, error, "invalid CA in DS");
  106. }
  107. hr = CADeleteCA(hCAInfo);
  108. _JumpIfError(hr, error, "CADeleteCA");
  109. hr = RemoveCAMachineFromCertPublishers();
  110. _JumpIfError(hr, error, "RemoveCAInDS");
  111. error:
  112. if (NULL != pwszDSName)
  113. {
  114. LocalFree(pwszDSName);
  115. }
  116. if (NULL != hCAInfo)
  117. {
  118. CACloseCA(hCAInfo);
  119. }
  120. return hr;
  121. }
  122. DWORD
  123. GetAuthoritativeDomainDn(
  124. IN LDAP* LdapHandle,
  125. OUT BSTR *DomainDn,
  126. OUT BSTR *ConfigDn
  127. )
  128. /*++
  129. Routine Description:
  130. This routine simply queries the operational attributes for the
  131. domaindn and configdn.
  132. The strings returned by this routine must be freed by the caller
  133. using RtlFreeHeap() using the process heap.
  134. Parameters:
  135. LdapHandle : a valid handle to an ldap session
  136. DomainDn : a pointer to a string to be allocated in this routine
  137. ConfigDn : a pointer to a string to be allocated in this routine
  138. Return Values:
  139. An error from the win32 error space.
  140. ERROR_SUCCESS and
  141. Other operation errors.
  142. --*/
  143. {
  144. DWORD WinError = ERROR_SUCCESS;
  145. ULONG LdapError;
  146. LDAPMessage *SearchResult = NULL;
  147. LDAPMessage *Entry = NULL;
  148. WCHAR *Attr = NULL;
  149. BerElement *BerElement;
  150. WCHAR **Values = NULL;
  151. WCHAR *AttrArray[3];
  152. WCHAR *DefaultNamingContext = L"defaultNamingContext";
  153. WCHAR *ConfigurationNamingContext = L"configurationNamingContext";
  154. WCHAR *ObjectClassFilter = L"objectClass=*";
  155. //
  156. // These must be present
  157. //
  158. //
  159. // Set the out parameters to null
  160. //
  161. if(ConfigDn)
  162. {
  163. *ConfigDn = NULL;
  164. }
  165. if(DomainDn)
  166. {
  167. *DomainDn = NULL;
  168. }
  169. //
  170. // Query for the ldap server oerational attributes to obtain the default
  171. // naming context.
  172. //
  173. AttrArray[0] = DefaultNamingContext;
  174. AttrArray[1] = ConfigurationNamingContext;
  175. AttrArray[2] = NULL; // this is the sentinel
  176. LdapError = ldap_search_sW(LdapHandle,
  177. NULL,
  178. LDAP_SCOPE_BASE,
  179. ObjectClassFilter,
  180. AttrArray,
  181. FALSE,
  182. &SearchResult);
  183. WinError = myHLdapError(LdapHandle, LdapError, NULL);
  184. if (ERROR_SUCCESS == WinError) {
  185. Entry = ldap_first_entry(LdapHandle, SearchResult);
  186. if (Entry) {
  187. Attr = ldap_first_attributeW(LdapHandle, Entry, &BerElement);
  188. while (Attr) {
  189. if (!_wcsicmp(Attr, DefaultNamingContext)) {
  190. if(DomainDn)
  191. {
  192. Values = ldap_get_values(LdapHandle, Entry, Attr);
  193. if (Values && Values[0]) {
  194. (*DomainDn) = SysAllocString(Values[0]);
  195. _JumpIfOutOfMemory(WinError, error, *DomainDn);
  196. }
  197. ldap_value_free(Values);
  198. }
  199. } else if (!_wcsicmp(Attr, ConfigurationNamingContext)) {
  200. if(ConfigDn)
  201. {
  202. Values = ldap_get_valuesW(LdapHandle, Entry, Attr);
  203. if (Values && Values[0]) {
  204. (*ConfigDn) = SysAllocString(Values[0]);
  205. _JumpIfOutOfMemory(WinError, error, *ConfigDn);
  206. }
  207. ldap_value_free(Values);
  208. }
  209. }
  210. Attr = ldap_next_attribute(LdapHandle, Entry, BerElement);
  211. }
  212. }
  213. if ( (DomainDn &&(!(*DomainDn))) || (ConfigDn && (!(*ConfigDn)))) {
  214. //
  215. // We could get the default domain - bail out
  216. //
  217. WinError = ERROR_CANT_ACCESS_DOMAIN_INFO;
  218. }
  219. }
  220. error:
  221. return WinError;
  222. }
  223. HRESULT CreateCertDSHierarchy(VOID)
  224. {
  225. HRESULT hr = S_OK;
  226. ULONG ldaperr;
  227. LDAP *pld = NULL;
  228. LDAPMod objectClass;
  229. DWORD err;
  230. WCHAR *objectClassVals[3];
  231. LDAPMod *mods[2];
  232. BSTR bstrConfigDN = NULL;
  233. WCHAR * awszLocations[] = {
  234. L"CN=Public Key Services,CN=Services,",
  235. L"CN=Enrollment Services,CN=Public Key Services,CN=Services,",
  236. NULL,
  237. };
  238. WCHAR ** pwszCurLocation;
  239. DWORD cbBuffer;
  240. BSTR bstrBuffer = NULL;
  241. // bind to ds
  242. hr = myRobustLdapBind(&pld, FALSE);
  243. if(hr != S_OK)
  244. {
  245. goto error;
  246. }
  247. err = GetAuthoritativeDomainDn(pld, NULL, &bstrConfigDN);
  248. if(err)
  249. {
  250. hr = HRESULT_FROM_WIN32(err);
  251. goto error;
  252. }
  253. pwszCurLocation = awszLocations;
  254. // Build the Public Key Services container
  255. mods[0] = &objectClass;
  256. mods[1] = NULL;
  257. objectClass.mod_op = 0;
  258. objectClass.mod_type = TEXT("objectclass");
  259. objectClass.mod_values = objectClassVals;
  260. objectClassVals[0] = TEXT("top");
  261. objectClassVals[1] = TEXT("container");
  262. objectClassVals[2] = NULL;
  263. while(*pwszCurLocation)
  264. {
  265. cbBuffer = wcslen(*pwszCurLocation) + wcslen(bstrConfigDN) + 1;
  266. // Build a string containing the CA Location
  267. bstrBuffer = SysAllocStringLen(NULL, cbBuffer);
  268. if(bstrBuffer == NULL)
  269. {
  270. hr = E_OUTOFMEMORY;
  271. goto error;
  272. }
  273. wcscpy(bstrBuffer, *pwszCurLocation);
  274. wcscat(bstrBuffer, bstrConfigDN);
  275. ldaperr = ldap_add_s(pld, bstrBuffer, mods);
  276. SysFreeString(bstrBuffer);
  277. if(ldaperr != LDAP_SUCCESS && ldaperr != LDAP_ALREADY_EXISTS)
  278. {
  279. hr = myHLdapError(pld, ldaperr, NULL);
  280. goto error;
  281. }
  282. pwszCurLocation++;
  283. }
  284. error:
  285. if(bstrConfigDN)
  286. {
  287. SysFreeString(bstrConfigDN);
  288. }
  289. if(pld != NULL)
  290. {
  291. ldap_unbind(pld);
  292. pld = NULL;
  293. }
  294. return hr;
  295. }
  296. //
  297. HRESULT InitializeCertificateTemplates(VOID)
  298. {
  299. HRESULT hr = S_OK;
  300. DWORD err = ERROR_SUCCESS;
  301. HINSTANCE hCertCli = NULL;
  302. LPFNDLL_INSTALL lpfnDllInstall = NULL;
  303. hCertCli = LoadLibrary(L"certcli.dll");
  304. if(hCertCli == NULL)
  305. {
  306. hr = myHLastError();
  307. goto error;
  308. }
  309. lpfnDllInstall = (LPFNDLL_INSTALL)GetProcAddress(hCertCli, "DllInstall");
  310. if(lpfnDllInstall == NULL)
  311. {
  312. hr = myHLastError();
  313. goto error;
  314. }
  315. err = lpfnDllInstall(TRUE, L"i");
  316. hr = HRESULT_FROM_WIN32(err);
  317. error:
  318. return hr;
  319. }
  320. HRESULT
  321. DNStoDirectoryName(IN LPWSTR wszDNSDomain,
  322. OUT LPWSTR *pwszDN)
  323. {
  324. HRESULT hr = S_OK;
  325. DWORD cDN;
  326. LPWSTR wszResult = NULL;
  327. LPWSTR wszCurrent, wszNext;
  328. if (wszDNSDomain == NULL)
  329. {
  330. hr = E_POINTER;
  331. _JumpError(hr, error, "DNStoDirectoryName");
  332. }
  333. if(0==wcsncmp(wszDNSDomain, L"\\\\", 2))
  334. {
  335. // this is a DC DNS name, skip the machine name
  336. wszDNSDomain = wcschr(wszDNSDomain, L'.');
  337. // no dot found?
  338. if(!wszDNSDomain)
  339. {
  340. hr =E_UNEXPECTED;
  341. _JumpError(hr, error, "DC DNS doesn't contain at least one dot");
  342. }
  343. // jump over the dot
  344. wszDNSDomain++;
  345. // no domain name following the DC name?
  346. if(L'\0'==*wszDNSDomain)
  347. {
  348. hr = E_UNEXPECTED;
  349. _JumpError(hr, error, "DC DNS name doesn't contain a domain name");
  350. }
  351. }
  352. // Estimate the size of the output string
  353. cDN = wcslen(wszDNSDomain) + 3;
  354. wszCurrent=wszDNSDomain;
  355. while(wszCurrent = wcschr(wszCurrent, L'.'))
  356. {
  357. cDN += 4; // sizeof ,DC=
  358. wszCurrent++;
  359. }
  360. cDN += 1; // NULL terminate
  361. wszResult = (LPWSTR)LocalAlloc(LMEM_FIXED, cDN * sizeof(WCHAR));
  362. if(wszResult == NULL)
  363. {
  364. hr = E_OUTOFMEMORY;
  365. _JumpError(hr, error, "LocalAlloc");
  366. }
  367. wszCurrent=wszDNSDomain;
  368. // prepend the first DC=
  369. wszNext = wszResult + 3;
  370. wcscpy(wszResult, L"DC=");
  371. while(*wszCurrent)
  372. {
  373. if(*wszCurrent != '.')
  374. {
  375. *wszNext++ = *wszCurrent++;
  376. }
  377. else
  378. {
  379. wszCurrent++;
  380. if(*wszCurrent)
  381. {
  382. wcscpy(wszNext, L",DC=");
  383. wszNext += 4;
  384. }
  385. }
  386. }
  387. *wszNext = 0;
  388. if(pwszDN)
  389. {
  390. *pwszDN = wszResult;
  391. wszResult = NULL;
  392. }
  393. error:
  394. if(wszResult)
  395. {
  396. LocalFree(wszResult);
  397. }
  398. return hr;
  399. }
  400. HRESULT CurrentUserCanInstallCA(bool& fCanInstall)
  401. {
  402. HRESULT hr;
  403. HANDLE hThread = NULL; // no free
  404. HANDLE hAccessToken = NULL, hDupToken = NULL;
  405. LDAP *pld = NULL;
  406. BSTR bstrConfigDN = NULL;
  407. LPWSTR pwszPKIContainerFilter =
  408. L"(&(objectClass=container)(CN=Public Key Services))";
  409. LPWSTR pwszSDAttr = L"nTSecurityDescriptor";
  410. LPWSTR pwszAttrArray[3];
  411. LDAPMessage* pResult = NULL;
  412. LDAPMessage *pEntry;
  413. struct berval **bervalSD = NULL;
  414. PSECURITY_DESCRIPTOR pSD; // no free
  415. GENERIC_MAPPING mapping;
  416. PRIVILEGE_SET PrivilegeSet;
  417. DWORD cPrivilegeSet = sizeof(PrivilegeSet);
  418. DWORD dwGrantedAccess;
  419. BOOL fAccess = FALSE;
  420. struct l_timeval timeout;
  421. CHAR sdBerValue[] = {0x30, 0x03, 0x02, 0x01,
  422. DACL_SECURITY_INFORMATION |
  423. OWNER_SECURITY_INFORMATION |
  424. GROUP_SECURITY_INFORMATION};
  425. LDAPControl se_info_control =
  426. {
  427. LDAP_SERVER_SD_FLAGS_OID_W,
  428. {
  429. 5, sdBerValue
  430. },
  431. TRUE
  432. };
  433. PLDAPControl server_controls[2] =
  434. {
  435. &se_info_control,
  436. NULL
  437. };
  438. pwszAttrArray[0] = pwszSDAttr;
  439. pwszAttrArray[1] = L"name";
  440. pwszAttrArray[2] = NULL;
  441. ZeroMemory(&mapping, sizeof(mapping));
  442. fCanInstall = false;
  443. // Get the access token for current thread
  444. hThread = GetCurrentThread();
  445. if (NULL == hThread)
  446. {
  447. hr = myHLastError();
  448. _JumpIfError(hr, error, "GetCurrentThread");
  449. }
  450. if (!OpenThreadToken(
  451. hThread,
  452. TOKEN_QUERY | TOKEN_DUPLICATE,
  453. FALSE,
  454. &hAccessToken))
  455. {
  456. hr = myHLastError();
  457. if(hr==HRESULT_FROM_WIN32(ERROR_NO_TOKEN))
  458. {
  459. HANDLE hProcess = GetCurrentProcess();
  460. if (NULL == hProcess)
  461. {
  462. hr = myHLastError();
  463. _JumpError(hr, error, "GetCurrentProcess");
  464. }
  465. if (!OpenProcessToken(hProcess,
  466. TOKEN_DUPLICATE,
  467. &hAccessToken))
  468. {
  469. hr = myHLastError();
  470. _JumpError(hr, error, "OpenProcessToken");
  471. }
  472. if (!DuplicateToken(hAccessToken, SecurityIdentification, &hDupToken))
  473. {
  474. hr = myHLastError();
  475. _JumpError(hr, error, "DuplicateToken");
  476. }
  477. }
  478. else
  479. {
  480. _JumpError(hr, error, "OpenThreadToken");
  481. }
  482. }
  483. hr = myRobustLdapBind(
  484. &pld,
  485. TRUE);
  486. _JumpIfError(hr, error, "myRobustLdapBind");
  487. hr = myGetAuthoritativeDomainDn(
  488. pld,
  489. NULL,
  490. &bstrConfigDN);
  491. _JumpIfError(hr, error, "myGetAuthoritativeDomainDn");
  492. timeout.tv_sec = csecLDAPTIMEOUT;
  493. timeout.tv_usec = 0;
  494. hr = ldap_search_ext_s(
  495. pld,
  496. bstrConfigDN,
  497. LDAP_SCOPE_SUBTREE,
  498. pwszPKIContainerFilter,
  499. pwszAttrArray,
  500. 0,
  501. (PLDAPControl *)&server_controls,
  502. NULL,
  503. &timeout,
  504. 0,
  505. &pResult);
  506. hr = myHLdapError(pld, hr, NULL);
  507. _JumpIfError(hr, error, "ldap_search_sW");
  508. pEntry = ldap_first_entry(pld, pResult);
  509. if (NULL == pEntry)
  510. {
  511. hr = myHLdapLastError(pld, NULL);
  512. _JumpError(hr, error, "ldap_first_entry");
  513. }
  514. bervalSD = ldap_get_values_len(pld, pEntry, pwszSDAttr);
  515. if(bervalSD && (*bervalSD)->bv_val)
  516. {
  517. pSD = (*bervalSD)->bv_val;
  518. if(IsValidSecurityDescriptor(pSD))
  519. {
  520. if(!AccessCheck(
  521. pSD,
  522. hDupToken,
  523. ACTRL_DS_WRITE_PROP |
  524. WRITE_DAC |
  525. ACTRL_DS_CREATE_CHILD,
  526. &mapping,
  527. &PrivilegeSet,
  528. &cPrivilegeSet,
  529. &dwGrantedAccess,
  530. &fAccess))
  531. {
  532. hr = myHLastError();
  533. if(E_ACCESSDENIED==hr)
  534. {
  535. hr = S_OK;
  536. }
  537. _JumpError(hr, error, "AccessCheck");
  538. }
  539. }
  540. else
  541. {
  542. DBGPRINT((DBG_SS_CERTOCM, "Invalid security descriptor for PKI container" ));
  543. }
  544. }
  545. else
  546. {
  547. DBGPRINT((DBG_SS_CERTOCM, "No security descriptor for PKI container" ));
  548. }
  549. if(fAccess)
  550. {
  551. fCanInstall = true;
  552. }
  553. error:
  554. if(bervalSD)
  555. {
  556. ldap_value_free_len(bervalSD);
  557. }
  558. if(bstrConfigDN)
  559. {
  560. SysFreeString(bstrConfigDN);
  561. }
  562. if (NULL != pResult)
  563. {
  564. ldap_msgfree(pResult);
  565. }
  566. if (pld)
  567. {
  568. ldap_unbind(pld);
  569. }
  570. if (hAccessToken)
  571. {
  572. CloseHandle(hAccessToken);
  573. }
  574. if (hDupToken)
  575. {
  576. CloseHandle(hDupToken);
  577. }
  578. //we should always return S_OK; since we do not want to abort
  579. //ocmsetup just because we failed to contact the directory
  580. return S_OK;
  581. }