// Advance the enumerator to the next principal in the result set, pulling in additional pages // of results (or ranges of attribute values) as needed. // Returns true if successful, false if no more results to return. internal override bool MoveNext() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMGroupsSet", "MoveNext"); _atBeginning = false; bool f = _groupsEnumerator.MoveNext(); if (f) { // Got a group. Create a DirectoryEntry for it. // Clone the ctxBase to pick up its credentials, then build an appropriate path. UnsafeNativeMethods.IADs nativeMember = (UnsafeNativeMethods.IADs)_groupsEnumerator.Current; // We do this, rather than using the DirectoryEntry constructor that takes a native IADs object, // is so the credentials get transferred to the new DirectoryEntry. If we just use the native // object constructor, the native object will have the right credentials, but the DirectoryEntry // will have default (null) credentials, which it'll use anytime it needs to use credentials. DirectoryEntry de = SDSUtils.BuildDirectoryEntry( nativeMember.ADsPath, _storeCtx.Credentials, _storeCtx.AuthTypes); _current = de; } return(f); }
private ResultSet FindByDate( FindByDateMatcher.DateProperty property, MatchType matchType, DateTime value, Type principalType ) { // We use the same SAMQuery set that we use for query-by-example, but with a different // SAMMatcher class to perform the date-range filter. // Get the entries we'll iterate over. Write access to Children is controlled through the // ctxBaseLock, but we don't want to have to hold that lock while we're iterating over all // the child entries. So we have to clone the ctxBase --- not ideal, but it prevents // multithreading issues. DirectoryEntries entries = SDSUtils.BuildDirectoryEntry(_ctxBase.Path, _credentials, _authTypes).Children; Debug.Assert(entries != null); // The SAMQuerySet will use this to restrict the types of DirectoryEntry objects returned. List <string> schemaTypes = GetSchemaFilter(principalType); // Create the ResultSet that will perform the client-side filtering SAMQuerySet resultSet = new SAMQuerySet( schemaTypes, entries, _ctxBase, -1, // no size limit this, new FindByDateMatcher(property, matchType, value)); return(resultSet); }
// Advance the enumerator to the next principal in the result set, pulling in additional pages // of results (or ranges of attribute values) as needed. // Returns true if successful, false if no more results to return. internal override bool MoveNext() { if (_atBeginning) { Debug.Assert(_principalDN != null); _current = SDSUtils.BuildDirectoryEntry( BuildPathFromDN(_principalDN), _storeCtx.Credentials, _storeCtx.AuthTypes); _current.RefreshCache(new string[] { _attributeToQuery }); _tokenGroupsEnum = _current.Properties[_attributeToQuery].GetEnumerator(); _atBeginning = false; } GlobalDebug.WriteLineIf(GlobalDebug.Info, "TokenGroupSet", "MoveNextLocal: returning primary group {0}", _current.Path); if (_tokenGroupsEnum.MoveNext()) { // Got a member from this group (or, got a group of which we're a member). // Create a DirectoryEntry for it. byte[] sid = (byte[])_tokenGroupsEnum.Current; _currentSID = new SecurityIdentifier(sid, 0); GlobalDebug.WriteLineIf(GlobalDebug.Info, "TokenGroupSet", "MoveNextLocal: got a value from the enumerator: {0}", _currentSID.ToString()); return(true); } return(false); }
internal static void WriteAttribute <T>(string dePath, string attribute, T value, NetCred credentials, AuthenticationTypes authTypes) { Debug.Assert(attribute != null && attribute.Length > 0); // Ideally, we'd just like to set the property in the principal's DirectoryEntry and write // the changes to the store. However, there might be other changes in the DirectoryEntry, // and we don't want to write all of them to the store. So we must make // a fresh DirectoryEntry and write using that. DirectoryEntry copyOfDe = null; try { copyOfDe = SDSUtils.BuildDirectoryEntry(dePath, credentials, authTypes); Debug.Assert(copyOfDe != null); // So we don't do a implicit GetInfo() and retrieve every attribute copyOfDe.RefreshCache(new string[] { attribute }); copyOfDe.Properties[attribute].Value = value; copyOfDe.CommitChanges(); } catch (System.Runtime.InteropServices.COMException e) { // ADSI threw an exception trying to write the change throw ExceptionHelper.GetExceptionFromCOMException(e); } finally { copyOfDe?.Dispose(); } }
private bool MoveNextPrimaryGroupDN() { this.current = SDSUtils.BuildDirectoryEntry(this.BuildPathFromDN(this.primaryGroupDN), this.storeCtx.Credentials, this.storeCtx.AuthTypes); this.storeCtx.InitializeNewDirectoryOptions((DirectoryEntry)this.current); this.currentForeignDE = null; this.currentForeignPrincipal = null; this.returnedPrimaryGroup = true; return(true); }
static internal void WriteAttribute(string dePath, string attribute, int value, NetCred credentials, AuthenticationTypes authTypes) { GlobalDebug.WriteLineIf( GlobalDebug.Info, "SDSUtils", "WriteAttribute: writing {0} to {1} on {2}", value.ToString(CultureInfo.InvariantCulture), attribute, dePath); Debug.Assert(attribute != null && attribute.Length > 0); // Ideally, we'd just like to set the property in the principal's DirectoryEntry and write // the changes to the store. However, there might be other changes in the DirectoryEntry, // and we don't want to write all of them to the store. So we must make // a fresh DirectoryEntry and write using that. DirectoryEntry copyOfDe = null; try { copyOfDe = SDSUtils.BuildDirectoryEntry(dePath, credentials, authTypes); Debug.Assert(copyOfDe != null); // So we don't do a implicit GetInfo() and retrieve every attribute copyOfDe.RefreshCache(new string[] { attribute }); copyOfDe.Properties[attribute].Value = value; copyOfDe.CommitChanges(); } catch (System.Runtime.InteropServices.COMException e) { GlobalDebug.WriteLineIf( GlobalDebug.Error, "SDSUtils", "WriteAttribute: caught exception with message '{0}' writing {1} to {2} on {3}", e.Message, value.ToString(CultureInfo.InvariantCulture), attribute, dePath); // ADSI threw an exception trying to write the change throw ExceptionHelper.GetExceptionFromCOMException(e); } finally { if (copyOfDe != null) { copyOfDe.Dispose(); } } }
internal override bool MoveNext() { this.atBeginning = false; bool flag = this.groupsEnumerator.MoveNext(); if (flag) { UnsafeNativeMethods.IADs current = (UnsafeNativeMethods.IADs) this.groupsEnumerator.Current; DirectoryEntry directoryEntry = SDSUtils.BuildDirectoryEntry(current.ADsPath, this.storeCtx.Credentials, this.storeCtx.AuthTypes); this.current = directoryEntry; } return(flag); }
internal override void UnlockAccount(AuthenticablePrincipal p) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "UnlockAccount"); Debug.Assert(p.fakePrincipal == false); Debug.Assert(p.unpersisted == false); // Computer accounts are never locked out, so nothing to do if (p is ComputerPrincipal) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "UnlockAccount: computer acct, skipping"); return; } DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; Debug.Assert(de != null); // After setting the property, we need to commit the change to the store. // We do it in a copy of de, so that we don't inadvertently commit any other // pending changes in de. DirectoryEntry copyOfDe = null; try { copyOfDe = SDSUtils.BuildDirectoryEntry(de.Path, _credentials, _authTypes); Debug.Assert(copyOfDe != null); copyOfDe.InvokeSet("IsAccountLocked", new object[] { false }); copyOfDe.CommitChanges(); } catch (System.Runtime.InteropServices.COMException e) { // ADSI threw an exception trying to write the change GlobalDebug.WriteLineIf(GlobalDebug.Error, "SAMStoreCtx", "UnlockAccount: caught COMException, message={0}", e.Message); throw ExceptionHelper.GetExceptionFromCOMException(e); } finally { if (copyOfDe != null) { copyOfDe.Dispose(); } } }
// The core query operation. // Given a PrincipalSearcher containg a query filter, transforms it into the store schema // and performs the query to get a collection of matching native objects (up to a maximum of sizeLimit, // or uses the sizelimit already set on the DirectorySearcher if sizeLimit == -1). // If the PrincipalSearcher does not have a query filter (PrincipalSearcher.QueryFilter == null), // matches all principals in the store. // // The collection may not be complete, i.e., paging - the returned ResultSet will automatically // page in additional results as needed. internal override ResultSet Query(PrincipalSearcher ps, int sizeLimit) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "Query"); Debug.Assert(sizeLimit >= -1); // Build the description of the properties we'll filter by. In SAMStoreCtx, the "native" searcher // is simply the QbeFilterDescription, which will be passed to the SAMQuerySet to use to // manually filter out non-matching results. QbeFilterDescription propertiesToMatch = (QbeFilterDescription)PushFilterToNativeSearcher(ps); // Get the entries we'll iterate over. Write access to Children is controlled through the // ctxBaseLock, but we don't want to have to hold that lock while we're iterating over all // the child entries. So we have to clone the ctxBase --- not ideal, but it prevents // multithreading issues. DirectoryEntries entries = SDSUtils.BuildDirectoryEntry(_ctxBase.Path, _credentials, _authTypes).Children; Debug.Assert(entries != null); // Determine the principal types of interest. The SAMQuerySet will use this to restrict // the types of DirectoryEntry objects returned. Type qbeFilterType = typeof(Principal); if (ps.QueryFilter != null) { qbeFilterType = ps.QueryFilter.GetType(); } List <string> schemaTypes = GetSchemaFilter(qbeFilterType); // Create the ResultSet that will perform the client-side filtering SAMQuerySet resultSet = new SAMQuerySet( schemaTypes, entries, _ctxBase, sizeLimit, this, new QbeMatcher(propertiesToMatch)); return(resultSet); }
internal static void WriteAttribute(string dePath, string attribute, int value, NetCred credentials, AuthenticationTypes authTypes) { DirectoryEntry directoryEntry = null; using (directoryEntry) { try { directoryEntry = SDSUtils.BuildDirectoryEntry(dePath, credentials, authTypes); string[] strArrays = new string[1]; strArrays[0] = attribute; directoryEntry.RefreshCache(strArrays); directoryEntry.Properties[attribute].Value = value; directoryEntry.CommitChanges(); } catch (COMException cOMException1) { COMException cOMException = cOMException1; throw ExceptionHelper.GetExceptionFromCOMException(cOMException); } } }
internal override bool MoveNext() { if (this.atBeginning) { this.current = SDSUtils.BuildDirectoryEntry(this.BuildPathFromDN(this.principalDN), this.storeCtx.Credentials, this.storeCtx.AuthTypes); string[] strArrays = new string[1]; strArrays[0] = this.attributeToQuery; this.current.RefreshCache(strArrays); this.tokenGroupsEnum = this.current.Properties[this.attributeToQuery].GetEnumerator(); this.atBeginning = false; } if (!this.tokenGroupsEnum.MoveNext()) { return(false); } else { byte[] current = (byte[])this.tokenGroupsEnum.Current; this.currentSID = new SecurityIdentifier(current, 0); return(true); } }
// Get groups of which p is a direct member internal override ResultSet GetGroupsMemberOf(Principal p) { // Enforced by the methods that call us Debug.Assert(p.unpersisted == false); if (!p.fakePrincipal) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "GetGroupsMemberOf: is real principal"); // No nested groups or computers as members of groups in SAM if (!(p is UserPrincipal)) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "GetGroupsMemberOf: not a user, returning empty set"); return(new EmptySet()); } Debug.Assert(p.UnderlyingObject != null); DirectoryEntry userDE = (DirectoryEntry)p.UnderlyingObject; UnsafeNativeMethods.IADsMembers iadsMembers = (UnsafeNativeMethods.IADsMembers)userDE.Invoke("Groups"); ResultSet resultSet = new SAMGroupsSet(iadsMembers, this, _ctxBase); return(resultSet); } else { // ADSI's IADsGroups doesn't work for fake principals like NT AUTHORITY\NETWORK SERVICE // We use the same SAMQuery set that we use for query-by-example, but with a different // SAMMatcher class to match groups which contain the specified principal as a member // Get the entries we'll iterate over. Write access to Children is controlled through the // ctxBaseLock, but we don't want to have to hold that lock while we're iterating over all // the child entries. So we have to clone the ctxBase --- not ideal, but it prevents // multithreading issues. DirectoryEntries entries = SDSUtils.BuildDirectoryEntry(_ctxBase.Path, _credentials, _authTypes).Children; Debug.Assert(entries != null); // The SAMQuerySet will use this to restrict the types of DirectoryEntry objects returned. List <string> schemaTypes = GetSchemaFilter(typeof(GroupPrincipal)); SecurityIdentifier principalSid = p.Sid; byte[] SidB = new byte[principalSid.BinaryLength]; principalSid.GetBinaryForm(SidB, 0); if (principalSid == null) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "SAMStoreCtx", "GetGroupsMemberOf: bad SID IC"); throw new InvalidOperationException(SR.StoreCtxNeedValueSecurityIdentityClaimToQuery); } // Create the ResultSet that will perform the client-side filtering SAMQuerySet resultSet = new SAMQuerySet( schemaTypes, entries, _ctxBase, -1, // no size limit this, new GroupMemberMatcher(SidB)); return(resultSet); } }
private bool MoveNextLocal() { bool needToRetry; do { needToRetry = false; bool f = _membersEnumerator.MoveNext(); if (f) // got a value { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: got a value from the enumerator"); UnsafeNativeMethods.IADs nativeMember = (UnsafeNativeMethods.IADs)_membersEnumerator.Current; // If we encountered a group member corresponding to a fake principal such as // NT AUTHORITY/NETWORK SERVICE, construct and prepare to return the fake principal. byte[] sid = (byte[])nativeMember.Get("objectSid"); SidType sidType = Utils.ClassifySID(sid); if (sidType == SidType.FakeObject) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: fake principal, sid={0}", Utils.ByteArrayToString(sid)); _currentFakePrincipal = _storeCtx.ConstructFakePrincipalFromSID(sid); _current = null; _currentForeign = null; if (_foreignResultSet != null) { _foreignResultSet.Dispose(); } _foreignResultSet = null; return(true); } // We do this, rather than using the DirectoryEntry constructor that takes a native IADs object, // is so the credentials get transferred to the new DirectoryEntry. If we just use the native // object constructor, the native object will have the right credentials, but the DirectoryEntry // will have default (null) credentials, which it'll use anytime it needs to use credentials. DirectoryEntry de = SDSUtils.BuildDirectoryEntry( _storeCtx.Credentials, _storeCtx.AuthTypes); if (sidType == SidType.RealObjectFakeDomain) { // Transform the "WinNT://BUILTIN/foo" path to "WinNT://machineName/foo" string builtinADsPath = nativeMember.ADsPath; UnsafeNativeMethods.Pathname pathCracker = new UnsafeNativeMethods.Pathname(); UnsafeNativeMethods.IADsPathname pathName = (UnsafeNativeMethods.IADsPathname)pathCracker; pathName.Set(builtinADsPath, 1 /* ADS_SETTYPE_FULL */); // Build the "WinNT://" portion of the new path StringBuilder adsPath = new StringBuilder(); adsPath.Append("WinNT://"); //adsPath.Append(pathName.Retrieve(9 /*ADS_FORMAT_SERVER */)); // Build the "WinNT://machineName/" portion of the new path adsPath.Append(_storeCtx.MachineUserSuppliedName); adsPath.Append('/'); // Build the "WinNT://machineName/foo" portion of the new path int cElements = pathName.GetNumElements(); Debug.Assert(cElements >= 2); // "WinNT://BUILTIN/foo" == 2 elements // Note that the ADSI WinNT provider indexes them backwards, e.g., in // "WinNT://BUILTIN/A/B", BUILTIN == 2, A == 1, B == 0. for (int i = cElements - 2; i >= 0; i--) { adsPath.Append(pathName.GetElement(i)); adsPath.Append('/'); } adsPath.Remove(adsPath.Length - 1, 1); // remove the trailing "/" de.Path = adsPath.ToString(); GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: fake domain: {0} --> {1}", builtinADsPath, adsPath); } else { Debug.Assert(sidType == SidType.RealObject); de.Path = nativeMember.ADsPath; GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: real domain {0}", de.Path); } // Debug.Assert(Utils.AreBytesEqual(sid, (byte[]) de.Properties["objectSid"].Value)); if (IsLocalMember(sid)) { // If we're processing recursively, and the member is a group, // we don't return it but instead treat it as something to recursively // visit (expand) later. if (!_recursive || !SAMUtils.IsOfObjectClass(de, "Group")) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: setting current to {0}", de.Path); // Not recursive, or not a group. Return the principal. _current = de; _currentFakePrincipal = null; _currentForeign = null; if (_foreignResultSet != null) { _foreignResultSet.Dispose(); } _foreignResultSet = null; return(true); } else { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: adding {0} to groupsToVisit", de.Path); // Save off for later, if we haven't done so already. if (!_groupsVisited.Contains(de.Path) && !_groupsToVisit.Contains(de.Path)) { _groupsToVisit.Add(de.Path); } needToRetry = true; continue; } } else { // It's a foreign principal (e..g, an AD user or group). // Save it off for later. GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: adding {0} to foreignMembers", de.Path); _foreignMembers.Add(de); needToRetry = true; continue; } } else { // We reached the end of this group's membership. // If we're supposed to be recursively expanding, we need to expand // any remaining non-foreign groups we earlier visited. if (_recursive) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: recursive processing, groupsToVisit={0}", _groupsToVisit.Count); if (_groupsToVisit.Count > 0) { // Pull off the next group to visit string groupPath = _groupsToVisit[0]; GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextLocal: recursively processing {0}", groupPath); _groupsToVisit.RemoveAt(0); _groupsVisited.Add(groupPath); // Set up for the next round of enumeration DirectoryEntry de = SDSUtils.BuildDirectoryEntry( groupPath, _storeCtx.Credentials, _storeCtx.AuthTypes); _group = (UnsafeNativeMethods.IADsGroup)de.NativeObject; UnsafeNativeMethods.IADsMembers iADsMembers = _group.Members(); _membersEnumerator = ((IEnumerable)iADsMembers).GetEnumerator(); // and go on to the first member of this new group needToRetry = true; continue; } } } }while (needToRetry); return(false); }
private bool MoveNextMemberSearcher() { bool nextSearchResult; bool flag = false; do { nextSearchResult = this.GetNextSearchResult(); flag = false; if (!nextSearchResult) { if (!this.recursive || this.groupsToVisit.Count <= 0) { continue; } string item = this.groupsToVisit[0]; this.groupsToVisit.RemoveAt(0); this.groupsVisited.Add(item); DirectoryEntry directoryEntry = SDSUtils.BuildDirectoryEntry(this.BuildPathFromDN(item), this.storeCtx.Credentials, this.storeCtx.AuthTypes); this.storeCtx.InitializeNewDirectoryOptions(directoryEntry); DirectorySearcher directorySearcher = SDSUtils.ConstructSearcher(directoryEntry); directorySearcher.Filter = "(objectClass=*)"; directorySearcher.SearchScope = SearchScope.Base; directorySearcher.AttributeScopeQuery = "member"; directorySearcher.CacheResults = false; this.memberSearchersQueue.Enqueue(directorySearcher); flag = true; } else { SearchResult current = (SearchResult)this.memberSearchResultsEnumerator.Current; string str = (string)current.Properties["distinguishedName"][0]; if (ADUtils.IsOfObjectClass(current, "group") || ADUtils.IsOfObjectClass(current, "user") || ADUtils.IsOfObjectClass(current, "foreignSecurityPrincipal")) { if (!this.recursive || !ADUtils.IsOfObjectClass(current, "group")) { if (!this.recursive || !ADUtils.IsOfObjectClass(current, "foreignSecurityPrincipal")) { if (this.usersVisited.ContainsKey(current.Properties["distinguishedName"][0].ToString())) { flag = true; } else { this.current = current; this.currentForeignDE = null; this.currentForeignPrincipal = null; this.usersVisited.Add(current.Properties["distinguishedName"][0].ToString(), true); } } else { if (!this.usersVisited.ContainsKey(current.Properties["distinguishedName"][0].ToString())) { this.foreignMembersCurrentGroup.Add(current.GetDirectoryEntry()); this.usersVisited.Add(current.Properties["distinguishedName"][0].ToString(), true); } flag = true; } } else { if (!this.groupsVisited.Contains(str) && !this.groupsToVisit.Contains(str)) { this.groupsToVisit.Add(str); } flag = true; } } else { flag = true; } } }while (flag); return(nextSearchResult); }
private bool MoveNextMemberEnum() { bool nextEnum; bool flag = false; bool flag1 = false; do { nextEnum = this.GetNextEnum(); flag = false; flag1 = false; if (!nextEnum) { if (!this.recursive || this.groupsToVisit.Count <= 0) { continue; } string item = this.groupsToVisit[0]; this.groupsToVisit.RemoveAt(0); this.groupsVisited.Add(item); DirectoryEntry directoryEntry = SDSUtils.BuildDirectoryEntry(this.BuildPathFromDN(item), this.storeCtx.Credentials, this.storeCtx.AuthTypes); this.storeCtx.InitializeNewDirectoryOptions(directoryEntry); this.membersQueue.Enqueue(new RangeRetriever(directoryEntry, "member", true)); flag = true; } else { DirectoryEntry directoryEntry1 = null; using (directoryEntry1) { if (!flag1 || directoryEntry1 == null) { string current = (string)this.membersEnum.Current; directoryEntry1 = SDSUtils.BuildDirectoryEntry(this.BuildPathFromDN(current), this.storeCtx.Credentials, this.storeCtx.AuthTypes); this.storeCtx.InitializeNewDirectoryOptions(directoryEntry1); this.storeCtx.LoadDirectoryEntryAttributes(directoryEntry1); if (ADUtils.IsOfObjectClass(directoryEntry1, "group") || ADUtils.IsOfObjectClass(directoryEntry1, "user") || ADUtils.IsOfObjectClass(directoryEntry1, "foreignSecurityPrincipal")) { if (!this.recursive || !ADUtils.IsOfObjectClass(directoryEntry1, "group")) { if (!this.recursive || !ADUtils.IsOfObjectClass(directoryEntry1, "foreignSecurityPrincipal")) { if (this.usersVisited.ContainsKey(directoryEntry1.Properties["distinguishedName"][0].ToString())) { flag = true; } else { this.current = directoryEntry1; this.currentForeignDE = null; this.currentForeignPrincipal = null; this.usersVisited.Add(directoryEntry1.Properties["distinguishedName"][0].ToString(), true); flag1 = false; } } else { if (!this.usersVisited.ContainsKey(directoryEntry1.Properties["distinguishedName"][0].ToString())) { this.foreignMembersCurrentGroup.Add(directoryEntry1); this.usersVisited.Add(directoryEntry1.Properties["distinguishedName"][0].ToString(), true); flag1 = false; } flag = true; } } else { if (!this.groupsVisited.Contains(current) && !this.groupsToVisit.Contains(current)) { this.groupsToVisit.Add(current); } flag = true; } } else { flag = true; } } } } }while (flag); return(nextEnum); }
private bool MoveNextLocal() { bool flag; do { flag = false; bool flag1 = this.membersEnumerator.MoveNext(); if (!flag1) { if (!this.recursive || this.groupsToVisit.Count <= 0) { continue; } string item = this.groupsToVisit[0]; this.groupsToVisit.RemoveAt(0); this.groupsVisited.Add(item); DirectoryEntry directoryEntry = SDSUtils.BuildDirectoryEntry(item, this.storeCtx.Credentials, this.storeCtx.AuthTypes); this.@group = (UnsafeNativeMethods.IADsGroup)directoryEntry.NativeObject; UnsafeNativeMethods.IADsMembers aDsMember = [email protected](); this.membersEnumerator = ((IEnumerable)aDsMember).GetEnumerator(); flag = true; } else { UnsafeNativeMethods.IADs current = (UnsafeNativeMethods.IADs) this.membersEnumerator.Current; byte[] numArray = (byte[])current.Get("objectSid"); SidType sidType = Utils.ClassifySID(numArray); if (sidType != SidType.FakeObject) { DirectoryEntry aDsPath = SDSUtils.BuildDirectoryEntry(this.storeCtx.Credentials, this.storeCtx.AuthTypes); if (sidType != SidType.RealObjectFakeDomain) { aDsPath.Path = current.ADsPath; } else { string str = current.ADsPath; UnsafeNativeMethods.Pathname pathname = new UnsafeNativeMethods.Pathname(); UnsafeNativeMethods.IADsPathname aDsPathname = (UnsafeNativeMethods.IADsPathname)pathname; aDsPathname.Set(str, 1); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("WinNT://"); stringBuilder.Append(this.storeCtx.MachineUserSuppliedName); stringBuilder.Append("/"); int numElements = aDsPathname.GetNumElements(); for (int i = numElements - 2; i >= 0; i--) { stringBuilder.Append(aDsPathname.GetElement(i)); stringBuilder.Append("/"); } stringBuilder.Remove(stringBuilder.Length - 1, 1); aDsPath.Path = stringBuilder.ToString(); } if (!this.IsLocalMember(numArray)) { this.foreignMembers.Add(aDsPath); flag = true; } else { if (!this.recursive || !SAMUtils.IsOfObjectClass(aDsPath, "Group")) { this.current = aDsPath; this.currentFakePrincipal = null; this.currentForeign = null; if (this.foreignResultSet != null) { this.foreignResultSet.Dispose(); } this.foreignResultSet = null; return(true); } else { if (!this.groupsVisited.Contains(aDsPath.Path) && !this.groupsToVisit.Contains(aDsPath.Path)) { this.groupsToVisit.Add(aDsPath.Path); } flag = true; } } } else { this.currentFakePrincipal = this.storeCtx.ConstructFakePrincipalFromSID(numArray); this.current = null; this.currentForeign = null; if (this.foreignResultSet != null) { this.foreignResultSet.Dispose(); } this.foreignResultSet = null; return(true); } } }while (flag); return(false); }