// // Internal constructors // internal ValueCollectionEnumerator(TrackedCollection <T> trackingList, List <TrackedCollection <T> .ValueEl> combinedValues) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "ValueCollectionEnumerator", "Ctor"); _inner = new TrackedCollectionEnumerator <T>("ValueCollectionEnumerator", trackingList, combinedValues); }
// 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); } }
protected void TranslateSids(string target, IntPtr[] pSids) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "SidList: processing {0} SIDs", pSids.Length); // if there are no SIDs to translate return if (pSids.Length == 0) { return; } // Build the list of SIDs to resolve int sidCount = pSids.Length; // Translate the SIDs in bulk IntPtr pOA = IntPtr.Zero; IntPtr pPolicyHandle = IntPtr.Zero; IntPtr pDomains = IntPtr.Zero; UnsafeNativeMethods.LSA_TRUST_INFORMATION[] domains; IntPtr pNames = IntPtr.Zero; UnsafeNativeMethods.LSA_TRANSLATED_NAME[] names; try { // // Get the policy handle // UnsafeNativeMethods.LSA_OBJECT_ATTRIBUTES oa = new UnsafeNativeMethods.LSA_OBJECT_ATTRIBUTES(); pOA = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(UnsafeNativeMethods.LSA_OBJECT_ATTRIBUTES))); Marshal.StructureToPtr(oa, pOA, false); int err = 0; if (target == null) { err = UnsafeNativeMethods.LsaOpenPolicy( IntPtr.Zero, pOA, 0x800, // POLICY_LOOKUP_NAMES ref pPolicyHandle); } else { // Build an entry. Note that LSA_UNICODE_STRING.length is in bytes, // while PtrToStringUni expects a length in characters. UnsafeNativeMethods.LSA_UNICODE_STRING_Managed lsaTargetString = new UnsafeNativeMethods.LSA_UNICODE_STRING_Managed(); lsaTargetString.buffer = target; lsaTargetString.length = (ushort)(target.Length * 2); lsaTargetString.maximumLength = lsaTargetString.length; IntPtr lsaTargetPr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(UnsafeNativeMethods.LSA_UNICODE_STRING))); try { Marshal.StructureToPtr(lsaTargetString, lsaTargetPr, false); err = UnsafeNativeMethods.LsaOpenPolicy( lsaTargetPr, pOA, 0x800, // POLICY_LOOKUP_NAMES ref pPolicyHandle); } finally { if (lsaTargetPr != IntPtr.Zero) { UnsafeNativeMethods.LSA_UNICODE_STRING lsaTargetUnmanagedPtr = (UnsafeNativeMethods.LSA_UNICODE_STRING)Marshal.PtrToStructure(lsaTargetPr, typeof(UnsafeNativeMethods.LSA_UNICODE_STRING)); if (lsaTargetUnmanagedPtr.buffer != IntPtr.Zero) { Marshal.FreeHGlobal(lsaTargetUnmanagedPtr.buffer); lsaTargetUnmanagedPtr.buffer = IntPtr.Zero; } Marshal.FreeHGlobal(lsaTargetPr); } } } if (err != 0) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "AuthZSet", "SidList: couldn't get policy handle, err={0}", err); throw new PrincipalOperationException(String.Format(CultureInfo.CurrentCulture, StringResources.AuthZErrorEnumeratingGroups, SafeNativeMethods.LsaNtStatusToWinError(err))); } Debug.Assert(pPolicyHandle != IntPtr.Zero); // // Translate the SIDs // err = UnsafeNativeMethods.LsaLookupSids( pPolicyHandle, sidCount, pSids, out pDomains, out pNames); // ignore error STATUS_SOME_NOT_MAPPED = 0x00000107 and // STATUS_NONE_MAPPED = 0xC0000073 if (err != 0 && err != 263 && err != -1073741709) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "AuthZSet", "SidList: LsaLookupSids failed, err={0}", err); throw new PrincipalOperationException(String.Format(CultureInfo.CurrentCulture, StringResources.AuthZErrorEnumeratingGroups, SafeNativeMethods.LsaNtStatusToWinError(err))); } // // Get the group names in managed form // names = new UnsafeNativeMethods.LSA_TRANSLATED_NAME[sidCount]; IntPtr pCurrentName = pNames; for (int i = 0; i < sidCount; i++) { names[i] = (UnsafeNativeMethods.LSA_TRANSLATED_NAME) Marshal.PtrToStructure(pCurrentName, typeof(UnsafeNativeMethods.LSA_TRANSLATED_NAME)); pCurrentName = new IntPtr(pCurrentName.ToInt64() + Marshal.SizeOf(typeof(UnsafeNativeMethods.LSA_TRANSLATED_NAME))); } // // Get the domain names in managed form // // Extract LSA_REFERENCED_DOMAIN_LIST.Entries UnsafeNativeMethods.LSA_REFERENCED_DOMAIN_LIST referencedDomains = (UnsafeNativeMethods.LSA_REFERENCED_DOMAIN_LIST)Marshal.PtrToStructure(pDomains, typeof(UnsafeNativeMethods.LSA_REFERENCED_DOMAIN_LIST)); int domainCount = referencedDomains.entries; // Extract LSA_REFERENCED_DOMAIN_LIST.Domains, by iterating over the array and marshalling // each native LSA_TRUST_INFORMATION into a managed LSA_TRUST_INFORMATION. domains = new UnsafeNativeMethods.LSA_TRUST_INFORMATION[domainCount]; IntPtr pCurrentDomain = referencedDomains.domains; for (int i = 0; i < domainCount; i++) { domains[i] = (UnsafeNativeMethods.LSA_TRUST_INFORMATION)Marshal.PtrToStructure(pCurrentDomain, typeof(UnsafeNativeMethods.LSA_TRUST_INFORMATION)); pCurrentDomain = new IntPtr(pCurrentDomain.ToInt64() + Marshal.SizeOf(typeof(UnsafeNativeMethods.LSA_TRUST_INFORMATION))); } GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "SidList: got {0} groups in {1} domains", sidCount, domainCount); // // Build the list of entries // Debug.Assert(names.Length == sidCount); for (int i = 0; i < names.Length; i++) { UnsafeNativeMethods.LSA_TRANSLATED_NAME name = names[i]; // Build an entry. Note that LSA_UNICODE_STRING.length is in bytes, // while PtrToStringUni expects a length in characters. SidListEntry entry = new SidListEntry(); Debug.Assert(name.name.length % 2 == 0); entry.name = Marshal.PtrToStringUni(name.name.buffer, name.name.length / 2); // Get the domain associated with this name Debug.Assert(name.domainIndex < domains.Length); if (name.domainIndex >= 0) { UnsafeNativeMethods.LSA_TRUST_INFORMATION domain = domains[name.domainIndex]; Debug.Assert(domain.name.length % 2 == 0); entry.sidIssuerName = Marshal.PtrToStringUni(domain.name.buffer, domain.name.length / 2); } entry.pSid = pSids[i]; _entries.Add(entry); } // Sort the list so they are oriented by the issuer name. // this.entries.Sort( new SidListComparer()); } finally { if (pDomains != IntPtr.Zero) { UnsafeNativeMethods.LsaFreeMemory(pDomains); } if (pNames != IntPtr.Zero) { UnsafeNativeMethods.LsaFreeMemory(pNames); } if (pPolicyHandle != IntPtr.Zero) { UnsafeNativeMethods.LsaClose(pPolicyHandle); } if (pOA != IntPtr.Zero) { Marshal.FreeHGlobal(pOA); } } }
public bool Remove(Principal principal) { CheckDisposed(); if (principal == null) { throw new ArgumentNullException("principal"); } // Ask the StoreCtx to verify that this member can be removed. Right now, the only // reason it couldn't is if it's actually a member by virtue of its primaryGroupId // pointing to this group. // // If storeCtxToUse == null, then we must be unpersisted, in which case there clearly // can't be any such primary group members pointing to this group on the store. StoreCtx storeCtxToUse = _owningGroup.GetStoreCtxToUse(); string explanation; Debug.Assert(storeCtxToUse != null || _owningGroup.unpersisted == true); if ((storeCtxToUse != null) && (!storeCtxToUse.CanGroupMemberBeRemoved(_owningGroup, principal, out explanation))) { throw new InvalidOperationException(explanation); } bool removed = false; // If the value was previously inserted, we just remove it from insertedValuesPending. if (_insertedValuesPending.Contains(principal)) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollection", "Remove: removing from insertedValuesPending"); MarkChange(); _insertedValuesPending.Remove(principal); removed = true; // If they did a Remove(x) --> Save() --> Add(x) --> Remove(x), we'll end up with x in neither // the ResultSet or the removedValuesCompleted list. This is bad. Avoid that by adding x // back to the removedValuesCompleted list here. // // At worst, we end up with x on the removedValuesCompleted list even though it's not even in // resultSet. That's not a problem. The only thing we use the removedValuesCompleted list for // is deciding which values in resultSet to skip, anyway. if (!_removedValuesCompleted.Contains(principal)) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollection", "Remove: adding to removedValuesCompleted"); _removedValuesCompleted.Add(principal); } } else { // They're trying to remove an already-persisted value. We add it to the // removedValues list. Then, if it's already been loaded into insertedValuesCompleted, // we remove it from insertedValuesCompleted. removed = Contains(principal); GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollection", "Remove: making it a pending remove, removed={0}", removed); if (removed) { MarkChange(); _removedValuesPending.Add(principal); // in case it's the result of a previous-but-already-committed insert _insertedValuesCompleted.Remove(principal); } } return(removed); }
// computerInfoLock must be held coming in here private void LoadComputerInfo() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "LoadComputerInfo"); Debug.Assert(_ctxBase != null); Debug.Assert(SAMUtils.IsOfObjectClass(_ctxBase, "Computer")); // // Target OS version // int versionMajor; int versionMinor; if (!SAMUtils.GetOSVersion(_ctxBase, out versionMajor, out versionMinor)) { throw new PrincipalOperationException(SR.SAMStoreCtxUnableToRetrieveVersion); } Debug.Assert(versionMajor > 0); Debug.Assert(versionMinor >= 0); if (versionMajor >= 6) // 6.0 == Longhorn { _isLSAM = true; } else { _isLSAM = false; } GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "LoadComputerInfo: ver={0}.{1}", versionMajor, versionMinor); // // Machine user-supplied name // // This ADSI property stores the machine name as supplied by the user in the ADsPath. // It could be a flat name or a DNS name. if (_ctxBase.Properties["Name"].Count > 0) { Debug.Assert(_ctxBase.Properties["Name"].Count == 1); _machineUserSuppliedName = (string)_ctxBase.Properties["Name"].Value; GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "LoadComputerInfo: machineUserSuppliedName={0}", _machineUserSuppliedName); } else { throw new PrincipalOperationException(SR.SAMStoreCtxUnableToRetrieveMachineName); } // // Machine flat name // IntPtr buffer = IntPtr.Zero; try { // This function takes in a flat or DNS name, and returns the flat name of the computer int err = UnsafeNativeMethods.NetWkstaGetInfo(_machineUserSuppliedName, 100, ref buffer); if (err == 0) { UnsafeNativeMethods.WKSTA_INFO_100 wkstaInfo = (UnsafeNativeMethods.WKSTA_INFO_100)Marshal.PtrToStructure(buffer, typeof(UnsafeNativeMethods.WKSTA_INFO_100)); _machineFlatName = wkstaInfo.wki100_computername; GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "LoadComputerInfo: machineFlatName={0}", _machineFlatName); } else { throw new PrincipalOperationException( SR.Format( SR.SAMStoreCtxUnableToRetrieveFlatMachineName, err)); } } finally { if (buffer != IntPtr.Zero) { UnsafeNativeMethods.NetApiBufferFree(buffer); } } }
internal override void Reset() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "Reset"); _currentGroup = -1; }
public bool MoveNext() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "Entering MoveNext"); CheckDisposed(); CheckChanged(); // We previously reached the end, nothing more to do if (_endReached) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: endReached"); return(false); } lock (_resultSet) { if (_currentMode == CurrentEnumeratorMode.None) { // At the very beginning // In case this ResultSet was previously used with another PrincipalCollectionEnumerator instance // (e.g., two foreach loops in a row) _resultSet.Reset(); if (!_memberCollection.Cleared && !_memberCollection.ClearCompleted) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: None mode, starting with existing values"); // Start by enumerating the existing values in the store _currentMode = CurrentEnumeratorMode.ResultSet; _enumerator = null; } else { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: None mode, skipping existing values"); // The member collection was cleared. Skip the ResultSet phase _currentMode = CurrentEnumeratorMode.InsertedValuesCompleted; _enumerator = (IEnumerator <Principal>)_insertedValuesCompleted.GetEnumerator(); } } Debug.Assert(_resultSet != null); if (_currentMode == CurrentEnumeratorMode.ResultSet) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: ResultSet mode"); bool needToRepeat = false; do { bool f = _resultSet.MoveNext(); if (f) { Principal principal = (Principal)_resultSet.CurrentAsPrincipal; if (_removedValuesCompleted.Contains(principal) || _removedValuesPending.Contains(principal)) { // It's a value that's been removed (either a pending remove that hasn't completed, or a remove // that completed _after_ we loaded the ResultSet from the store). GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: ResultSet mode, found remove, skipping"); needToRepeat = true; continue; } else if (_insertedValuesCompleted.Contains(principal) || _insertedValuesPending.Contains(principal)) { // insertedValuesCompleted: We must have gotten the ResultSet after the inserted committed. // We don't want to return // the principal twice, so we'll skip it here and later return it in // the CurrentEnumeratorMode.InsertedValuesCompleted mode. // // insertedValuesPending: The principal must have been originally in the ResultSet, but then // removed, saved, and re-added, with the re-add still pending. GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: ResultSet mode, found insert, skipping"); needToRepeat = true; continue; } else { needToRepeat = false; _current = principal; return(true); } } else { // No more values left to retrieve. Now try the insertedValuesCompleted list. GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: ResultSet mode, moving to InsValuesComp mode"); _currentMode = CurrentEnumeratorMode.InsertedValuesCompleted; _enumerator = (IEnumerator <Principal>)_insertedValuesCompleted.GetEnumerator(); needToRepeat = false; } }while (needToRepeat); } // These are values whose insertion has completed, but after we already loaded the ResultSet from the store. if (_currentMode == CurrentEnumeratorMode.InsertedValuesCompleted) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: InsValuesComp mode"); bool f = _enumerator.MoveNext(); if (f) { _current = _enumerator.Current; return(true); } else { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: InsValuesComp mode, moving to InsValuesPend mode"); _currentMode = CurrentEnumeratorMode.InsertedValuesPending; _enumerator = (IEnumerator <Principal>)_insertedValuesPending.GetEnumerator(); } } // These are values whose insertion has not yet been committed to the store. if (_currentMode == CurrentEnumeratorMode.InsertedValuesPending) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: InsValuesPend mode"); bool f = _enumerator.MoveNext(); if (f) { _current = _enumerator.Current; return(true); } else { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollectionEnumerator", "MoveNext: InsValuesPend mode, nothing left"); _endReached = true; return(false); } } } Debug.Fail(String.Format(CultureInfo.CurrentCulture, "PrincipalCollectionEnumerator.MoveNext: fell off end of function, mode = {0}", _currentMode.ToString())); return(false); }
public void Save(PrincipalContext context) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "Principal", "Entering Save(Context)"); // Make sure we're not disposed or deleted. CheckDisposedOrDeleted(); // Make sure we're not a fake principal CheckFakePrincipal(); // We must have a PrincipalContext to save into. This should always be the case, unless we're unpersisted // and they never set a PrincipalContext. if (context == null) { Debug.Assert(this.unpersisted); throw new InvalidOperationException(SR.NullArguments); } if (context.ContextType == ContextType.Machine || _ctx.ContextType == ContextType.Machine) { throw new InvalidOperationException(SR.SaveToNotSupportedAgainstMachineStore); } // If the user is trying to save to the same context we are already set to then just save the changes if (context == _ctx) { Save(); return; } // If we already have a context set on this object then make sure the new // context is of the same type. if (context.ContextType != _ctx.ContextType) { Debug.Assert(this.unpersisted); throw new InvalidOperationException(SR.SaveToMustHaveSamecontextType); } StoreCtx originalStoreCtx = GetStoreCtxToUse(); _ctx = context; // Call the appropriate operation depending on whether this is an insert or update StoreCtx newStoreCtx = GetStoreCtxToUse(); Debug.Assert(newStoreCtx != null); // since we know this.ctx isn't null Debug.Assert(originalStoreCtx != null); // since we know this.ctx isn't null if (this.unpersisted) { // We have an unpersisted principal so we just want to create a principal in the new store. GlobalDebug.WriteLineIf(GlobalDebug.Info, "Principal", "Save(context): inserting new principal of type {0} using {1}", this.GetType(), newStoreCtx.GetType()); Debug.Assert(newStoreCtx == _ctx.ContextForType(this.GetType())); newStoreCtx.Insert(this); this.unpersisted = false; // once we persist, we're no longer in the unpersisted state } else { // We have a principal that already exists. We need to move it to the new store. GlobalDebug.WriteLineIf(GlobalDebug.Info, "Principal", "Save(context): Moving principal of type {0} using {1}", this.GetType(), newStoreCtx.GetType()); // we are now saving to a new store so this principal is unpersisted. this.unpersisted = true; // If the user has modified the name save away the current name so // if the move succeeds and the update fails we will move the item back to the original // store with the original name. bool nameModified = _nameChanged == LoadState.Changed; string previousName = null; if (nameModified) { string newName = _name; _ctx.QueryCtx.Load(this, PropertyNames.PrincipalName); previousName = _name; this.Name = newName; } newStoreCtx.Move(originalStoreCtx, this); try { this.unpersisted = false; // once we persist, we're no longer in the unpersisted state newStoreCtx.Update(this); } catch (System.SystemException e) { try { GlobalDebug.WriteLineIf(GlobalDebug.Error, "Principal", "Save(context):, Update Failed (attempting to move back) Exception {0} ", e.Message); if (nameModified) { this.Name = previousName; } originalStoreCtx.Move(newStoreCtx, this); GlobalDebug.WriteLineIf(GlobalDebug.Info, "Principal", "Move back succeeded"); } catch (System.SystemException deleteFail) { // The move back failed. Just continue we will throw the original exception below. GlobalDebug.WriteLineIf(GlobalDebug.Error, "Principal", "Save(context):, Move back Failed {0} ", deleteFail.Message); } if (e is System.Runtime.InteropServices.COMException) { throw ExceptionHelper.GetExceptionFromCOMException((System.Runtime.InteropServices.COMException)e); } else { throw; } } } _ctx.QueryCtx = newStoreCtx; // so Updates go to the right StoreCtx }
static internal void InsertPrincipal( Principal p, StoreCtx storeCtx, GroupMembershipUpdater updateGroupMembership, NetCred credentials, AuthenticationTypes authTypes, bool needToSetPassword) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SDSUtils", "Entering InsertPrincipal"); Debug.Assert(storeCtx != null); Debug.Assert(storeCtx is ADStoreCtx || storeCtx is SAMStoreCtx); Debug.Assert(p != null); if ((!(p is UserPrincipal)) && (!(p is GroupPrincipal)) && (!(p is AuthenticablePrincipal)) && (!(p is ComputerPrincipal))) { // It's not a type of Principal that we support GlobalDebug.WriteLineIf(GlobalDebug.Warn, "SDSUtils", "InsertPrincipal: Bad principal type:" + p.GetType().ToString()); throw new InvalidOperationException(SR.Format(SR.StoreCtxUnsupportedPrincipalTypeForSave, p.GetType())); } // Commit the properties SDSUtils.ApplyChangesToDirectory( p, storeCtx, updateGroupMembership, credentials, authTypes ); // Handle any saved-off operations // For SAM, we set password elsewhere prior to creating the principal, so needToSetPassword == false // For AD, we have to set the password after creating the principal, so needToSetPassword == true if (needToSetPassword && p.GetChangeStatusForProperty(PropertyNames.PwdInfoPassword)) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SDSUtils", "InsertPrincipal: Setting password"); // Only AuthenticablePrincipals can have PasswordInfo Debug.Assert(p is AuthenticablePrincipal); string password = (string)p.GetValueForProperty(PropertyNames.PwdInfoPassword); Debug.Assert(password != null); // if null, PasswordInfo should not have indicated it was changed storeCtx.SetPassword((AuthenticablePrincipal)p, password); } if (p.GetChangeStatusForProperty(PropertyNames.PwdInfoExpireImmediately)) { // Only AuthenticablePrincipals can have PasswordInfo Debug.Assert(p is AuthenticablePrincipal); bool expireImmediately = (bool)p.GetValueForProperty(PropertyNames.PwdInfoExpireImmediately); if (expireImmediately) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SDSUtils", "InsertPrincipal: Setting pwd expired"); storeCtx.ExpirePassword((AuthenticablePrincipal)p); } } }
private bool MoveNextForeign() { bool needToRetry; do { needToRetry = false; GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextForeign: foreignMembers count={0}", _foreignMembers.Count); if (_foreignMembers.Count > 0) { // foreignDE is a DirectoryEntry in _this_ store representing a principal in another store DirectoryEntry foreignDE = _foreignMembers[0]; _foreignMembers.RemoveAt(0); GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextForeign: foreignDE={0}", foreignDE.Path); // foreignPrincipal is a principal from _another_ store (e.g., it's backed by an ADStoreCtx) Principal foreignPrincipal = _storeCtx.ResolveCrossStoreRefToPrincipal(foreignDE); // If we're not enumerating recursively, return the principal. // If we are enumerating recursively, and it's a group, save it off for later. if (!_recursive || !(foreignPrincipal is GroupPrincipal)) { // Return the principal. GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextForeign: setting currentForeign to {0}", foreignDE.Path); _current = null; _currentFakePrincipal = null; _currentForeign = foreignPrincipal; if (_foreignResultSet != null) { _foreignResultSet.Dispose(); } _foreignResultSet = null; return(true); } else { // Save off the group for recursive expansion, and go on to the next principal. GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextForeign: adding {0} to foreignGroups", foreignDE.Path); _foreignGroups.Add((GroupPrincipal)foreignPrincipal); needToRetry = true; continue; } } if (_foreignResultSet == null && _foreignGroups.Count > 0) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextForeign: getting foreignResultSet (foreignGroups count={0})", _foreignGroups.Count); // We're expanding recursively, and either (1) we're immediately before // the recursive expansion of the first foreign group, or (2) we just completed // the recursive expansion of a foreign group, and now are moving on to the next. Debug.Assert(_recursive == true); // Pull off a foreign group to expand. GroupPrincipal foreignGroup = _foreignGroups[0]; _foreignGroups.RemoveAt(0); // Since it's a foreign group, we don't know how to enumerate its members. So we'll // ask the group, through its StoreCtx, to do it for us. Effectively, we'll end up acting // as a proxy to the foreign group's ResultSet. _foreignResultSet = foreignGroup.GetStoreCtxToUse().GetGroupMembership(foreignGroup, true); } // We're either just beginning the recursive expansion of a foreign group, or we're continuing the expansion // that we started on a previous call to MoveNext(). if (_foreignResultSet != null) { Debug.Assert(_recursive == true); bool f = _foreignResultSet.MoveNext(); if (f) { // By setting current, currentFakePrincipal, and currentForeign to null, // CurrentAsPrincipal/CurrentAsIdentityReference will know to proxy out to foreignResultSet. GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextForeign: using foreignResultSet"); _current = null; _currentFakePrincipal = null; _currentForeign = null; return(true); } // Ran out of members in the foreign group, is there another foreign group remaining that we need // to expand? if (_foreignGroups.Count > 0) { // Yes, there is. Null out the foreignResultSet so we'll pull out the next foreign group // the next time around the loop. GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextForeign: ran out of members, using next foreignResultSet"); _foreignResultSet.Dispose(); _foreignResultSet = null; Debug.Assert(_foreignMembers.Count == 0); needToRetry = true; } else { // No, there isn't. Nothing left to do. We set foreignResultSet to null here just // to leave things in a clean state --- it shouldn't really be necessary. GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "MoveNextForeign: ran out of members, nothing more to do"); _foreignResultSet.Dispose(); _foreignResultSet = null; } } }while (needToRetry); return(false); }
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); }
// Must be called inside of lock(domainInfoLock) protected override void LoadDomainInfo() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "LoadComputerInfo"); Debug.Assert(this.ctxBase != null); // // DNS Domain Name // this.dnsHostName = ADUtils.GetServerName(this.ctxBase); // Treat the user supplied server name as the domain and forest name... this.domainFlatName = userSuppliedServerName; this.forestDnsName = userSuppliedServerName; this.domainDnsName = userSuppliedServerName; // // Find the partition in which the supplied ctxBase belongs by comparing it with the list of partitions hosted by this // LDS (ADAM) instance. // using (DirectoryEntry rootDse = new DirectoryEntry("LDAP://" + this.userSuppliedServerName + "/rootDse", "", "", AuthenticationTypes.Anonymous)) { string ctxBaseDN = (string)this.ctxBase.Properties["distinguishedName"][0]; int maxMatchLength = -1; foreach (string partitionDN in rootDse.Properties["namingContexts"]) { if ((partitionDN.Length > maxMatchLength) && ctxBaseDN.EndsWith(partitionDN, StringComparison.OrdinalIgnoreCase)) { maxMatchLength = partitionDN.Length; this.contextBasePartitionDN = partitionDN; } } } // // User supplied name // UnsafeNativeMethods.Pathname pathCracker = new UnsafeNativeMethods.Pathname(); UnsafeNativeMethods.IADsPathname pathName = (UnsafeNativeMethods.IADsPathname)pathCracker; pathName.Set(this.ctxBase.Path, 1 /* ADS_SETTYPE_FULL */); try { this.userSuppliedServerName = pathName.Retrieve(9 /*ADS_FORMAT_SERVER */); GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "LoadComputerInfo: using user-supplied name {0}", this.userSuppliedServerName); } catch (COMException e) { if (((uint)e.ErrorCode) == ((uint)0x80005000)) // E_ADS_BAD_PATHNAME { // Serverless path GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "LoadComputerInfo: using empty string as user-supplied name"); this.userSuppliedServerName = ""; } else { GlobalDebug.WriteLineIf(GlobalDebug.Error, "ADStoreCtx", "LoadComputerInfo: caught COMException {0} {1} looking for user-supplied name", e.ErrorCode, e.Message); throw; } } }
// // Internal Constructors // // Constructs a enumerator to enumerate over the supplied of ResultSet // Note that resultSet can be null internal FindResultEnumerator(ResultSet resultSet) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "FindResultEnumerator", "Ctor"); _resultSet = resultSet; }
private bool IsLocalMember(byte[] sid) { // BUILTIN SIDs are local, but we can't determine that by looking at domainName SidType sidType = Utils.ClassifySID(sid); Debug.Assert(sidType != SidType.FakeObject); if (sidType == SidType.RealObjectFakeDomain) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "IsLocalMember: fake domain, SID={0}", Utils.ByteArrayToString(sid)); return(true); } bool isLocal = false; // Ask the OS to resolve the SID to its target. int accountUsage = 0; string name; string domainName; int err = Utils.LookupSid( _storeCtx.MachineUserSuppliedName, _storeCtx.Credentials, sid, out name, out domainName, out accountUsage); if (err != 0) { GlobalDebug.WriteLineIf(GlobalDebug.Error, "SAMMembersSet", "IsLocalMember: LookupSid failed, sid={0}, server={1}, err={2}", Utils.ByteArrayToString(sid), _storeCtx.MachineUserSuppliedName, err); throw new PrincipalOperationException( String.Format(CultureInfo.CurrentCulture, SR.SAMStoreCtxErrorEnumeratingGroup, err)); } if (String.Compare(_storeCtx.MachineFlatName, domainName, StringComparison.OrdinalIgnoreCase) == 0) { isLocal = true; } GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMMembersSet", "IsLocalMember: sid={0}, isLocal={1}, domainName={2}", Utils.ByteArrayToString(sid), isLocal, domainName); return(isLocal); }
public bool MoveNext() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "RangeRetriever", "Entering MoveNext"); if (_endReached) { return(false); } // Determine if we have already visited the current object. if (_currentIndex < InnerList.Count) { _currentResult = InnerList[_currentIndex]; _currentIndex++; return(true); } else if (_cacheFilled) { // We have just walked the entire cache. No need to visit the directory // since we cached everything that is out there. return(false); } if (!_endReached && _currentEnumerator == null) { // First time we're being called GlobalDebug.WriteLineIf(GlobalDebug.Info, "RangeRetriever", "MoveNext: first time"); _currentEnumerator = GetNextChunk(); if (_currentEnumerator == null) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "RangeRetriever", "MoveNext: got null enumerator for first time"); _endReached = true; } } if (_endReached) { return(false); } bool needToRetry; bool f; do { needToRetry = false; f = _currentEnumerator.MoveNext(); if (f) { // Got a result, prepare to return it _currentResult = _currentEnumerator.Current; GlobalDebug.WriteLineIf(GlobalDebug.Info, "RangeRetriever", "MoveNext: got a result '{0}'", _currentResult.ToString()); } else { // Ran out of results in this range, try the next chunk GlobalDebug.WriteLineIf(GlobalDebug.Info, "RangeRetriever", "MoveNext: retrieving next range"); _currentEnumerator = GetNextChunk(); if (_currentEnumerator == null) { // No more chunks remain GlobalDebug.WriteLineIf(GlobalDebug.Info, "RangeRetriever", "MoveNext: end reached"); _endReached = true; _cacheFilled = _cacheValues; //Set cachedFilled boolean to cacheValues flags. } else { // Got the next chunk, try pulling a result out of it needToRetry = true; } } }while (needToRetry); if (f) { if (_cacheValues) { InnerList.Add(_currentResult); } _currentIndex++; } return(f); }
// These are verbatim C# string ( @ ) where \ is actually \\ // Input Matches RegEx // ----- ------- ----- // * any ( 1 or more ) .* // // \* * \* // \ \ \\ // ( ( \( // \( ( \( // ) ) \) // \) ) \) // \\ \ \\ // x x x (where x is anything else) // Add \G to beginning and \z to the end so that the regex will be anchored at the either end of the property // \G = Regex must match at the beginning // \z = Regex must match at the end // ( ) * are special characters to Regex so they must be escaped with \\. We support these from teh user either raw or already escaped. // Any other \ in the input string are translated to an actual \ in the match because we cannot determine usage except for ( ) * // The user cannot enter any regex escape sequence they would like in their match string. Only * is supported. // // @"c:\Home" -> "c:\\\\Home" OR @"c:\\Home" // // internal static string PAPIQueryToRegexString(string papiString) { StringBuilder sb = new StringBuilder(papiString.Length); sb.Append(@"\G"); bool escapeMode = false; foreach (char c in papiString) { if (escapeMode == false) { switch (c) { case '(': sb.Append(@"\("); // ( --> \( break; case ')': sb.Append(@"\)"); // ) --> \) break; case '\\': escapeMode = true; break; case '*': sb.Append(@".*"); // * --> .* break; default: sb.Append(c); // x --> x break; } } else { escapeMode = false; switch (c) { case '(': sb.Append(@"\("); // \( --> \( break; case ')': sb.Append(@"\)"); // \) --> \) break; case '*': sb.Append(@"\*"); // \* --> \* break; case '\\': sb.Append(@"\\\\"); // \\ --> \\ break; default: sb.Append(@"\\"); sb.Append(c); // \x --> \x break; } } } // There was a '\\' but no character after it because we were at the // end of the string. // Append '\\\\' to match the '\\'. if (escapeMode) { sb.Append(@"\\"); } GlobalDebug.WriteLineIf( GlobalDebug.Info, "SAMUtils", "PAPIQueryToRegexString: mapped '{0}' to '{1}'", papiString, sb.ToString()); sb.Append(@"\z"); return(sb.ToString()); }
internal AuthZSet( byte[] userSid, NetCred credentials, ContextOptions contextOptions, string flatUserAuthority, StoreCtx userStoreCtx, object userCtxBase) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "AuthZSet: SID={0}, authority={1}, storeCtx={2}", Utils.ByteArrayToString(userSid), flatUserAuthority, userStoreCtx.GetType()); _userType = userStoreCtx.OwningContext.ContextType; _userCtxBase = userCtxBase; _userStoreCtx = userStoreCtx; _credentials = credentials; _contextOptions = contextOptions; // flatUserAuthority is flat domain name if userType == Domain, // flat host name if userType == LocalMachine _flatUserAuthority = flatUserAuthority; // Preload the PrincipalContext cache with the user's PrincipalContext _contexts[flatUserAuthority] = userStoreCtx.OwningContext; IntPtr hUser = IntPtr.Zero; // // Get the SIDs of the groups to which the user belongs // IntPtr pClientContext = IntPtr.Zero; IntPtr pResManager = IntPtr.Zero; IntPtr pBuffer = IntPtr.Zero; try { UnsafeNativeMethods.LUID luid = new UnsafeNativeMethods.LUID(); luid.low = 0; luid.high = 0; _psMachineSid = new SafeMemoryPtr(Utils.GetMachineDomainSid()); _psUserSid = new SafeMemoryPtr(Utils.ConvertByteArrayToIntPtr(userSid)); bool f; int lastError = 0; GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "Initializing resource manager"); // Create a resource manager f = UnsafeNativeMethods.AuthzInitializeResourceManager( UnsafeNativeMethods.AUTHZ_RM_FLAG.AUTHZ_RM_FLAG_NO_AUDIT, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, null, out pResManager ); if (f) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "Getting ctx from SID"); // Construct a context for the user based on the user's SID f = UnsafeNativeMethods.AuthzInitializeContextFromSid( 0, // default flags _psUserSid.DangerousGetHandle(), pResManager, IntPtr.Zero, luid, IntPtr.Zero, out pClientContext ); if (f) { int bufferSize = 0; GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "Getting info from ctx"); // Extract the group SIDs from the user's context. Determine the size of the buffer we need. f = UnsafeNativeMethods.AuthzGetInformationFromContext( pClientContext, 2, // AuthzContextInfoGroupsSids 0, out bufferSize, IntPtr.Zero ); if (!f && (bufferSize > 0) && (Marshal.GetLastWin32Error() == 122) /*ERROR_INSUFFICIENT_BUFFER*/) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "Getting info from ctx (size={0})", bufferSize); Debug.Assert(bufferSize > 0); // Set up the needed buffer pBuffer = Marshal.AllocHGlobal(bufferSize); // Extract the group SIDs from the user's context, into our buffer.0 f = UnsafeNativeMethods.AuthzGetInformationFromContext( pClientContext, 2, // AuthzContextInfoGroupsSids bufferSize, out bufferSize, pBuffer ); if (f) { // Marshall the native buffer into managed SID_AND_ATTR structures. // The native buffer holds a TOKEN_GROUPS structure: // // struct TOKEN_GROUPS { // DWORD GroupCount; // SID_AND_ATTRIBUTES Groups[ANYSIZE_ARRAY]; // }; // // Extract TOKEN_GROUPS.GroupCount UnsafeNativeMethods.TOKEN_GROUPS tokenGroups = (UnsafeNativeMethods.TOKEN_GROUPS)Marshal.PtrToStructure(pBuffer, typeof(UnsafeNativeMethods.TOKEN_GROUPS)); int groupCount = tokenGroups.groupCount; GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "Found {0} groups", groupCount); // Extract TOKEN_GROUPS.Groups, by iterating over the array and marshalling // each native SID_AND_ATTRIBUTES into a managed SID_AND_ATTR. UnsafeNativeMethods.SID_AND_ATTR[] groups = new UnsafeNativeMethods.SID_AND_ATTR[groupCount]; IntPtr currentItem = new IntPtr(pBuffer.ToInt64() + Marshal.SizeOf(typeof(UnsafeNativeMethods.TOKEN_GROUPS)) - IntPtr.Size); for (int i = 0; i < groupCount; i++) { groups[i] = (UnsafeNativeMethods.SID_AND_ATTR)Marshal.PtrToStructure(currentItem, typeof(UnsafeNativeMethods.SID_AND_ATTR)); currentItem = new IntPtr(currentItem.ToInt64() + Marshal.SizeOf(typeof(UnsafeNativeMethods.SID_AND_ATTR))); } _groupSidList = new SidList(groups); } else { lastError = Marshal.GetLastWin32Error(); } } else { lastError = Marshal.GetLastWin32Error(); Debug.Fail("With a zero-length buffer, this should have never succeeded"); } } else { lastError = Marshal.GetLastWin32Error(); } } else { lastError = Marshal.GetLastWin32Error(); } if (!f) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "AuthZSet", "Failed to retrieve group list, {0}", lastError); throw new PrincipalOperationException( SR.Format( SR.AuthZFailedToRetrieveGroupList, lastError)); } // Save off the buffer since it still holds the native SIDs referenced by SidList _psBuffer = new SafeMemoryPtr(pBuffer); pBuffer = IntPtr.Zero; } catch (Exception e) { GlobalDebug.WriteLineIf(GlobalDebug.Error, "AuthZSet", "Caught exception {0} with message {1}", e.GetType(), e.Message); if (_psBuffer != null && !_psBuffer.IsInvalid) { _psBuffer.Close(); } if (_psUserSid != null && !_psUserSid.IsInvalid) { _psUserSid.Close(); } if (_psMachineSid != null && !_psMachineSid.IsInvalid) { _psMachineSid.Close(); } // We're on a platform that doesn't have the AuthZ library if (e is DllNotFoundException) { throw new NotSupportedException(SR.AuthZNotSupported, e); } if (e is EntryPointNotFoundException) { throw new NotSupportedException(SR.AuthZNotSupported, e); } throw; } finally { if (pClientContext != IntPtr.Zero) { UnsafeNativeMethods.AuthzFreeContext(pClientContext); } if (pResManager != IntPtr.Zero) { UnsafeNativeMethods.AuthzFreeResourceManager(pResManager); } if (pBuffer != IntPtr.Zero) { Marshal.FreeHGlobal(pBuffer); } } }
internal static bool GetOSVersion(DirectoryEntry computerDE, out int versionMajor, out int versionMinor) { Debug.Assert(SAMUtils.IsOfObjectClass(computerDE, "Computer")); versionMajor = 0; versionMinor = 0; string version = null; try { if (computerDE.Properties["OperatingSystemVersion"].Count > 0) { Debug.Assert(computerDE.Properties["OperatingSystemVersion"].Count == 1); version = (string)computerDE.Properties["OperatingSystemVersion"].Value; } } catch (COMException e) { GlobalDebug.WriteLineIf(GlobalDebug.Error, "SAMUtils", "GetOSVersion: caught COMException with message " + e.Message); // Couldn't retrieve the value if (e.ErrorCode == unchecked ((int)0x80070035)) // ERROR_BAD_NETPATH { return(false); } throw; } // Couldn't retrieve the value if (version == null || version.Length == 0) { return(false); } // This string should be in the form "M.N", where M and N are integers. // We'll also accept "M", which we'll treat as "M.0". // // We'll split the string into its period-separated components, and parse // each component into an int. string[] versionComponents = version.Split(new char[] { '.' }); Debug.Assert(versionComponents.Length >= 1); // since version was a non-empty string try { versionMajor = int.Parse(versionComponents[0], CultureInfo.InvariantCulture); if (versionComponents.Length > 1) { versionMinor = int.Parse(versionComponents[1], CultureInfo.InvariantCulture); } // Sanity check: there are no negetive OS versions, nor is there a version "0". if (versionMajor <= 0 || versionMinor < 0) { Debug.Fail("SAMUtils.GetOSVersion: {computerDE.Path} claims to have negetive OS version, {version}"); return(false); } } catch (FormatException) { Debug.Fail($"SAMUtils.GetOSVersion: FormatException on {version} for {computerDE.Path}"); return(false); } catch (OverflowException) { Debug.Fail($"SAMUtils.GetOSVersion: OverflowException on {version} for {computerDE.Path}"); return(false); } return(true); }
override internal bool MoveNext() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADDNConstraintLinkedAttrSet", "Entering MoveNext"); GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADDNConstraintLinkedAttrSet", "Filter {0}", _constraintData); bool match = false; string dn = "NotSet"; if (!base.MoveNext()) { return(false); } else { while (!match) { if (null == this.current) { return(false); } switch (_constraint) { case ConstraintType.ContainerStringMatch: if (this.current is SearchResult) { dn = ((SearchResult)this.current).Properties["distinguishedName"][0].ToString(); } else { dn = ((DirectoryEntry)this.current).Properties["distinguishedName"].Value.ToString(); } if (dn.EndsWith((string)_constraintData, StringComparison.Ordinal)) { match = true; } break; case ConstraintType.ResultValidatorDelegateMatch: { ResultValidator resultValidator = _constraintData as ResultValidator; if (resultValidator != null) { dSPropertyCollection resultPropCollection = null; if (this.current is SearchResult) { resultPropCollection = new dSPropertyCollection(((SearchResult)this.current).Properties); } else { resultPropCollection = new dSPropertyCollection(((DirectoryEntry)this.current).Properties); } match = resultValidator.Invoke(resultPropCollection); } else { Debug.Fail("ADStoreCtx.ADDNConstraintLinkedAttrSet: Invalid constraint data. Expected: object of type ResultValidator"); } break; } default: Debug.Fail("ADStoreCtx.ADDNConstraintLinkedAttrSet: fell off end looking for " + _constraint.ToString()); break; } GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADDNConstraintLinkedAttrSet", "Found {0} Match {1}", dn, match.ToString()); if (!match) { if (!this.MoveNext()) { return(false); } } } return(match); } }
internal void ReadServerConfig(string serverName, ref ServerProperties properties) { string[] proplist = new string[] { "msDS-PortSSL", "msDS-PortLDAP", "domainControllerFunctionality", "dnsHostName", "supportedCapabilities" }; LdapConnection ldapConnection = null; try { bool useSSL = (_options & ContextOptions.SecureSocketLayer) > 0; if (useSSL && _contextType == ContextType.Domain) { LdapDirectoryIdentifier directoryid = new LdapDirectoryIdentifier(serverName, LdapConstants.LDAP_SSL_PORT); ldapConnection = new LdapConnection(directoryid); } else { ldapConnection = new LdapConnection(serverName); } ldapConnection.AutoBind = false; // If SSL was enabled on the initial connection then turn it on for the search. // This is required bc the appended port number will be SSL and we don't know what port LDAP is running on. ldapConnection.SessionOptions.SecureSocketLayer = useSSL; string baseDN = null; // specify base as null for RootDSE search string ldapSearchFilter = "(objectClass=*)"; SearchResponse searchResponse = null; SearchRequest searchRequest = new SearchRequest(baseDN, ldapSearchFilter, System.DirectoryServices.Protocols .SearchScope.Base, proplist); try { searchResponse = (SearchResponse)ldapConnection.SendRequest(searchRequest); } catch (LdapException ex) { throw new PrincipalServerDownException(SR.ServerDown, ex); } // Fill in the struct with the casted properties from the serach results. // there will always be only 1 item on the rootDSE so all entry indexes are 0 properties.dnsHostName = (string)searchResponse.Entries[0].Attributes["dnsHostName"][0]; properties.SupportCapabilities = new string[searchResponse.Entries[0].Attributes["supportedCapabilities"].Count]; for (int i = 0; i < searchResponse.Entries[0].Attributes["supportedCapabilities"].Count; i++) { properties.SupportCapabilities[i] = (string)searchResponse.Entries[0].Attributes["supportedCapabilities"][i]; } foreach (string capability in properties.SupportCapabilities) { if (CapabilityMap.LDAP_CAP_ACTIVE_DIRECTORY_ADAM_OID == capability) { properties.contextType = ContextType.ApplicationDirectory; } else if (CapabilityMap.LDAP_CAP_ACTIVE_DIRECTORY_OID == capability) { properties.contextType = ContextType.Domain; } } // If we can't determine the OS vesion so we must fall back to lowest level of functionality if (searchResponse.Entries[0].Attributes.Contains("domainControllerFunctionality")) { properties.OsVersion = (DomainControllerMode)Convert.ToInt32(searchResponse.Entries[0].Attributes["domainControllerFunctionality"][0], CultureInfo.InvariantCulture); } else { properties.OsVersion = DomainControllerMode.Win2k; } if (properties.contextType == ContextType.ApplicationDirectory) { if (searchResponse.Entries[0].Attributes.Contains("msDS-PortSSL")) { properties.portSSL = Convert.ToInt32(searchResponse.Entries[0].Attributes["msDS-PortSSL"][0]); } if (searchResponse.Entries[0].Attributes.Contains("msDS-PortLDAP")) { properties.portLDAP = Convert.ToInt32(searchResponse.Entries[0].Attributes["msDS-PortLDAP"][0]); } } GlobalDebug.WriteLineIf(GlobalDebug.Info, "ReadServerConfig", "OsVersion : " + properties.OsVersion.ToString()); GlobalDebug.WriteLineIf(GlobalDebug.Info, "ReadServerConfig", "dnsHostName : " + properties.dnsHostName); GlobalDebug.WriteLineIf(GlobalDebug.Info, "ReadServerConfig", "contextType : " + properties.contextType.ToString()); GlobalDebug.WriteLineIf(GlobalDebug.Info, "ReadServerConfig", "portSSL : " + properties.portSSL.ToString(CultureInfo.InvariantCulture)); GlobalDebug.WriteLineIf(GlobalDebug.Info, "ReadServerConfig", "portLDAP :" + properties.portLDAP.ToString(CultureInfo.InvariantCulture)); } finally { ldapConnection?.Dispose(); } }
// Applies to supplied propertySet to the supplied Principal, and adds any resulting filters // to qbeFilterDescription. private void BuildFilterSet(Principal p, string[] propertySet, QbeFilterDescription qbeFilterDescription) { foreach (string propertyName in propertySet) { if (p.GetChangeStatusForProperty(propertyName)) { // Property has changed. Add it to the filter set. object value = p.GetValueForProperty(propertyName); GlobalDebug.WriteLineIf( GlobalDebug.Info, "StoreCtx", "BuildFilterSet: type={0}, property name={1}, property value={2} of type {3}", p.GetType().ToString(), propertyName, value.ToString(), value.GetType().ToString()); // Build the right filter based on type of the property value if (value is PrincipalValueCollection <string> ) { PrincipalValueCollection <string> trackingList = (PrincipalValueCollection <string>)value; foreach (string s in trackingList.Inserted) { object filter = FilterFactory.CreateFilter(propertyName); ((FilterBase)filter).Value = (string)s; qbeFilterDescription.FiltersToApply.Add(filter); } } else if (value is X509Certificate2Collection) { // Since QBE filter objects are always unpersisted, any certs in the collection // must have been inserted by the application. X509Certificate2Collection certCollection = (X509Certificate2Collection)value; foreach (X509Certificate2 cert in certCollection) { object filter = FilterFactory.CreateFilter(propertyName); ((FilterBase)filter).Value = (X509Certificate2)cert; qbeFilterDescription.FiltersToApply.Add(filter); } } else { // It's not one of the multivalued cases. Try the scalar cases. object filter = FilterFactory.CreateFilter(propertyName); if (value == null) { ((FilterBase)filter).Value = null; } else if (value is bool) { ((FilterBase)filter).Value = (bool)value; } else if (value is string) { ((FilterBase)filter).Value = (string)value; } else if (value is GroupScope) { ((FilterBase)filter).Value = (GroupScope)value; } else if (value is byte[]) { ((FilterBase)filter).Value = (byte[])value; } else if (value is Nullable <DateTime> ) { ((FilterBase)filter).Value = (Nullable <DateTime>)value; } else if (value is ExtensionCache) { ((FilterBase)filter).Value = (ExtensionCache)value; } else if (value is QbeMatchType) { ((FilterBase)filter).Value = (QbeMatchType)value; } else { // Internal error. Didn't match either the known multivalued or scalar cases. Debug.Fail($"StoreCtx.BuildFilterSet: fell off end looking for {propertyName} of type {value.GetType()}"); } qbeFilterDescription.FiltersToApply.Add(filter); } } } }
public PrincipalContext( ContextType contextType, string name, string container, ContextOptions options, string userName, string password) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalContext", "Entering ctor"); if ((userName == null && password != null) || (userName != null && password == null)) { throw new ArgumentException(SR.ContextBadUserPwdCombo); } if ((options & ~(ContextOptions.Signing | ContextOptions.Negotiate | ContextOptions.Sealing | ContextOptions.SecureSocketLayer | ContextOptions.SimpleBind | ContextOptions.ServerBind)) != 0) { throw new InvalidEnumArgumentException(nameof(options), (int)options, typeof(ContextOptions)); } if (contextType == ContextType.Machine && ((options & ~ContextOptions.Negotiate) != 0)) { throw new ArgumentException(SR.InvalidContextOptionsForMachine); } if ((contextType == ContextType.Domain || contextType == ContextType.ApplicationDirectory) && (((options & (ContextOptions.Negotiate | ContextOptions.SimpleBind)) == 0) || (((options & (ContextOptions.Negotiate | ContextOptions.SimpleBind)) == ((ContextOptions.Negotiate | ContextOptions.SimpleBind)))))) { throw new ArgumentException(SR.InvalidContextOptionsForAD); } if ((contextType != ContextType.Machine) && (contextType != ContextType.Domain) && (contextType != ContextType.ApplicationDirectory) #if TESTHOOK && (contextType != ContextType.Test) #endif ) { throw new InvalidEnumArgumentException(nameof(contextType), (int)contextType, typeof(ContextType)); } if ((contextType == ContextType.Machine) && (container != null)) { throw new ArgumentException(SR.ContextNoContainerForMachineCtx); } if ((contextType == ContextType.ApplicationDirectory) && ((string.IsNullOrEmpty(container)) || (string.IsNullOrEmpty(name)))) { throw new ArgumentException(SR.ContextNoContainerForApplicationDirectoryCtx); } _contextType = contextType; _name = name; _container = container; _options = options; _username = userName; _password = password; DoServerVerifyAndPropRetrieval(); _credValidate = new CredentialValidator(contextType, name, _serverProperties); }
// 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. override internal bool MoveNext() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMQuerySet", "Entering MoveNext"); Debug.Assert(_enumerator != null); bool needToRetry = false; bool f; // Have we exceeded the requested size limit? if ((_sizeLimit != -1) && (_resultsReturned >= _sizeLimit)) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMQuerySet", "MoveNext: exceeded sizelimit, ret={0}, limit={1}", _resultsReturned, _sizeLimit); _endReached = true; } // End was reached previously. Nothing more to do. if (_endReached) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMQuerySet", "MoveNext: endReached"); return(false); } // Pull the next result. We may have to repeat this several times // until we find a result that matches the user's filter. do { f = _enumerator.MoveNext(); needToRetry = false; if (f) { DirectoryEntry entry = (DirectoryEntry)_enumerator.Current; // Does it match the user's properties? // // We'd like to use DirectoryEntries.SchemaFilter rather than calling // IsOfCorrectType here, but SchemaFilter has a bug // where multiple DirectoryEntries all share the same SchemaFilter --- // which would create multithreading issues for us. if (IsOfCorrectType(entry) && _matcher.Matches(entry)) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMQuerySet", "MoveNext: found a match on {0}", entry.Path); // Yes. It's our new current object _current = entry; _resultsReturned++; } else { // No. Retry. needToRetry = true; } } }while (needToRetry); if (!f) { /* * // One more to try: the root object * if (IsOfCorrectType(this.ctxBase) && this.matcher.Matches(this.ctxBase)) * { * GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMQuerySet", "MoveNext: found a match on root {0}", this.ctxBase); * * this.current = this.ctxBase; * this.resultsReturned++; * f = true; * } * else * { * endReached = true; * } * */ } return(f); }
private void DoLDAPDirectoryInit() { // use the servername if they gave us one, else let ADSI figure it out string serverName = ""; if (_name != null) { if (_contextType == ContextType.ApplicationDirectory) { serverName = _serverProperties.dnsHostName + ":" + ((ContextOptions.SecureSocketLayer & _options) > 0 ? _serverProperties.portSSL : _serverProperties.portLDAP); } else { serverName = _name; } serverName += "/"; } GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalContext", "DoLDAPDirectoryInit: serverName is " + serverName); // use the options they specified AuthenticationTypes authTypes = SDSUtils.MapOptionsToAuthTypes(_options); GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalContext", "DoLDAPDirectoryInit: authTypes is " + authTypes.ToString()); DirectoryEntry de = new DirectoryEntry("LDAP://" + serverName + _container, _username, _password, authTypes); try { // Set the password port to the ssl port read off of the rootDSE. Without this // password change/set won't work when we connect without SSL and ADAM is running // on non-standard port numbers. We have already verified directory connectivity at this point // so this should always succeed. if (_serverProperties.portSSL > 0) { de.Options.PasswordPort = _serverProperties.portSSL; } StoreCtx storeCtx = CreateContextFromDirectoryEntry(de); _queryCtx = storeCtx; _userCtx = storeCtx; _groupCtx = storeCtx; _computerCtx = storeCtx; _connectedServer = ADUtils.GetServerName(de); de = null; } catch (System.Runtime.InteropServices.COMException e) { throw ExceptionHelper.GetExceptionFromCOMException(e); } catch (Exception e) { GlobalDebug.WriteLineIf(GlobalDebug.Error, "PrincipalContext", "DoLDAPDirectoryInit: caught exception of type " + e.GetType().ToString() + " and message " + e.Message); throw; } finally { // Cleanup the DE on failure de?.Dispose(); } }
internal override void Move(StoreCtx originalStore, Principal p) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "Move"); }
private void DoLDAPDirectoryInitNoContainer() { byte[] USERS_CONTAINER_GUID = new byte[] { 0xa9, 0xd1, 0xca, 0x15, 0x76, 0x88, 0x11, 0xd1, 0xad, 0xed, 0x00, 0xc0, 0x4f, 0xd8, 0xd5, 0xcd }; byte[] COMPUTERS_CONTAINER_GUID = new byte[] { 0xaa, 0x31, 0x28, 0x25, 0x76, 0x88, 0x11, 0xd1, 0xad, 0xed, 0x00, 0xc0, 0x4f, 0xd8, 0xd5, 0xcd }; // The StoreCtxs that will be used in the PrincipalContext, and their associated DirectoryEntry objects. DirectoryEntry deUserGroupOrg = null; DirectoryEntry deComputer = null; DirectoryEntry deBase = null; ADStoreCtx storeCtxUserGroupOrg = null; ADStoreCtx storeCtxComputer = null; ADStoreCtx storeCtxBase = null; GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalContext", "Entering DoLDAPDirectoryInitNoContainer"); // // Build a DirectoryEntry that represents the root of the domain. // // Use the RootDSE to find the default naming context DirectoryEntry deRootDse = null; string adsPathBase; // use the servername if they gave us one, else let ADSI figure it out string serverName = ""; if (_name != null) { serverName = _name + "/"; } GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalContext", "DoLDAPDirectoryInitNoContainer: serverName is " + serverName); // use the options they specified AuthenticationTypes authTypes = SDSUtils.MapOptionsToAuthTypes(_options); GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalContext", "DoLDAPDirectoryInitNoContainer: authTypes is " + authTypes.ToString()); try { deRootDse = new DirectoryEntry("LDAP://" + serverName + "rootDse", _username, _password, authTypes); // This will also detect if the server is down or nonexistent string domainNC = (string)deRootDse.Properties["defaultNamingContext"][0]; adsPathBase = "LDAP://" + serverName + domainNC; GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalContext", "DoLDAPDirectoryInitNoContainer: domainNC is " + domainNC); GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalContext", "DoLDAPDirectoryInitNoContainer: adsPathBase is " + adsPathBase); } finally { // Don't allow the DE to leak deRootDse?.Dispose(); } try { // Build a DE for the root of the domain using the retrieved naming context deBase = new DirectoryEntry(adsPathBase, _username, _password, authTypes); // Set the password port to the ssl port read off of the rootDSE. Without this // password change/set won't work when we connect without SSL and ADAM is running // on non-standard port numbers. We have already verified directory connectivity at this point // so this should always succeed. if (_serverProperties.portSSL > 0) { deBase.Options.PasswordPort = _serverProperties.portSSL; } // // Use the wellKnownObjects attribute to determine the default location // for users and computers. // string adsPathUserGroupOrg = null; string adsPathComputer = null; PropertyValueCollection wellKnownObjectValues = deBase.Properties["wellKnownObjects"]; foreach (UnsafeNativeMethods.IADsDNWithBinary value in wellKnownObjectValues) { if (Utils.AreBytesEqual(USERS_CONTAINER_GUID, (byte[])value.BinaryValue)) { Debug.Assert(adsPathUserGroupOrg == null); adsPathUserGroupOrg = "LDAP://" + serverName + value.DNString; GlobalDebug.WriteLineIf( GlobalDebug.Info, "PrincipalContext", "DoLDAPDirectoryInitNoContainer: found USER, adsPathUserGroupOrg is " + adsPathUserGroupOrg); } // Is it the computer container? if (Utils.AreBytesEqual(COMPUTERS_CONTAINER_GUID, (byte[])value.BinaryValue)) { Debug.Assert(adsPathComputer == null); adsPathComputer = "LDAP://" + serverName + value.DNString; GlobalDebug.WriteLineIf( GlobalDebug.Info, "PrincipalContext", "DoLDAPDirectoryInitNoContainer: found COMPUTER, adsPathComputer is " + adsPathComputer); } } if ((adsPathUserGroupOrg == null) || (adsPathComputer == null)) { // Something's wrong with the domain, it's not exposing the proper // well-known object fields. throw new PrincipalOperationException(SR.ContextNoWellKnownObjects); } // // Build DEs for the Users and Computers containers. // The Users container will also be used as the default for Groups. // The reason there are different contexts for groups, users and computers is so that // when a principal is created it will go into the appropriate default container. This is so users don't // by default create principals in the root of their directory. When a search happens the base context is used so that // the whole directory will be covered. // deUserGroupOrg = new DirectoryEntry(adsPathUserGroupOrg, _username, _password, authTypes); deComputer = new DirectoryEntry(adsPathComputer, _username, _password, authTypes); StoreCtx userStore = CreateContextFromDirectoryEntry(deUserGroupOrg); _userCtx = userStore; _groupCtx = userStore; deUserGroupOrg = null; // since we handed off ownership to the StoreCtx _computerCtx = CreateContextFromDirectoryEntry(deComputer); deComputer = null; _queryCtx = CreateContextFromDirectoryEntry(deBase); _connectedServer = ADUtils.GetServerName(deBase); deBase = null; } catch (Exception e) { GlobalDebug.WriteLineIf(GlobalDebug.Error, "PrincipalContext", "DoLDAPDirectoryInitNoContainer: caught exception of type " + e.GetType().ToString() + " and message " + e.Message); // Cleanup on failure. Once a DE has been successfully handed off to a ADStoreCtx, // that ADStoreCtx will handle Dispose()'ing it deUserGroupOrg?.Dispose(); deComputer?.Dispose(); deBase?.Dispose(); storeCtxUserGroupOrg?.Dispose(); storeCtxComputer?.Dispose(); storeCtxBase?.Dispose(); throw; } }
// // Cross-store support // // Given a native store object that represents a "foreign" principal (e.g., a FPO object in this store that // represents a pointer to another store), maps that representation to the other store's StoreCtx and returns // a Principal from that other StoreCtx. The implementation of this method is highly dependent on the // details of the particular store, and must have knowledge not only of this StoreCtx, but also of how to // interact with other StoreCtxs to fulfill the request. // // This method is typically used by ResultSet implementations, when they're iterating over a collection // (e.g., of group membership) and encounter an entry that represents a foreign principal. internal override Principal ResolveCrossStoreRefToPrincipal(object o) { Debug.Assert(o is DirectoryEntry); // Get the SID of the foreign principal DirectoryEntry foreignDE = (DirectoryEntry)o; if (foreignDE.Properties["objectSid"].Count == 0) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "SAMStoreCtx", "ResolveCrossStoreRefToPrincipal: no objectSid found"); throw new PrincipalOperationException(SR.SAMStoreCtxCantRetrieveObjectSidForCrossStore); } Debug.Assert(foreignDE.Properties["objectSid"].Count == 1); byte[] sid = (byte[])foreignDE.Properties["objectSid"].Value; // Ask the OS to resolve the SID to its target. int accountUsage = 0; string name; string domainName; int err = Utils.LookupSid(this.MachineUserSuppliedName, _credentials, sid, out name, out domainName, out accountUsage); if (err != 0) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "SAMStoreCtx", "ResolveCrossStoreRefToPrincipal: LookupSid failed, err={0}, server={1}", err, this.MachineUserSuppliedName); throw new PrincipalOperationException( SR.Format(SR.SAMStoreCtxCantResolveSidForCrossStore, err)); } GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "ResolveCrossStoreRefToPrincipal: LookupSid found {0} in {1}", name, domainName); // Since this is SAM, the remote principal must be an AD principal. // Build a PrincipalContext for the store which owns the principal // Use the ad default options so we turn sign and seal back on. #if USE_CTX_CACHE PrincipalContext remoteCtx = SDSCache.Domain.GetContext(domainName, _credentials, DefaultContextOptions.ADDefaultContextOption); #else PrincipalContext remoteCtx = new PrincipalContext( ContextType.Domain, domainName, null, (this.credentials != null ? credentials.UserName : null), (this.credentials != null ? credentials.Password : null), DefaultContextOptions.ADDefaultContextOption); #endif SecurityIdentifier sidObj = new SecurityIdentifier(sid, 0); Principal p = remoteCtx.QueryCtx.FindPrincipalByIdentRef( typeof(Principal), UrnScheme.SidScheme, sidObj.ToString(), DateTime.UtcNow); if (p != null) { return(p); } else { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "SAMStoreCtx", "ResolveCrossStoreRefToPrincipal: no matching principal"); throw new PrincipalOperationException(SR.SAMStoreCtxFailedFindCrossStoreTarget); } }
private void TranslateSids(string target, IntPtr[] pSids) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "SidList: processing {0} SIDs", pSids.Length); // if there are no SIDs to translate return if (pSids.Length == 0) { return; } // Build the list of SIDs to resolve int sidCount = pSids.Length; // Translate the SIDs in bulk SafeLsaPolicyHandle policyHandle = null; SafeLsaMemoryHandle domainsHandle = null; SafeLsaMemoryHandle namesHandle = null; try { // // Get the policy handle // Interop.OBJECT_ATTRIBUTES oa = default; uint err = Interop.Advapi32.LsaOpenPolicy( target, ref oa, (int)Interop.Advapi32.PolicyRights.POLICY_LOOKUP_NAMES, out policyHandle); if (err != 0) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "AuthZSet", "SidList: couldn't get policy handle, err={0}", err); throw new PrincipalOperationException(SR.Format( SR.AuthZErrorEnumeratingGroups, Interop.Advapi32.LsaNtStatusToWinError(err))); } Debug.Assert(!policyHandle.IsInvalid); // // Translate the SIDs // err = Interop.Advapi32.LsaLookupSids( policyHandle, sidCount, pSids, out domainsHandle, out namesHandle); // Ignore error STATUS_SOME_NOT_MAPPED and STATUS_NONE_MAPPED if (err != Interop.StatusOptions.STATUS_SUCCESS && err != Interop.StatusOptions.STATUS_SOME_NOT_MAPPED && err != Interop.StatusOptions.STATUS_NONE_MAPPED) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "AuthZSet", "SidList: LsaLookupSids failed, err={0}", err); throw new PrincipalOperationException(SR.Format( SR.AuthZErrorEnumeratingGroups, Interop.Advapi32.LsaNtStatusToWinError(err))); } // // Get the group names in managed form // namesHandle.Initialize((uint)sidCount, (uint)Marshal.SizeOf <Interop.LSA_TRANSLATED_NAME>()); Interop.LSA_TRANSLATED_NAME[] names = new Interop.LSA_TRANSLATED_NAME[sidCount]; namesHandle.ReadArray(0, names, 0, names.Length); // // Get the domain names in managed form // domainsHandle.InitializeReferencedDomainsList(); Interop.LSA_REFERENCED_DOMAIN_LIST domainList = domainsHandle.Read <Interop.LSA_REFERENCED_DOMAIN_LIST>(0); // Extract LSA_REFERENCED_DOMAIN_LIST.Entries int domainCount = domainList.Entries; // Extract LSA_REFERENCED_DOMAIN_LIST.Domains, by iterating over the array and marshalling // each native LSA_TRUST_INFORMATION into a managed LSA_TRUST_INFORMATION. Interop.LSA_TRUST_INFORMATION[] domains = new Interop.LSA_TRUST_INFORMATION[domainCount]; IntPtr pCurrentDomain = domainList.Domains; for (int i = 0; i < domainCount; i++) { domains[i] = (Interop.LSA_TRUST_INFORMATION)Marshal.PtrToStructure(pCurrentDomain, typeof(Interop.LSA_TRUST_INFORMATION)); pCurrentDomain = new IntPtr(pCurrentDomain.ToInt64() + Marshal.SizeOf(typeof(Interop.LSA_TRUST_INFORMATION))); } GlobalDebug.WriteLineIf(GlobalDebug.Info, "AuthZSet", "SidList: got {0} groups in {1} domains", sidCount, domainCount); // // Build the list of entries // Debug.Assert(names.Length == sidCount); for (int i = 0; i < names.Length; i++) { Interop.LSA_TRANSLATED_NAME name = names[i]; // Build an entry. Note that LSA_UNICODE_STRING.length is in bytes, // while PtrToStringUni expects a length in characters. SidListEntry entry = new SidListEntry(); Debug.Assert(name.Name.Length % 2 == 0); entry.name = Marshal.PtrToStringUni(name.Name.Buffer, name.Name.Length / 2); // Get the domain associated with this name Debug.Assert(name.DomainIndex < domains.Length); if (name.DomainIndex >= 0) { Interop.LSA_TRUST_INFORMATION domain = domains[name.DomainIndex]; Debug.Assert(domain.Name.Length % 2 == 0); entry.sidIssuerName = Marshal.PtrToStringUni(domain.Name.Buffer, domain.Name.Length / 2); } entry.pSid = pSids[i]; _entries.Add(entry); } // Sort the list so they are oriented by the issuer name. // this.entries.Sort( new SidListComparer()); } finally { if (domainsHandle != null) { domainsHandle.Dispose(); } if (namesHandle != null) { namesHandle.Dispose(); } if (policyHandle != null) { policyHandle.Dispose(); } } }
// // ICollection // void ICollection.CopyTo(Array array, int index) { CheckDisposed(); if (index < 0) { throw new ArgumentOutOfRangeException(nameof(index)); } if (array == null) { throw new ArgumentNullException(nameof(array)); } if (array.Rank != 1) { throw new ArgumentException(SR.PrincipalCollectionNotOneDimensional); } if (index >= array.GetLength(0)) { throw new ArgumentException(SR.PrincipalCollectionIndexNotInArray); } ArrayList tempArray = new ArrayList(); lock (_resultSet) { ResultSetBookmark bookmark = null; try { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollection", "CopyTo: bookmarking"); bookmark = _resultSet.BookmarkAndReset(); PrincipalCollectionEnumerator containmentEnumerator = new PrincipalCollectionEnumerator( _resultSet, this, _removedValuesCompleted, _removedValuesPending, _insertedValuesCompleted, _insertedValuesPending); int arraySize = array.GetLength(0) - index; int tempArraySize = 0; while (containmentEnumerator.MoveNext()) { tempArray.Add(containmentEnumerator.Current); checked { tempArraySize++; } // Make sure the array has enough space, allowing for the "index" offset. // We check inline, rather than doing a PrincipalCollection.Count upfront, // because counting is just as expensive as enumerating over all the results, so we // only want to do it once. if (arraySize < tempArraySize) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "PrincipalCollection", "CopyTo: array too small (has {0}, need >= {1}", arraySize, tempArraySize); throw new ArgumentException(SR.PrincipalCollectionArrayTooSmall); } } } finally { if (bookmark != null) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "PrincipalCollection", "CopyTo: restoring from bookmark"); _resultSet.RestoreBookmark(bookmark); } } } foreach (object o in tempArray) { array.SetValue(o, index); checked { index++; } } }
public void Dispose() { GlobalDebug.WriteLineIf(GlobalDebug.Info, "ValueCollectionEnumerator", "Entering Dispose"); _inner.Dispose(); }