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.

785 lines
15 KiB

  1. // Copyright (C) 1997 Microsoft Corporation
  2. //
  3. // ADSI wrapper
  4. //
  5. // 9-22-97 sburns
  6. #include "headers.hxx"
  7. #include "adsi.hpp"
  8. const String ADSI::PROVIDER(L"WinNT");
  9. const String ADSI::PROVIDER_ROOT(L"WinNT://");
  10. const String ADSI::CLASS_User(USER_CLASS_NAME);
  11. const String ADSI::CLASS_Group(GROUP_CLASS_NAME);
  12. const String ADSI::CLASS_Computer(COMPUTER_CLASS_NAME);
  13. const String ADSI::PATH_SEP(L"/");
  14. const String ADSI::PROPERTY_PasswordExpired(L"PasswordExpired");
  15. const String ADSI::PROPERTY_UserFlags(L"UserFlags");
  16. const String ADSI::PROPERTY_LocalDrive(L"HomeDirDrive");
  17. const String ADSI::PROPERTY_UserParams(L"Parameters");
  18. const String ADSI::PROPERTY_ObjectSID(L"ObjectSID");
  19. const String ADSI::PROPERTY_GroupType(L"groupType");
  20. // InetOrgPerson needs to be supported as if it was a user.
  21. // The WINNT provider always returns inetOrgPerson objects
  22. // as users but the LDAP provider returns them as inetOrgPerson.
  23. // This string is used for the comparison
  24. // NTRAID#NTBUG9-436314-2001/07/16-jeffjon
  25. const String ADSI::CLASS_InetOrgPerson(L"inetOrgPerson");
  26. static const String COMPUTER_SUFFIX(L"," COMPUTER_CLASS_NAME);
  27. static
  28. HRESULT
  29. buildEnumerator(
  30. SmartInterface<IADsContainer>& container,
  31. IEnumVARIANT*& enumVariant);
  32. static
  33. HRESULT
  34. buildEnumerator(IADsMembers& members, IEnumVARIANT*& enumVariant);
  35. static
  36. HRESULT
  37. enumerateNext(
  38. IEnumVARIANT& enumVariant,
  39. int numberElementsToRead,
  40. _variant_t destinationBuf[],
  41. int& elementsRead);
  42. static
  43. HRESULT
  44. freeEnumerator(IEnumVARIANT& enumerator);
  45. static
  46. HRESULT
  47. buildEnumerator(
  48. SmartInterface<IADsContainer>& container,
  49. IEnumVARIANT*& enumVariant)
  50. {
  51. LOG_FUNCTION(buildEnumerator);
  52. return ::ADsBuildEnumerator(container, &enumVariant);
  53. }
  54. HRESULT
  55. buildEnumerator(IADsMembers& members, IEnumVARIANT*& enumVariant)
  56. {
  57. LOG_FUNCTION(buildEnumerator);
  58. // this fast-and-loose cast is from ADSI sample code...
  59. return ::ADsBuildEnumerator((IADsContainer*) &members, &enumVariant);
  60. }
  61. HRESULT
  62. freeEnumerator(IEnumVARIANT& enumerator)
  63. {
  64. LOG_FUNCTION(freeEnumerator);
  65. return ::ADsFreeEnumerator(&enumerator);
  66. }
  67. HRESULT
  68. enumerateNext(
  69. IEnumVARIANT& enumVariant,
  70. int numberElementsToRead,
  71. _variant_t destinationBuf[],
  72. int& elementsRead)
  73. {
  74. LOG_FUNCTION(enumerateNext);
  75. ASSERT(numberElementsToRead);
  76. ULONG n = 0;
  77. HRESULT hr =
  78. ::ADsEnumerateNext(
  79. &enumVariant,
  80. numberElementsToRead,
  81. destinationBuf,
  82. &n);
  83. // this cast is safe, as we never ask for more elements than can be
  84. // counted with an int.
  85. elementsRead = static_cast<int>(n);
  86. return hr;
  87. }
  88. HRESULT
  89. walkArray(
  90. _variant_t varray[],
  91. int arraySize,
  92. ADSI::ObjectVisitor& visitor)
  93. {
  94. LOG_FUNCTION(walkArray);
  95. HRESULT hr = S_OK;
  96. for (int i = 0; i < arraySize; i++ )
  97. {
  98. IDispatch* dispatch = varray[i].pdispVal;
  99. ASSERT(dispatch);
  100. if (dispatch)
  101. {
  102. IADs* object = 0;
  103. hr = dispatch->QueryInterface(QI_PARAMS(IADs, &object));
  104. BREAK_ON_FAILED_HRESULT(hr);
  105. ASSERT(object);
  106. if (object)
  107. {
  108. SmartInterface<IADs> so(0);
  109. so.Acquire(object);
  110. visitor.Visit(so);
  111. }
  112. }
  113. // we do not release dispatch, as this is done when the array is
  114. // destroyed: _variant_t::~_variant_t calls VariantClear. As each
  115. // element has type VT_DISPATCH, VariantClear releases the interface for
  116. // us.
  117. }
  118. return hr;
  119. }
  120. HRESULT
  121. walkEnumeration(IEnumVARIANT& enumerator, ADSI::ObjectVisitor& visitor)
  122. {
  123. LOG_FUNCTION(walkEnumeration);
  124. // read 100 values at a time.
  125. static const int MAX_ADS_ENUM = 100;
  126. HRESULT hr = S_OK;
  127. bool done = false;
  128. do
  129. {
  130. _variant_t varray[MAX_ADS_ENUM];
  131. int objects_fetched = 0;
  132. hr =
  133. enumerateNext(
  134. enumerator,
  135. MAX_ADS_ENUM,
  136. varray,
  137. objects_fetched);
  138. BREAK_ON_FAILED_HRESULT(hr);
  139. done = (hr == S_FALSE) ? true : false;
  140. hr = walkArray(varray, objects_fetched, visitor);
  141. BREAK_ON_FAILED_HRESULT(hr);
  142. }
  143. while (!done);
  144. return hr;
  145. }
  146. buildVarArrayStr(
  147. const StringVector& strings,
  148. _variant_t& v)
  149. {
  150. LOG_FUNCTION(buildVarArrayStr);
  151. ASSERT(strings.size());
  152. PWSTR* a = new PWSTR[strings.size()];
  153. for (int i = 0; i < strings.size(); i++)
  154. {
  155. a[i] = const_cast<wchar_t*>(strings[i].c_str());
  156. }
  157. HRESULT hr =
  158. ::ADsBuildVarArrayStr(a, static_cast<DWORD>(strings.size()), &v);
  159. delete[] a;
  160. return hr;
  161. }
  162. HRESULT
  163. ADSI::VisitChildren(
  164. const String& containerPath,
  165. const String& objectADSIClass,
  166. ADSI::ObjectVisitor& visitor)
  167. {
  168. LOG_FUNCTION2(
  169. ADSI::VisitChildren,
  170. String::format(
  171. L"container: %1 class: %2",
  172. containerPath.c_str(),
  173. objectADSIClass.c_str()));
  174. ASSERT(!containerPath.empty());
  175. ASSERT(!objectADSIClass.empty());
  176. HRESULT hr = S_OK;
  177. // This interface must be released
  178. IEnumVARIANT* enumerator = 0;
  179. do
  180. {
  181. hr = CoInitialize(0);
  182. BREAK_ON_FAILED_HRESULT(hr);
  183. SmartInterface<IADsContainer> container(0);
  184. hr = ADSI::GetContainer(containerPath, container);
  185. // failure => not a valid container
  186. BREAK_ON_FAILED_HRESULT(hr);
  187. _variant_t filter;
  188. PWSTR a = const_cast<wchar_t*>(objectADSIClass.c_str());
  189. hr = ::ADsBuildVarArrayStr(&a, 1, &filter);
  190. BREAK_ON_FAILED_HRESULT(hr);
  191. hr = container->put_Filter(filter);
  192. BREAK_ON_FAILED_HRESULT(hr);
  193. hr = buildEnumerator(container, enumerator);
  194. BREAK_ON_FAILED_HRESULT(hr);
  195. hr = walkEnumeration(*enumerator, visitor);
  196. BREAK_ON_FAILED_HRESULT(hr);
  197. }
  198. while (0);
  199. if (enumerator)
  200. {
  201. freeEnumerator(*enumerator);
  202. }
  203. return hr;
  204. }
  205. HRESULT
  206. ADSI::VisitMembers(
  207. const SmartInterface<IADsGroup>& group,
  208. ADSI::ObjectVisitor& visitor)
  209. {
  210. LOG_FUNCTION(ADSI::VisitMembers);
  211. HRESULT hr = S_OK;
  212. // these must be released when we're done
  213. IADsMembers* members = 0;
  214. IEnumVARIANT* enumerator = 0;
  215. do
  216. {
  217. hr = group->Members(&members);
  218. BREAK_ON_FAILED_HRESULT(hr);
  219. hr = buildEnumerator(*members, enumerator);
  220. BREAK_ON_FAILED_HRESULT(hr);
  221. hr = walkEnumeration(*enumerator, visitor);
  222. BREAK_ON_FAILED_HRESULT(hr);
  223. }
  224. while (0);
  225. if (enumerator)
  226. {
  227. freeEnumerator(*enumerator);
  228. }
  229. if (members)
  230. {
  231. members->Release();
  232. }
  233. return hr;
  234. }
  235. String
  236. ADSI::ExtractObjectName(const String& ADSIPath)
  237. {
  238. LOG_FUNCTION2(ADSI::ExtractObjectName, ADSIPath);
  239. ASSERT(!ADSIPath.empty());
  240. PathCracker cracker(ADSIPath);
  241. return cracker.leaf();
  242. }
  243. String
  244. ADSI::ComposeMachineContainerPath(const String& computerName)
  245. {
  246. return
  247. PROVIDER_ROOT
  248. + computerName
  249. + COMPUTER_SUFFIX;
  250. }
  251. HRESULT
  252. ADSI::RenameObject(
  253. const String& containerADSIPath,
  254. const String& objectADSIPath,
  255. const String& newName)
  256. {
  257. LOG_FUNCTION2(
  258. ADSI::RenameObject,
  259. String::format(
  260. L"container: %1 object: %2, new name: %3",
  261. containerADSIPath.c_str(),
  262. objectADSIPath.c_str(),
  263. newName.c_str()));
  264. ASSERT(!containerADSIPath.empty());
  265. ASSERT(!objectADSIPath.empty());
  266. ASSERT(!newName.empty());
  267. HRESULT hr = S_OK;
  268. do
  269. {
  270. SmartInterface<IADsContainer> container(0);
  271. hr = ADSI::GetContainer(containerADSIPath, container);
  272. BREAK_ON_FAILED_HRESULT(hr);
  273. IDispatch* object = 0;
  274. hr =
  275. container->MoveHere(
  276. AutoBstr(objectADSIPath),
  277. AutoBstr(newName),
  278. &object);
  279. BREAK_ON_FAILED_HRESULT(hr);
  280. ASSERT(object);
  281. }
  282. while (0);
  283. return hr;
  284. }
  285. HRESULT
  286. ADSI::DeleteObject(
  287. const String& containerADSIPath,
  288. const String& objectRelativeName,
  289. const String& objectClass)
  290. {
  291. LOG_FUNCTION2(
  292. ADSI::DeleteObject,
  293. String::format(
  294. L"container: %1 object: %2 class: %3",
  295. containerADSIPath.c_str(),
  296. objectRelativeName.c_str(),
  297. objectClass.c_str()));
  298. ASSERT(!containerADSIPath.empty());
  299. ASSERT(!objectRelativeName.empty());
  300. ASSERT(!objectClass.empty());
  301. HRESULT hr = S_OK;
  302. do
  303. {
  304. SmartInterface<IADsContainer> container(0);
  305. hr = ADSI::GetContainer(containerADSIPath, container);
  306. BREAK_ON_FAILED_HRESULT(hr);
  307. hr =
  308. container->Delete(
  309. AutoBstr(objectClass),
  310. AutoBstr(objectRelativeName));
  311. BREAK_ON_FAILED_HRESULT(hr);
  312. }
  313. while (0);
  314. return hr;
  315. }
  316. HRESULT
  317. ADSI::IsComputerAccessible(const String& machine)
  318. {
  319. LOG_FUNCTION2(ADSI::IsComputerAccessible, machine);
  320. ASSERT(!machine.empty());
  321. String path = ADSI::ComposeMachineContainerPath(machine);
  322. SmartInterface<IADsContainer> container(0);
  323. return ADSI::GetContainer(path, container);
  324. }
  325. HRESULT
  326. ADSI::VisitGroups(
  327. const SmartInterface<IADsUser>& user,
  328. ADSI::ObjectVisitor& visitor)
  329. {
  330. LOG_FUNCTION(ADSI::VisitGroups);
  331. HRESULT hr = S_OK;
  332. // these must be released when we're done
  333. IADsMembers* members = 0;
  334. IEnumVARIANT* enumerator = 0;
  335. do
  336. {
  337. hr = user->Groups(&members);
  338. BREAK_ON_FAILED_HRESULT(hr);
  339. hr = buildEnumerator(*members, enumerator);
  340. BREAK_ON_FAILED_HRESULT(hr);
  341. hr = walkEnumeration(*enumerator, visitor);
  342. BREAK_ON_FAILED_HRESULT(hr);
  343. }
  344. while (0);
  345. if (enumerator)
  346. {
  347. freeEnumerator(*enumerator);
  348. }
  349. if (members)
  350. {
  351. members->Release();
  352. }
  353. return hr;
  354. }
  355. // e.g. DOMAIN\account
  356. String
  357. ADSI::ExtractDomainObjectName(const String& ADSIPath)
  358. {
  359. LOG_FUNCTION2(ADSI::ExtractDomainObjectName, ADSIPath);
  360. ASSERT(!ADSIPath.empty());
  361. String result(ADSIPath);
  362. size_t pos = ADSIPath.find_last_of(ADSI::PATH_SEP);
  363. if (pos != String::npos)
  364. {
  365. // the last '/' marks the user name, just prior to that is the machine
  366. // name (or the domain name), so find the 2nd to last '/'
  367. pos = ADSIPath.find_last_of(ADSI::PATH_SEP, pos - 1);
  368. if (pos != String::npos)
  369. {
  370. String s = ADSIPath.substr(pos + 1);
  371. result = s.replace(ADSI::PATH_SEP, L"\\");
  372. }
  373. }
  374. else
  375. {
  376. // there's something weird about the path
  377. ASSERT(false);
  378. }
  379. LOG(result);
  380. return result;
  381. }
  382. void
  383. ADSI::FreeSid(SID* sid)
  384. {
  385. ASSERT(sid);
  386. delete[] reinterpret_cast<BYTE*>(sid);
  387. }
  388. // allocates memory (with ::operator new) to hold a copy of the SID inside the
  389. // variant. returns a pointer to that memory as a SID*, which the caller
  390. // should free with ADSI::FreeSid.
  391. HRESULT
  392. VariantToSid(VARIANT* var, SID*& result)
  393. {
  394. LOG_FUNCTION(VariantToSid);
  395. ASSERT(var);
  396. ASSERT(V_VT(var) == (VT_ARRAY | VT_UI1));
  397. result = 0;
  398. HRESULT hr = S_OK;
  399. SAFEARRAY* psa = V_ARRAY(var);
  400. bool safeArrayAccessed = false;
  401. do
  402. {
  403. ASSERT(psa);
  404. ASSERT(psa != (SAFEARRAY*)-1);
  405. if (!psa or psa == (SAFEARRAY*)-1)
  406. {
  407. LOG(L"variant not safe array");
  408. hr = E_INVALIDARG;
  409. break;
  410. }
  411. if (::SafeArrayGetDim(psa) != 1)
  412. {
  413. LOG(L"safe array: wrong number of dimensions");
  414. hr = E_INVALIDARG;
  415. break;
  416. }
  417. if (::SafeArrayGetElemsize(psa) != 1)
  418. {
  419. LOG(L"safe array: wrong element type");
  420. hr = E_INVALIDARG;
  421. break;
  422. }
  423. PSID sid = 0;
  424. hr = ::SafeArrayAccessData(psa, reinterpret_cast<void**>(&sid));
  425. BREAK_ON_FAILED_HRESULT(hr);
  426. safeArrayAccessed = true;
  427. if (!::IsValidSid(sid))
  428. {
  429. LOG(L"sid not valid");
  430. hr = E_INVALIDARG;
  431. break;
  432. }
  433. // caller frees the result with ADSI::FreeSid
  434. DWORD bufSize = ::GetLengthSid(sid);
  435. BYTE* buffer = new BYTE[bufSize];
  436. ::ZeroMemory(buffer, bufSize);
  437. result = reinterpret_cast<SID*>(buffer);
  438. hr = Win::CopySid(bufSize, result, sid);
  439. BREAK_ON_FAILED_HRESULT(hr);
  440. }
  441. while (0);
  442. if (safeArrayAccessed)
  443. {
  444. HRESULT unused = ::SafeArrayUnaccessData(psa);
  445. ASSERT(SUCCEEDED(unused));
  446. }
  447. if (FAILED(hr))
  448. {
  449. ADSI::FreeSid(result);
  450. result = 0;
  451. }
  452. LOG_HRESULT(hr);
  453. return hr;
  454. }
  455. // Converts a VARIANT containing a safe array of bytes to a WinNT SID-style
  456. // path (WinNT://S-x-x...)
  457. HRESULT
  458. ADSI::VariantToSidPath(VARIANT* var, String& result)
  459. {
  460. LOG_FUNCTION(ADSI::VariantToSidPath);
  461. ASSERT(var);
  462. ASSERT(V_VT(var) == (VT_ARRAY | VT_UI1));
  463. result.erase();
  464. HRESULT hr = S_OK;
  465. SID* sid = 0;
  466. do
  467. {
  468. hr = VariantToSid(var, sid);
  469. BREAK_ON_FAILED_HRESULT(hr);
  470. String sidString;
  471. hr = Win::ConvertSidToStringSid(sid, sidString);
  472. BREAK_ON_FAILED_HRESULT(hr);
  473. result = ADSI::PROVIDER_ROOT + sidString;
  474. }
  475. while (0);
  476. ADSI::FreeSid(sid);
  477. LOG_HRESULT(hr);
  478. LOG(result);
  479. return hr;
  480. }
  481. HRESULT
  482. ADSI::GetSid(const String& adsiPath, SID*& result)
  483. {
  484. LOG_FUNCTION2(ADSI::GetSid, adsiPath);
  485. ASSERT(!adsiPath.empty());
  486. ASSERT(IsWinNTPath(adsiPath));
  487. HRESULT hr = S_OK;
  488. result = 0;
  489. do
  490. {
  491. SmartInterface<IADs> iads(0);
  492. IADs* p = 0;
  493. hr =
  494. ::ADsGetObject(
  495. adsiPath.c_str(),
  496. QI_PARAMS(IADs, &p));
  497. BREAK_ON_FAILED_HRESULT(hr);
  498. iads.Acquire(p);
  499. hr = ADSI::GetSid(iads, result);
  500. BREAK_ON_FAILED_HRESULT(hr);
  501. }
  502. while (0);
  503. return hr;
  504. }
  505. HRESULT
  506. ADSI::GetSid(const SmartInterface<IADs>& iads, SID*& result)
  507. {
  508. LOG_FUNCTION(ADSI::GetSid);
  509. ASSERT(iads);
  510. result = 0;
  511. HRESULT hr = S_OK;
  512. do
  513. {
  514. // get the account SID
  515. _variant_t variant;
  516. hr = iads->Get(AutoBstr(ADSI::PROPERTY_ObjectSID), &variant);
  517. BREAK_ON_FAILED_HRESULT(hr);
  518. hr = VariantToSid(&variant, result);
  519. BREAK_ON_FAILED_HRESULT(hr);
  520. }
  521. while (0);
  522. return hr;
  523. }
  524. HRESULT
  525. ADSI::GetSidPath(const SmartInterface<IADs>& iads, String& result)
  526. {
  527. LOG_FUNCTION(ADSI::GetSidPath);
  528. ASSERT(iads);
  529. result.erase();
  530. HRESULT hr = S_OK;
  531. do
  532. {
  533. // get the account SID
  534. _variant_t variant;
  535. hr = iads->Get(AutoBstr(ADSI::PROPERTY_ObjectSID), &variant);
  536. BREAK_ON_FAILED_HRESULT(hr);
  537. hr = ADSI::VariantToSidPath(&variant, result);
  538. BREAK_ON_FAILED_HRESULT(hr);
  539. }
  540. while (0);
  541. return hr;
  542. }
  543. HRESULT
  544. ADSI::GetSidPath(const String& adsiPath, String& result)
  545. {
  546. LOG_FUNCTION2(ADSI::GetSidPath, adsiPath);
  547. ASSERT(!adsiPath.empty());
  548. ASSERT(IsWinNTPath(adsiPath));
  549. result.erase();
  550. HRESULT hr = S_OK;
  551. do
  552. {
  553. SmartInterface<IADs> iads(0);
  554. IADs* p = 0;
  555. hr =
  556. ::ADsGetObject(
  557. adsiPath.c_str(),
  558. QI_PARAMS(IADs, &p));
  559. BREAK_ON_FAILED_HRESULT(hr);
  560. iads.Acquire(p);
  561. hr = ADSI::GetSidPath(iads, result);
  562. BREAK_ON_FAILED_HRESULT(hr);
  563. }
  564. while (0);
  565. return hr;
  566. }
  567. bool
  568. ADSI::IsWinNTPath(const String& path)
  569. {
  570. LOG_FUNCTION2(ADSI::IsWinNTPath, path);
  571. bool result = false;
  572. if (path.find(ADSI::PROVIDER_ROOT) == 0)
  573. {
  574. result = true;
  575. }
  576. LOG(result ? L"true" : L"false");
  577. return result;
  578. }