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.

333 lines
12 KiB

  1. /*---------------------------------------------------------------------------
  2. File: SetDetector.cpp
  3. Comments: implementation of COM object to detect whether a set of users and
  4. groups forms a closed set.
  5. This is used by the GUI, and the engine to determine whether ReACLing must be
  6. done for intra-forest, mixed-mode source domain, incremental migrations.
  7. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  8. Proprietary and confidential to Mission Critical Software, Inc.
  9. REVISION LOG ENTRY
  10. Revision By: Christy Boles
  11. Revised on 07/01/99
  12. ---------------------------------------------------------------------------
  13. */// SetDetector.cpp : Implementation of CMcsClosedSetApp and DLL registration.
  14. #include "stdafx.h"
  15. #include "ClSet.h"
  16. #include "Detector.h"
  17. #include "Common.hpp"
  18. #include "UString.hpp"
  19. #include "TNode.hpp"
  20. #include "ResStr.h"
  21. #include <comdef.h>
  22. #include <iads.h>
  23. #include <adshlp.h>
  24. #import "\bin\NetEnum.tlb" no_namespace, named_guids
  25. class TItemNode : public TNode
  26. {
  27. _bstr_t m_name;
  28. long m_iter;
  29. long m_status;
  30. long m_nLinks;
  31. TItemNode ** m_Links;
  32. public:
  33. TItemNode(WCHAR const * name) { m_name = name; m_Links = NULL; m_status = 0; m_iter = 0; m_nLinks = 0; }
  34. void SetIter(long val) { m_iter = val; }
  35. void SetStatus(long val) { m_status = val; }
  36. long GetStatus() { return m_status; }
  37. long GetIter() { return m_iter; }
  38. WCHAR const * GetName() { return (WCHAR const *)m_name; }
  39. };
  40. class TLinkTree : public TNodeListSortable
  41. {
  42. static int CompNode(const TNode * n1, const TNode * n2)
  43. {
  44. TItemNode * t1 = (TItemNode *)n1;
  45. TItemNode * t2 = (TItemNode *)n2;
  46. return UStrICmp(t1->GetName(),t2->GetName());
  47. }
  48. static int CompValue(const TNode * n, const void * v)
  49. {
  50. TItemNode * p = (TItemNode *)n;
  51. WCHAR const * name = (WCHAR const *) v;
  52. return UStrICmp(p->GetName(),name);
  53. }
  54. public:
  55. TLinkTree() { TypeSetTree(); CompareSet(&TLinkTree::CompNode); }
  56. ~TLinkTree() { ToSorted(); DeleteAllListItems(TItemNode); }
  57. TItemNode * Lookup(WCHAR const * name) { return (TItemNode *)Find(&TLinkTree::CompValue,name); }
  58. };
  59. /////////////////////////////////////////////////////////////////////////////
  60. //
  61. HRESULT
  62. AddToList(
  63. TLinkTree * pUsers,
  64. TLinkTree * pGroups,
  65. WCHAR const * domain,
  66. WCHAR const * pName
  67. )
  68. {
  69. HRESULT hr = S_OK;
  70. IADs * pADs = NULL;
  71. WCHAR path[MAX_PATH];
  72. BSTR bstrClass = NULL;
  73. TItemNode * pNode = NULL;
  74. swprintf(path,L"LDAP://%s/%s",domain,pName);
  75. hr = ADsGetObject(path,IID_IADs,(void**)&pADs);
  76. if ( SUCCEEDED(hr) )
  77. {
  78. // get the object class
  79. hr = pADs->get_Class(&bstrClass);
  80. if ( SUCCEEDED(hr) )
  81. {
  82. if (!UStrICmp((WCHAR*)bstrClass,L"user") )
  83. {
  84. // add it to the users list
  85. pNode = new TItemNode(path);
  86. pUsers->Insert(pNode);
  87. }
  88. else if ( !UStrICmp((WCHAR*)bstrClass,L"group") )
  89. {
  90. // add it to the groups list
  91. pNode = new TItemNode(path);
  92. pGroups->Insert(pNode);
  93. }
  94. else
  95. {
  96. // we only support users and groups!
  97. MCSASSERT(FALSE);
  98. hr = E_NOTIMPL;
  99. }
  100. SysFreeString(bstrClass);
  101. }
  102. pADs->Release();
  103. }
  104. return hr;
  105. }
  106. STDMETHODIMP
  107. CSetDetector::IsClosedSet(
  108. BSTR domain, /*[in]*/
  109. LONG nItems, /*[in]*/
  110. BSTR pNames[], /*[in,size_is(nItems)]*/
  111. BOOL * bIsClosed, /*[out]*/
  112. BSTR * pReason /*[out]*/
  113. )
  114. {
  115. HRESULT hr = S_OK;
  116. long i;
  117. TLinkTree users;
  118. TLinkTree groups;
  119. BOOL bClosed = TRUE;
  120. WCHAR path[MAX_PATH];
  121. // initialize output variables
  122. (*bIsClosed) = FALSE;
  123. (*pReason) = NULL;
  124. // sort through the list of items and add them to the trees
  125. for ( i = 0 ; i < nItems ; i++ )
  126. {
  127. // for each item, get an IADs pointer to it and add it to the tree
  128. hr = AddToList(&users,&users,domain,pNames[i]);
  129. }
  130. // now iterate through the user's tree checking the group memberships of each user
  131. TNodeTreeEnum e;
  132. TItemNode * pUser;
  133. IADsUser * pADs = NULL;
  134. IADsContainer * pCont = NULL;
  135. INetObjEnumeratorPtr pEnum;
  136. VARIANT member;
  137. VARIANT memberOf;
  138. IEnumVARIANT * pEnumerator = NULL;
  139. WCHAR reason[1000] = L"";
  140. VariantInit(&member);
  141. VariantInit(&memberOf);
  142. hr = pEnum.CreateInstance(CLSID_NetObjEnumerator);
  143. if ( SUCCEEDED(hr) )
  144. {
  145. for ( i = 0 , pUser = (TItemNode*)e.OpenFirst(&users) ; pUser && bClosed ; pUser = (TItemNode*)e.Next() , i++)
  146. {
  147. // get the group memberships for the user
  148. swprintf(path,L"LDAP://%s/%s",domain,pNames[i]);
  149. SAFEARRAYBOUND bound[1] = { { 3, 0 } };
  150. SAFEARRAY * pArray = SafeArrayCreate(VT_BSTR,1,bound);
  151. hr = pEnum->SetQuery(path,domain,L"(objectClass=*)",ADS_SCOPE_BASE,TRUE);
  152. if ( SUCCEEDED(hr) )
  153. {
  154. long ndx[1];
  155. ndx[0] = 0;
  156. SafeArrayPutElement(pArray,ndx,SysAllocString(L"member"));
  157. ndx[0] = 1;
  158. SafeArrayPutElement(pArray,ndx,SysAllocString(L"memberOf"));
  159. ndx[0] = 2;
  160. SafeArrayPutElement(pArray,ndx,SysAllocString(L"distinguishedName"));
  161. hr = pEnum->SetColumns((long)pArray);
  162. }
  163. if ( SUCCEEDED(hr) )
  164. {
  165. hr = pEnum->Execute(&pEnumerator);
  166. }
  167. if ( SUCCEEDED(hr) )
  168. {
  169. unsigned long count = 0;
  170. while ( bClosed && hr != S_FALSE )
  171. {
  172. hr = pEnumerator->Next(1,&member,&count);
  173. // break if there was an error, or Next returned S_FALSE
  174. if ( hr != S_OK )
  175. break;
  176. // see if this is an array
  177. if ( member.vt == ( VT_ARRAY | VT_VARIANT ) )
  178. {
  179. pArray = member.parray;
  180. VARIANT * pData;
  181. WCHAR path2[MAX_PATH];
  182. SafeArrayAccessData(pArray,(void**)&pData);
  183. // pData[0] has the members list
  184. if ( pData[0].vt == ( VT_ARRAY | VT_VARIANT) )
  185. {
  186. // enumerate the members, checking to see if each one is in the list
  187. SAFEARRAY * pMembers = pData[0].parray;
  188. VARIANT * pMemVar = NULL;
  189. long count;
  190. SafeArrayGetUBound(pMembers,1,&count);
  191. SafeArrayAccessData(pMembers,(void**)&pMemVar);
  192. for ( long i = 0 ; i <= count ; i++ )
  193. {
  194. swprintf(path2,L"LDAP://%ls/%ls",domain,pMemVar[i].bstrVal);
  195. // check each member to see if it is in the tree
  196. if ( ! users.Lookup(path2) )
  197. {
  198. WCHAR * args[2];
  199. args[0] = path;
  200. args[1] = pMemVar[i].bstrVal;
  201. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  202. GET_STRING(IDS_CLSET_MEMBER_NOT_INCLUDED),0,0,reason,DIM(reason),(char **)args);
  203. bClosed = FALSE;
  204. break;
  205. }
  206. }
  207. SafeArrayUnaccessData(pMembers);
  208. }
  209. else
  210. {
  211. // there may be just a single member
  212. if ( pData[0].vt == VT_BSTR && UStrLen(pData[0].bstrVal))
  213. {
  214. swprintf(path2,L"LDAP://%ls/%ls",domain,pData[0].bstrVal);
  215. // check each member to see if it is in the tree
  216. if ( ! users.Lookup(path2) )
  217. {
  218. WCHAR * args[2];
  219. args[0] = path;
  220. args[1] = pData[0].bstrVal;
  221. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  222. GET_STRING(IDS_CLSET_MEMBER_NOT_INCLUDED),0,0,reason,DIM(reason),(char **)args);
  223. bClosed = FALSE;
  224. break;
  225. }
  226. }
  227. }
  228. // pData[1] has the memberOf list
  229. if ( pData[1].vt == ( VT_ARRAY | VT_VARIANT) )
  230. {
  231. // enumerate the member-ofs, checking to see if each one is in the list
  232. // enumerate the members, checking to see if each one is in the list
  233. SAFEARRAY * pMembers = pData[1].parray;
  234. VARIANT * pMemVar = NULL;
  235. long count;
  236. hr = SafeArrayGetUBound(pMembers,1,&count);
  237. hr = SafeArrayAccessData(pMembers,(void**)&pMemVar);
  238. for ( long i = 0 ; i <= count ; i++ )
  239. {
  240. swprintf(path2,L"LDAP://%ls/%ls",domain,pMemVar[i].bstrVal);
  241. // check each member to see if it is in the tree
  242. if ( ! users.Lookup(path2) )
  243. {
  244. WCHAR * args[2];
  245. args[0] = path;
  246. args[1] = pMemVar[i].bstrVal;
  247. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  248. GET_STRING(IDS_CLSET_GROUP_NOT_INCLUDED),0,0,reason,DIM(reason),(char **)args);
  249. bClosed = FALSE;
  250. break;
  251. }
  252. }
  253. SafeArrayUnaccessData(pMembers);
  254. }
  255. else
  256. {
  257. // there may be just a single entry
  258. if ( pData[1].vt == VT_BSTR && UStrLen(pData[1].bstrVal))
  259. {
  260. swprintf(path2,L"LDAP://%ls/%ls",domain,pData[1].bstrVal);
  261. // check each member to see if it is in the tree
  262. if ( ! users.Lookup(path2) )
  263. {
  264. WCHAR * args[2];
  265. args[0] = path;
  266. args[1] = pData[1].bstrVal;
  267. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  268. GET_STRING(IDS_CLSET_GROUP_NOT_INCLUDED),0,0,reason,DIM(reason),(char **)args);
  269. bClosed = FALSE;
  270. break;
  271. }
  272. }
  273. }
  274. SafeArrayUnaccessData(pArray);
  275. }
  276. }
  277. pEnumerator->Release();
  278. VariantInit(&member);
  279. }
  280. }
  281. e.Close();
  282. }
  283. (*bIsClosed) = bClosed;
  284. if ( ! bClosed )
  285. {
  286. (*pReason) = SysAllocString(reason);
  287. }
  288. return hr;
  289. }