| File: System\DirectoryServices\AccountManagement\AD\TokenGroupsSet.cs | Web Access |
| Project: src\runtime\src\libraries\System.DirectoryServices.AccountManagement\src\System.DirectoryServices.AccountManagement.csproj (System.DirectoryServices.AccountManagement) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.DirectoryServices; using System.Security.Principal; using System.Text; namespace System.DirectoryServices.AccountManagement { internal sealed class TokenGroupSet : ResultSet { internal TokenGroupSet( string userDN, ADStoreCtx storeCtx, bool readDomainGroups) { _principalDN = userDN; _storeCtx = storeCtx; _attributeToQuery = readDomainGroups ? "tokenGroups" : "tokenGroupsGlobalAndUniversal"; GlobalDebug.WriteLineIf(GlobalDebug.Info, "TokenGroupSet", "TokenGroupSet: userDN={0}", userDN); } private readonly string _principalDN; private readonly ADStoreCtx _storeCtx; private bool _atBeginning = true; private DirectoryEntry _current; // current member of the group (or current group of the user) private IEnumerator _tokenGroupsEnum; private SecurityIdentifier _currentSID; private bool _disposed; private readonly string _attributeToQuery; // Return the principal we're positioned at as a Principal object. // Need to use our StoreCtx's GetAsPrincipal to convert the native object to a Principal internal override object CurrentAsPrincipal { get { if (_currentSID != null) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "TokenGroupSet", "CurrentAsPrincipal: using current"); string SidBindingString = $"<SID={Utils.SecurityIdentifierToLdapHexBindingString(_currentSID)}>"; DirectoryEntry currentDE = SDSUtils.BuildDirectoryEntry( BuildPathFromDN(SidBindingString), _storeCtx.Credentials, _storeCtx.AuthTypes); _storeCtx.InitializeNewDirectoryOptions(currentDE); _storeCtx.LoadDirectoryEntryAttributes(currentDE); return ADUtils.DirectoryEntryAsPrincipal(currentDE, _storeCtx); } return null; } } // 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; } // Resets the enumerator to before the first result in the set. This potentially can be an expensive // operation, e.g., if doing a paged search, may need to re-retrieve the first page of results. // As a special case, if the ResultSet is already at the very beginning, this is guaranteed to be // a no-op. internal override void Reset() { if (_atBeginning) return; _tokenGroupsEnum.Reset(); } // IDisposable implementation public override void Dispose() { try { if (!_disposed) { _current?.Dispose(); _disposed = true; } } finally { base.Dispose(); } } private string BuildPathFromDN(string dn) { string userSuppliedServername = _storeCtx.UserSuppliedServerName; UnsafeNativeMethods.Pathname pathCracker = new UnsafeNativeMethods.Pathname(); UnsafeNativeMethods.IADsPathname pathName = (UnsafeNativeMethods.IADsPathname)pathCracker; pathName.EscapedMode = 2 /* ADS_ESCAPEDMODE_ON */; pathName.Set(dn, 4 /* ADS_SETTYPE_DN */); string escapedDn = pathName.Retrieve(7 /* ADS_FORMAT_X500_DN */); if (userSuppliedServername.Length > 0) return "LDAP://" + _storeCtx.UserSuppliedServerName + "/" + escapedDn; else return "LDAP://" + escapedDn; } } }