Beispiel #1
0
 //
 // 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);
 }
Beispiel #2
0
        // 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);
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #5
0
        // 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);
                }
            }
        }
Beispiel #6
0
        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);
        }
Beispiel #8
0
        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
        }
Beispiel #9
0
        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);
                }
            }
        }
Beispiel #10
0
        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);
        }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        // 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;
                }
            }
        }
Beispiel #13
0
        //
        // 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;
        }
Beispiel #14
0
        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);
        }
Beispiel #15
0
        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);
        }
Beispiel #16
0
        //  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());
        }
Beispiel #17
0
        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);
                }
            }
        }
Beispiel #18
0
        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);
            }
        }
Beispiel #20
0
        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();
            }
        }
Beispiel #21
0
        // 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);
                    }
                }
            }
        }
Beispiel #22
0
        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);
        }
Beispiel #23
0
        // 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);
        }
Beispiel #24
0
        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();
            }
        }
Beispiel #25
0
 internal override void Move(StoreCtx originalStore, Principal p)
 {
     GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "Move");
 }
Beispiel #26
0
        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;
            }
        }
Beispiel #27
0
        //
        // 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);
            }
        }
Beispiel #28
0
        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();
                }
            }
        }
Beispiel #29
0
        //
        // 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++; }
            }
        }
Beispiel #30
0
 public void Dispose()
 {
     GlobalDebug.WriteLineIf(GlobalDebug.Info, "ValueCollectionEnumerator", "Entering Dispose");
     _inner.Dispose();
 }