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.

1152 lines
26 KiB

  1. //+--------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: cainfop.cpp
  7. //
  8. // Contents:
  9. //
  10. //---------------------------------------------------------------------------
  11. #include "pch.cpp"
  12. #pragma hdrstop
  13. #include <certca.h>
  14. #include <lm.h>
  15. #include <cainfop.h>
  16. #include <cainfoc.h>
  17. #include <winldap.h>
  18. #include <ntlsa.h>
  19. #include <dsgetdc.h>
  20. #include <accctrl.h>
  21. #include "certacl.h"
  22. #include "oidmgr.h"
  23. #include "csldap.h"
  24. #define __dwFILE__ __dwFILE_CERTCLIB_CAINFOP_CPP__
  25. CRITICAL_SECTION g_csDomainSidCache;
  26. extern BOOL g_fInitDone;
  27. //we only keep one copy of the localSystem's sid
  28. PSID g_pLocalSid=NULL;
  29. #define DOMAIN_SID_CACHE_INC 10
  30. typedef struct _DOMAIN_SID_CACHE
  31. {
  32. LPWSTR wszDomain;
  33. PSID pSid;
  34. } DOMAIN_SID_CACHE, *PDOMAIN_SID_CACHE;
  35. PDOMAIN_SID_CACHE g_DomainSidCache = NULL;
  36. DWORD g_cDomainSidCache = 0;
  37. DWORD g_cMaxDomainSidCache = 0;
  38. ULONG g_cDomainCache = 0;
  39. PDS_DOMAIN_TRUSTS g_pDomainCache = NULL;
  40. LPWSTR g_pwszEnterpriseRoot = NULL;
  41. DWORD myGetEnterpriseDnsName(OUT LPWSTR *pwszDomain);
  42. HRESULT
  43. CAGetAuthoritativeDomainDn(
  44. IN LDAP* LdapHandle,
  45. OUT CERTSTR *DomainDn,
  46. OUT CERTSTR *ConfigDn
  47. )
  48. /*++
  49. Routine Description:
  50. This routine simply queries the operational attributes for the
  51. domaindn and configdn.
  52. The strings returned by this routine must be freed by the caller
  53. using RtlFreeHeap() using the process heap.
  54. Parameters:
  55. LdapHandle : a valid handle to an ldap session
  56. DomainDn : a pointer to a string to be allocated in this routine
  57. ConfigDn : a pointer to a string to be allocated in this routine
  58. Return Values:
  59. An error from the win32 error space.
  60. ERROR_SUCCESS and
  61. Other operation errors.
  62. --*/
  63. {
  64. HRESULT hr=E_FAIL;
  65. BSTR bstrDomainDN=NULL;
  66. BSTR bstrConfigDN=NULL;
  67. hr = myGetAuthoritativeDomainDn(LdapHandle, &bstrDomainDN, &bstrConfigDN);
  68. _JumpIfError(hr, error, "myGetAuthoritativeDomainDn");
  69. //convert BSTR to CERTSTR
  70. if(DomainDn)
  71. {
  72. (*DomainDn) = CertAllocString(bstrDomainDN);
  73. if(NULL == (*DomainDn))
  74. {
  75. hr=E_OUTOFMEMORY;
  76. _JumpError(hr, error, "CertAllocString");
  77. }
  78. }
  79. if(ConfigDn)
  80. {
  81. (*ConfigDn) = CertAllocString(bstrConfigDN);
  82. if(NULL == (*ConfigDn))
  83. {
  84. hr=E_OUTOFMEMORY;
  85. if(DomainDn)
  86. {
  87. if(*DomainDn)
  88. {
  89. CertFreeString(*DomainDn);
  90. *DomainDn=NULL;
  91. }
  92. }
  93. _JumpError(hr, error, "CertAllocString");
  94. }
  95. }
  96. hr=S_OK;
  97. error:
  98. if(bstrDomainDN)
  99. SysFreeString(bstrDomainDN);
  100. if(bstrConfigDN)
  101. SysFreeString(bstrConfigDN);
  102. return hr;
  103. }
  104. DWORD
  105. DNStoRFC1779Name(WCHAR *rfcDomain,
  106. ULONG *rfcDomainLength,
  107. LPCWSTR dnsDomain)
  108. /*++
  109. Routine Description:
  110. This routine takes the DNS-style name of a domain controller and
  111. contructs the corresponding RFC1779 style name, using the
  112. domainComponent prefix.
  113. Parameters:
  114. rfcDomain - this is the destination string
  115. rfcDomainLength - this is the length in wchars of rfcDomain
  116. dnsDomain - NULL-terminated dns name.
  117. Return Values:
  118. ERROR_SUCCESS if succesful;
  119. ERROR_INSUFFICIENT_BUFFER if there is not enough space in the dst string -
  120. rfcDomainLength will set to number of characters needed.
  121. --*/
  122. {
  123. DWORD WinError = ERROR_SUCCESS;
  124. WCHAR *NextToken;
  125. ULONG length = 1; // include the null character
  126. WCHAR Buffer[DNS_MAX_NAME_LENGTH+1];
  127. if (!rfcDomainLength || !dnsDomain) {
  128. return ERROR_INVALID_PARAMETER;
  129. }
  130. if (wcslen(dnsDomain) > DNS_MAX_NAME_LENGTH) {
  131. return ERROR_INVALID_PARAMETER;
  132. }
  133. RtlCopyMemory(Buffer, dnsDomain, (wcslen(dnsDomain)+1)*sizeof(WCHAR));
  134. if (rfcDomain && *rfcDomainLength > 0) {
  135. RtlZeroMemory(rfcDomain, *rfcDomainLength*sizeof(WCHAR));
  136. }
  137. //
  138. // Start contructing the string
  139. //
  140. NextToken = wcstok(Buffer, L".");
  141. if ( NextToken )
  142. {
  143. //
  144. // Append the intial DC=
  145. //
  146. length += 3;
  147. if ( length <= *rfcDomainLength && rfcDomain )
  148. {
  149. wcscpy(rfcDomain, L"DC=");
  150. }
  151. }
  152. while ( NextToken )
  153. {
  154. length += wcslen(NextToken);
  155. if (length <= *rfcDomainLength && rfcDomain)
  156. {
  157. wcscat(rfcDomain, NextToken);
  158. }
  159. NextToken = wcstok(NULL, L".");
  160. if ( NextToken )
  161. {
  162. length += 4;
  163. if (length <= *rfcDomainLength && rfcDomain)
  164. {
  165. wcscat(rfcDomain, L",DC=");
  166. }
  167. }
  168. }
  169. if ( length > *rfcDomainLength )
  170. {
  171. WinError = ERROR_INSUFFICIENT_BUFFER;
  172. }
  173. //
  174. // Return how much space was needed
  175. //
  176. *rfcDomainLength = length;
  177. return WinError;
  178. }
  179. VOID
  180. FreeSidCache()
  181. {
  182. if(g_pDomainCache)
  183. {
  184. NetApiBufferFree(g_pDomainCache);
  185. g_pDomainCache = NULL;
  186. }
  187. }
  188. DWORD myUpdateDomainSidCache()
  189. {
  190. if(g_pDomainCache)
  191. {
  192. NetApiBufferFree(g_pDomainCache);
  193. g_pDomainCache = NULL;
  194. }
  195. return DsEnumerateDomainTrusts(
  196. NULL,
  197. DS_DOMAIN_VALID_FLAGS,
  198. &g_pDomainCache,
  199. &g_cDomainCache);
  200. }
  201. // if not found, returns OK with NULL *ppSid
  202. DWORD myFindDomainSidInCache(
  203. IN LPCWSTR pcwszDomainName,
  204. OUT PSID* ppSid)
  205. {
  206. DWORD dwErr = ERROR_SUCCESS;
  207. for(ULONG c=0; c<g_cDomainCache; c++)
  208. {
  209. // if name matches Netbios or DNS name, return sid
  210. if(g_pDomainCache[c].DomainSid) // some entries don't have SID
  211. {
  212. if((g_pDomainCache[c].NetbiosDomainName && // one of the names might be null
  213. 0 == _wcsicmp(pcwszDomainName,
  214. g_pDomainCache[c].NetbiosDomainName)) ||
  215. (g_pDomainCache[c].DnsDomainName &&
  216. 0 == _wcsicmp(pcwszDomainName,
  217. g_pDomainCache[c].DnsDomainName)))
  218. {
  219. *ppSid = (PSID)LocalAlloc(
  220. LMEM_FIXED,
  221. GetLengthSid(g_pDomainCache[c].DomainSid));
  222. if(*ppSid == NULL)
  223. {
  224. dwErr = ERROR_OUTOFMEMORY;
  225. }
  226. else
  227. {
  228. if(!CopySid(
  229. GetLengthSid(g_pDomainCache[c].DomainSid),
  230. *ppSid,
  231. g_pDomainCache[c].DomainSid))
  232. {
  233. LocalFree(*ppSid);
  234. *ppSid=NULL;
  235. dwErr=GetLastError();
  236. }
  237. }
  238. break;
  239. }
  240. }
  241. }
  242. return dwErr;
  243. }
  244. DWORD
  245. myGetSidFromDomain(
  246. IN LPWSTR wszDomain,
  247. OUT PSID *ppDomainSid)
  248. {
  249. DWORD dwErr = ERROR_SUCCESS;
  250. if (!g_fInitDone)
  251. {
  252. return((DWORD) HRESULT_FROM_WIN32(ERROR_DLL_INIT_FAILED));
  253. }
  254. __try
  255. {
  256. EnterCriticalSection(&g_csDomainSidCache);
  257. if(wszDomain == NULL)
  258. {
  259. dwErr = myGetEnterpriseDnsName(&wszDomain);
  260. if(dwErr != ERROR_SUCCESS)
  261. {
  262. _LeaveError(dwErr, "myGetEnterpriseDnsName");
  263. }
  264. }
  265. dwErr = myFindDomainSidInCache(wszDomain, ppDomainSid);
  266. _LeaveIfError(dwErr, "myFindDomainSidInCache");
  267. if(NULL == *ppDomainSid)
  268. {
  269. // not found in cache, update and try again
  270. dwErr = myUpdateDomainSidCache();
  271. _LeaveIfError(dwErr, "myUpdateDomainSidCache");
  272. dwErr = myFindDomainSidInCache(wszDomain, ppDomainSid);
  273. _LeaveIfError(dwErr, "myUpdateDomainSidCache");
  274. if(NULL == *ppDomainSid)
  275. {
  276. dwErr = (DWORD) E_FAIL;
  277. _LeaveErrorStr(dwErr, "SID not found", wszDomain);
  278. }
  279. }
  280. }
  281. __except(dwErr = myHEXCEPTIONCODE(), EXCEPTION_EXECUTE_HANDLER)
  282. {
  283. }
  284. LeaveCriticalSection(&g_csDomainSidCache);
  285. return dwErr;
  286. }
  287. // CACleanup is called multiple times!
  288. VOID
  289. CACleanup()
  290. {
  291. if (NULL != g_pwszEnterpriseRoot)
  292. {
  293. LocalFree(g_pwszEnterpriseRoot);
  294. g_pwszEnterpriseRoot = NULL;
  295. }
  296. if (NULL != g_pLocalSid)
  297. {
  298. FreeSid(g_pLocalSid);
  299. g_pLocalSid = NULL;
  300. }
  301. if (NULL != g_pwszEnterpriseRootOID)
  302. {
  303. LocalFree(g_pwszEnterpriseRootOID);
  304. g_pwszEnterpriseRootOID = NULL;
  305. }
  306. FreeSidCache();
  307. }
  308. DWORD
  309. myGetEnterpriseDnsName(
  310. OUT WCHAR **ppwszDomain)
  311. {
  312. HRESULT hr;
  313. LSA_HANDLE hPolicy = NULL;
  314. POLICY_DNS_DOMAIN_INFO *pDomainInfo = NULL;
  315. if (NULL == g_pwszEnterpriseRoot)
  316. {
  317. LSA_OBJECT_ATTRIBUTES oa;
  318. SECURITY_QUALITY_OF_SERVICE sqos;
  319. NTSTATUS dwStatus;
  320. sqos.Length = sizeof(sqos);
  321. sqos.ImpersonationLevel = SecurityImpersonation;
  322. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  323. sqos.EffectiveOnly = FALSE;
  324. InitializeObjectAttributes(&oa, NULL, 0, NULL, NULL);
  325. oa.SecurityQualityOfService = &sqos;
  326. dwStatus = LsaOpenPolicy(
  327. NULL,
  328. &oa,
  329. POLICY_VIEW_LOCAL_INFORMATION,
  330. &hPolicy);
  331. hr = LsaNtStatusToWinError(dwStatus);
  332. _JumpIfError(hr, error, "LsaOpenPolicy");
  333. dwStatus = LsaQueryInformationPolicy(
  334. hPolicy,
  335. PolicyDnsDomainInformation,
  336. (VOID **) &pDomainInfo);
  337. hr = LsaNtStatusToWinError(dwStatus);
  338. _JumpIfError(hr, error, "LsaNtStatusToWinError");
  339. if (0 >= pDomainInfo->DnsForestName.Length ||
  340. NULL == pDomainInfo->DnsForestName.Buffer)
  341. {
  342. hr = ERROR_CANT_ACCESS_DOMAIN_INFO;
  343. _JumpError(hr, error, "DomainInfo");
  344. }
  345. hr = myDupString(
  346. pDomainInfo->DnsForestName.Buffer,
  347. &g_pwszEnterpriseRoot);
  348. _JumpIfError(hr, error, "myDupString");
  349. }
  350. hr = myDupString(g_pwszEnterpriseRoot, ppwszDomain);
  351. _JumpIfError(hr, error, "myDupString");
  352. error:
  353. if (NULL != pDomainInfo)
  354. {
  355. LsaFreeMemory(pDomainInfo);
  356. }
  357. if (NULL != hPolicy)
  358. {
  359. LsaClose(hPolicy);
  360. }
  361. return(hr);
  362. }
  363. CCAProperty::CCAProperty(LPCWSTR wszName)
  364. {
  365. m_awszValues = NULL;
  366. m_pNext = NULL;
  367. m_wszName = CertAllocString(wszName);
  368. }
  369. CCAProperty::~CCAProperty()
  370. {
  371. _Cleanup();
  372. }
  373. HRESULT CCAProperty::_Cleanup()
  374. {
  375. // NOTE: this should only be called via
  376. // DeleteChain
  377. if(m_awszValues)
  378. {
  379. LocalFree(m_awszValues);
  380. m_awszValues = NULL;
  381. }
  382. if(m_wszName)
  383. {
  384. CertFreeString(m_wszName);
  385. m_wszName = NULL;
  386. }
  387. m_pNext = NULL;
  388. return S_OK;
  389. }
  390. HRESULT CCAProperty::Find(LPCWSTR wszName, CCAProperty **ppCAProp)
  391. {
  392. if((wszName == NULL) || (ppCAProp == NULL))
  393. {
  394. return E_POINTER;
  395. }
  396. if(this == NULL)
  397. {
  398. return E_POINTER;
  399. }
  400. if((m_wszName != NULL) &&(mylstrcmpiL(wszName, m_wszName) == 0))
  401. {
  402. *ppCAProp = this;
  403. return S_OK;
  404. }
  405. if(m_pNext)
  406. {
  407. return m_pNext->Find(wszName, ppCAProp);
  408. }
  409. // Didn't find one
  410. *ppCAProp = NULL;
  411. return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  412. }
  413. HRESULT CCAProperty::Append(CCAProperty **ppCAPropChain, CCAProperty *pNewProp)
  414. {
  415. CCAProperty *pCurrent;
  416. if((ppCAPropChain == NULL) || (pNewProp == NULL))
  417. {
  418. return E_POINTER;
  419. }
  420. if(*ppCAPropChain == NULL)
  421. {
  422. *ppCAPropChain = pNewProp;
  423. return S_OK;
  424. }
  425. pCurrent = *ppCAPropChain;
  426. while(pCurrent->m_pNext != NULL)
  427. {
  428. pCurrent = pCurrent->m_pNext;
  429. }
  430. pCurrent->m_pNext = pNewProp;
  431. return S_OK;
  432. }
  433. HRESULT CCAProperty::GetValue(LPWSTR **pawszProperties)
  434. {
  435. HRESULT hr;
  436. LPWSTR *awsz;
  437. if(pawszProperties == NULL)
  438. {
  439. return E_POINTER;
  440. }
  441. awsz = m_awszValues;
  442. m_awszValues = NULL;
  443. hr = SetValue(awsz);
  444. *pawszProperties = m_awszValues;
  445. m_awszValues = awsz;
  446. if(hr != S_OK)
  447. {
  448. *pawszProperties = NULL;
  449. }
  450. return hr;
  451. }
  452. HRESULT CCAProperty::SetValue(LPWSTR *awszProperties)
  453. {
  454. DWORD cbStringTotal = 0;
  455. DWORD cStrings=1;
  456. WCHAR **pwszAttr;
  457. WCHAR *wszCurString;
  458. if(m_awszValues)
  459. {
  460. LocalFree(m_awszValues);
  461. m_awszValues = NULL;
  462. }
  463. if(NULL == awszProperties)
  464. {
  465. return S_OK;
  466. }
  467. for(pwszAttr = awszProperties; *pwszAttr != NULL; pwszAttr++)
  468. {
  469. cStrings += 1;
  470. cbStringTotal += (wcslen(*pwszAttr) + 1)*sizeof(WCHAR);
  471. }
  472. m_awszValues = (WCHAR **)LocalAlloc(LMEM_FIXED, cStrings*sizeof(WCHAR *) + cbStringTotal);
  473. if(m_awszValues == NULL)
  474. {
  475. return E_OUTOFMEMORY;
  476. }
  477. wszCurString = (WCHAR *)(m_awszValues + cStrings);
  478. cStrings = 0;
  479. for(pwszAttr = awszProperties; *pwszAttr != NULL; pwszAttr++)
  480. {
  481. m_awszValues[cStrings] = wszCurString;
  482. wcscpy(wszCurString, *pwszAttr);
  483. wszCurString += wcslen(wszCurString) + 1;
  484. cStrings += 1;
  485. }
  486. m_awszValues[cStrings] = NULL;
  487. return S_OK;
  488. }
  489. HRESULT CCAProperty::DeleteChain(CCAProperty **ppCAProp)
  490. {
  491. if(ppCAProp == NULL)
  492. {
  493. return E_POINTER;
  494. }
  495. if(*ppCAProp == NULL)
  496. {
  497. return S_OK;
  498. }
  499. DeleteChain(&(*ppCAProp)->m_pNext);
  500. delete *ppCAProp;
  501. return S_OK;
  502. }
  503. HRESULT CCAProperty::LoadFromRegValue(HKEY hkReg, LPCWSTR wszValue)
  504. {
  505. DWORD err;
  506. DWORD dwType;
  507. DWORD dwSize;
  508. HRESULT hr = S_OK;
  509. WCHAR *wszValues = NULL;
  510. if(m_awszValues)
  511. {
  512. LocalFree(m_awszValues);
  513. m_awszValues = NULL;
  514. }
  515. if((hkReg == NULL ) || (wszValue == NULL))
  516. {
  517. return E_POINTER;
  518. }
  519. err = RegQueryValueEx(hkReg,
  520. wszValue,
  521. NULL,
  522. &dwType,
  523. NULL,
  524. &dwSize);
  525. if(ERROR_SUCCESS != err)
  526. {
  527. hr = myHError(err);
  528. goto error;
  529. }
  530. if(sizeof(WCHAR) != dwSize)
  531. {
  532. switch(dwType)
  533. {
  534. case REG_SZ:
  535. //protect registry corruption. Add the NULL terminator
  536. m_awszValues = (WCHAR **)LocalAlloc(LPTR, 2*sizeof(WCHAR *) + dwSize + sizeof(WCHAR));
  537. if(m_awszValues == NULL)
  538. {
  539. hr = E_OUTOFMEMORY;
  540. goto error;
  541. }
  542. err = RegQueryValueEx(hkReg,
  543. wszValue,
  544. NULL,
  545. &dwType,
  546. (PBYTE)(m_awszValues+2),
  547. &dwSize);
  548. if(ERROR_SUCCESS != err)
  549. {
  550. hr = myHError(err);
  551. goto error;
  552. }
  553. m_awszValues[0] = (WCHAR *)(m_awszValues+2);
  554. m_awszValues[1] = NULL;
  555. break;
  556. case REG_MULTI_SZ:
  557. {
  558. WCHAR *wszCur;
  559. DWORD cStrings = 1;
  560. //add the double NULL terminator
  561. wszValues = (WCHAR *)LocalAlloc(LPTR, dwSize + sizeof(WCHAR) + sizeof(WCHAR));
  562. if(wszValues == NULL)
  563. {
  564. hr = E_OUTOFMEMORY;
  565. goto error;
  566. }
  567. err = RegQueryValueEx(hkReg,
  568. wszValue,
  569. NULL,
  570. &dwType,
  571. (PBYTE)wszValues,
  572. &dwSize);
  573. if(ERROR_SUCCESS != err)
  574. {
  575. hr = myHError(err);
  576. goto error;
  577. }
  578. wszCur = wszValues;
  579. while(wcslen(wszCur) > 0)
  580. {
  581. cStrings++;
  582. wszCur += wcslen(wszCur)+1;
  583. }
  584. m_awszValues = (WCHAR **)LocalAlloc(LMEM_FIXED, cStrings*sizeof(WCHAR *) + dwSize + sizeof(WCHAR) + sizeof(WCHAR));
  585. if(m_awszValues == NULL)
  586. {
  587. hr = E_OUTOFMEMORY;
  588. goto error;
  589. }
  590. CopyMemory((PBYTE)(m_awszValues + cStrings), wszValues, dwSize + sizeof(WCHAR) + sizeof(WCHAR));
  591. wszCur = (WCHAR *)(m_awszValues + cStrings);
  592. cStrings = 0;
  593. while(wcslen(wszCur) > 0)
  594. {
  595. m_awszValues[cStrings] = wszCur;
  596. cStrings++;
  597. wszCur += wcslen(wszCur)+1;
  598. }
  599. m_awszValues[cStrings] = NULL;
  600. break;
  601. }
  602. default:
  603. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  604. goto error;
  605. }
  606. }
  607. error:
  608. if(wszValues)
  609. {
  610. LocalFree(wszValues);
  611. }
  612. return hr;
  613. }
  614. HRESULT CCAProperty::UpdateToRegValue(HKEY hkReg, LPCWSTR wszValue)
  615. {
  616. DWORD err;
  617. CERTSTR bstrRegValue = NULL;
  618. HRESULT hr = S_OK;
  619. if((hkReg == NULL ) || (wszValue == NULL))
  620. {
  621. return E_POINTER;
  622. }
  623. if(m_awszValues == NULL)
  624. {
  625. bstrRegValue = CertAllocString(TEXT(""));
  626. if(bstrRegValue == NULL)
  627. {
  628. hr = E_OUTOFMEMORY;
  629. goto error;
  630. }
  631. }
  632. else
  633. {
  634. LPWSTR *pwszCur = m_awszValues;
  635. LPWSTR wszCopy = NULL;
  636. DWORD cValues = 0;
  637. while(*pwszCur)
  638. {
  639. cValues += wcslen(*pwszCur) + 1;
  640. pwszCur++;
  641. }
  642. cValues++;
  643. bstrRegValue = CertAllocStringLen(NULL, cValues);
  644. if(bstrRegValue == NULL)
  645. {
  646. hr = E_OUTOFMEMORY;
  647. goto error;
  648. }
  649. pwszCur = m_awszValues;
  650. wszCopy = bstrRegValue;
  651. while(*pwszCur)
  652. {
  653. CopyMemory(wszCopy, *pwszCur, sizeof(WCHAR)*(wcslen(*pwszCur)+1));
  654. wszCopy += (wcslen(*pwszCur)+1);
  655. pwszCur++;
  656. }
  657. *wszCopy = NULL;
  658. }
  659. err = RegSetValueEx(hkReg,
  660. wszValue,
  661. NULL,
  662. REG_MULTI_SZ,
  663. (PBYTE)bstrRegValue,
  664. CertStringByteLen(bstrRegValue));
  665. if(ERROR_SUCCESS != err )
  666. {
  667. hr = myHError(err);
  668. goto error;
  669. }
  670. error:
  671. if(bstrRegValue)
  672. {
  673. CertFreeString(bstrRegValue);
  674. }
  675. return hr;
  676. }
  677. HRESULT CertFreeString(CERTSTR cstrString)
  678. {
  679. if(cstrString == NULL)
  680. {
  681. return E_POINTER;
  682. }
  683. WCHAR *pData = (WCHAR *)(((PBYTE)cstrString)-sizeof(UINT));
  684. LocalFree(pData);
  685. return S_OK;
  686. }
  687. CERTSTR CertAllocString(LPCWSTR wszString)
  688. {
  689. if(wszString == NULL)
  690. {
  691. return NULL;
  692. }
  693. return CertAllocStringLen(wszString, wcslen(wszString)+1);
  694. }
  695. CERTSTR CertAllocStringLen(LPCWSTR wszString, UINT len)
  696. {
  697. CERTSTR szResult;
  698. szResult = CertAllocStringByteLen(NULL, len*sizeof(WCHAR));
  699. if (NULL != szResult && NULL != wszString)
  700. {
  701. CopyMemory(szResult, wszString, min(wcslen(wszString)+1, len)*sizeof(WCHAR));
  702. }
  703. return szResult;
  704. }
  705. CERTSTR CertAllocStringByteLen(LPCSTR szString, UINT len)
  706. {
  707. PBYTE pbResult;
  708. pbResult = (PBYTE)LocalAlloc(LMEM_FIXED, len + sizeof(UINT) + sizeof(WCHAR));
  709. if (NULL == pbResult)
  710. return NULL;
  711. *((UINT *)pbResult) = len;
  712. pbResult += sizeof(UINT);
  713. *((UNALIGNED WCHAR *)(pbResult+len)) = L'\0';
  714. if(szString)
  715. {
  716. CopyMemory(pbResult, szString, min(len, strlen(szString)+1));
  717. }
  718. return (CERTSTR)pbResult;
  719. }
  720. UINT CertStringLen(CERTSTR cstrString)
  721. {
  722. if(cstrString == NULL)
  723. {
  724. return 0;
  725. }
  726. return(*((UINT *)((PBYTE)cstrString - sizeof(UINT))))/sizeof(WCHAR);
  727. }
  728. UINT CertStringByteLen(CERTSTR cstrString)
  729. {
  730. if(cstrString == NULL)
  731. {
  732. return 0;
  733. }
  734. return(*((UINT *)((PBYTE)cstrString - sizeof(UINT))));
  735. }
  736. HRESULT CAAccessCheckp(HANDLE ClientToken, PSECURITY_DESCRIPTOR pSD)
  737. {
  738. return CAAccessCheckpEx(ClientToken, pSD, CERTTYPE_ACCESS_CHECK_ENROLL);
  739. }
  740. HRESULT CAAccessCheckpEx(HANDLE ClientToken, PSECURITY_DESCRIPTOR pSD, DWORD dwOption)
  741. {
  742. HRESULT hr = S_OK;
  743. HANDLE hClientToken = NULL;
  744. HANDLE hHandle = NULL;
  745. PRIVILEGE_SET ps;
  746. DWORD dwPSSize = sizeof(ps);
  747. GENERIC_MAPPING AccessMapping;
  748. BOOL fAccessAllowed = FALSE;
  749. DWORD grantAccess;
  750. PTOKEN_USER pUserInfo = NULL;
  751. DWORD cbUserInfo = 0;
  752. SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY;
  753. OBJECT_TYPE_LIST aObjectTypeList[] = {
  754. {
  755. ACCESS_OBJECT_GUID, // Level
  756. 0, // Sbz
  757. const_cast<GUID *>(&GUID_ENROLL)
  758. }
  759. };
  760. DWORD cObjectTypeList = sizeof(aObjectTypeList)/sizeof(aObjectTypeList[0]);
  761. OBJECT_TYPE_LIST aAutoEnrollList[] = {
  762. {
  763. ACCESS_OBJECT_GUID, // Level
  764. 0, // Sbz
  765. const_cast<GUID *>(&GUID_AUTOENROLL)
  766. }
  767. };
  768. DWORD cAutoEnrollList = sizeof(aAutoEnrollList)/sizeof(aAutoEnrollList[0]);
  769. if(pSD == NULL)
  770. {
  771. hr = E_ACCESSDENIED;
  772. goto error;
  773. }
  774. if(ClientToken == NULL)
  775. {
  776. hHandle = GetCurrentThread();
  777. if (NULL == hHandle)
  778. {
  779. hr = myHLastError();
  780. }
  781. else
  782. {
  783. if (!OpenThreadToken(hHandle,
  784. TOKEN_QUERY,
  785. TRUE, // open as self
  786. &hClientToken))
  787. {
  788. hr = myHLastError();
  789. CloseHandle(hHandle);
  790. hHandle = NULL;
  791. }
  792. }
  793. if(hr != S_OK)
  794. {
  795. hHandle = GetCurrentProcess();
  796. if (NULL == hHandle)
  797. {
  798. hr = myHLastError();
  799. }
  800. else
  801. {
  802. HANDLE hProcessToken = NULL;
  803. hr = S_OK;
  804. if (!OpenProcessToken(hHandle,
  805. TOKEN_DUPLICATE,
  806. &hProcessToken))
  807. {
  808. hr = myHLastError();
  809. CloseHandle(hHandle);
  810. hHandle = NULL;
  811. }
  812. else
  813. {
  814. if(!DuplicateToken(hProcessToken,
  815. SecurityImpersonation,
  816. &hClientToken))
  817. {
  818. hr = myHLastError();
  819. CloseHandle(hHandle);
  820. hHandle = NULL;
  821. }
  822. CloseHandle(hProcessToken);
  823. }
  824. }
  825. }
  826. }
  827. else
  828. {
  829. hClientToken = ClientToken;
  830. }
  831. // First, we check the special case. If the ClientToken
  832. // primary SID is for Local System, then we get the
  833. // real domain relative sid for this machine
  834. GetTokenInformation(hClientToken, TokenUser, NULL, 0, &cbUserInfo);
  835. if(cbUserInfo == 0)
  836. {
  837. hr = myHLastError();
  838. goto error;
  839. }
  840. pUserInfo = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, cbUserInfo);
  841. if(pUserInfo == NULL)
  842. {
  843. hr = E_OUTOFMEMORY;
  844. goto error;
  845. }
  846. if(!GetTokenInformation(hClientToken, TokenUser, pUserInfo, cbUserInfo, &cbUserInfo))
  847. {
  848. hr = myHLastError();
  849. goto error;
  850. }
  851. // Check it see if we're local-system
  852. if(0 == (CERTTYPE_ACCESS_CHECK_NO_MAPPING & dwOption))
  853. {
  854. if(NULL == g_pLocalSid)
  855. {
  856. if(!AllocateAndInitializeSid(&IDAuthorityNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0,0,0,0,0,0,0, &g_pLocalSid))
  857. {
  858. hr = myHLastError();
  859. g_pLocalSid=NULL;
  860. goto error;
  861. }
  862. }
  863. if(EqualSid(g_pLocalSid, pUserInfo->User.Sid))
  864. {
  865. // This is local system.
  866. // Derive the real token
  867. if(hClientToken != ClientToken)
  868. {
  869. CloseHandle(hClientToken);
  870. }
  871. hClientToken = NULL;
  872. if(!myNetLogonUser(NULL, NULL, NULL, &hClientToken))
  873. {
  874. hr = myHLastError();
  875. goto error;
  876. }
  877. }
  878. }
  879. if(CERTTYPE_ACCESS_CHECK_ENROLL & dwOption)
  880. {
  881. if(!AccessCheckByType(
  882. pSD, // security descriptor
  883. NULL, // SID of object being checked
  884. hClientToken, // handle to client access token
  885. ACTRL_DS_CONTROL_ACCESS, // requested access rights
  886. aObjectTypeList, // array of object types
  887. cObjectTypeList, // number of object type elements
  888. &AccessMapping, // map generic to specific rights
  889. &ps, // receives privileges used
  890. &dwPSSize, // size of privilege-set buffer
  891. &grantAccess, // retrieves mask of granted rights
  892. &fAccessAllowed)) // retrieves results of access check
  893. {
  894. hr = myHLastError();
  895. _JumpIfError(hr, error, "AccessCheckByType");
  896. }
  897. }
  898. else
  899. {
  900. if(0 == (CERTTYPE_ACCESS_CHECK_AUTO_ENROLL & dwOption))
  901. {
  902. hr=E_INVALIDARG;
  903. goto error;
  904. }
  905. if(!AccessCheckByType(
  906. pSD, // security descriptor
  907. NULL, // SID of object being checked
  908. hClientToken, // handle to client access token
  909. ACTRL_DS_CONTROL_ACCESS, // requested access rights
  910. aAutoEnrollList, // array of object types
  911. cAutoEnrollList, // number of object type elements
  912. &AccessMapping, // map generic to specific rights
  913. &ps, // receives privileges used
  914. &dwPSSize, // size of privilege-set buffer
  915. &grantAccess, // retrieves mask of granted rights
  916. &fAccessAllowed)) // retrieves results of access check
  917. {
  918. hr = myHLastError();
  919. _JumpIfError(hr, error, "AccessCheckByType");
  920. }
  921. }
  922. if(fAccessAllowed)
  923. {
  924. hr = S_OK;
  925. }
  926. else
  927. {
  928. hr = myHLastError();
  929. }
  930. error:
  931. if(pUserInfo)
  932. {
  933. LocalFree(pUserInfo);
  934. }
  935. if(hHandle)
  936. {
  937. CloseHandle(hHandle);
  938. }
  939. if(hClientToken != ClientToken)
  940. {
  941. if(hClientToken)
  942. {
  943. CloseHandle(hClientToken);
  944. }
  945. }
  946. return hr;
  947. }