public DirectoryEntry()
 {
     this.path = "";
     this.useCache = true;
     this.authenticationType = AuthenticationTypes.Secure;
     this.options = new DirectoryEntryConfiguration(this);
 }
 public DirectoryEntry(string path, string username, string password, AuthenticationTypes authenticationType) : this(path)
 {
     this.credentials = new NetworkCredential(username, password);
     if (username == null)
     {
         this.userNameIsNull = true;
     }
     if (password == null)
     {
         this.passwordIsNull = true;
     }
     this.authenticationType = authenticationType;
 }
 internal DirectoryEntry(string path, bool useCache, string username, string password, AuthenticationTypes authenticationType)
 {
     this.path = "";
     this.useCache = true;
     this.authenticationType = AuthenticationTypes.Secure;
     this.path = path;
     this.useCache = useCache;
     this.credentials = new NetworkCredential(username, password);
     if (username == null)
     {
         this.userNameIsNull = true;
     }
     if (password == null)
     {
         this.passwordIsNull = true;
     }
     this.authenticationType = authenticationType;
     this.options = new DirectoryEntryConfiguration(this);
 }
Exemple #4
0
		static Utils()
		{
			Utils.LOGON32_LOGON_NEW_CREDENTIALS = 9;
			Utils.LOGON32_PROVIDER_WINNT50 = 3;
			Utils.POLICY_VIEW_LOCAL_INFORMATION = 1;
			Utils.STANDARD_RIGHTS_REQUIRED = 0xf0000;
			Utils.SYNCHRONIZE = 0x100000;
			Utils.THREAD_ALL_ACCESS = Utils.STANDARD_RIGHTS_REQUIRED | Utils.SYNCHRONIZE | 0x3ff;
			Utils.DefaultAuthType = AuthenticationTypes.Secure | AuthenticationTypes.Signing | AuthenticationTypes.Sealing;
			Utils.LANG_ENGLISH = 9;
			Utils.SUBLANG_ENGLISH_US = 1;
			Utils.SORT_DEFAULT = 0;
			Utils.LANGID = Convert.ToUInt32 ((ushort)Utils.SUBLANG_ENGLISH_US << 10 | (ushort)Utils.LANG_ENGLISH);
			Utils.LCID = Convert.ToUInt32 ((ushort)Utils.SORT_DEFAULT << 16 | (ushort)Utils.LANGID);
			Utils.NORM_IGNORECASE = 1;
			Utils.NORM_IGNORENONSPACE = 2;
			Utils.NORM_IGNOREKANATYPE = 0x10000;
			Utils.NORM_IGNOREWIDTH = 0x20000;
			Utils.SORT_STRINGSORT = 0x1000;
			Utils.DEFAULT_CMP_FLAGS = Utils.NORM_IGNORECASE | Utils.NORM_IGNOREKANATYPE | Utils.NORM_IGNORENONSPACE | Utils.NORM_IGNOREWIDTH | Utils.SORT_STRINGSORT;
			Utils.NTAuthorityString = null;
		}
Exemple #5
0
        internal DirectoryEntry(object adsObject, bool useCache, string username, string password, AuthenticationTypes authenticationType, bool AdsObjIsExternal)
        {
            _adsObject = adsObject as UnsafeNativeMethods.IAds;
            if (_adsObject == null)
                throw new ArgumentException(Res.GetString(Res.DSDoesNotImplementIADs));

            // GetInfo is not needed here. ADSI executes an implicit GetInfo when GetEx 
            // is called on the PropertyValueCollection. 0x800704BC error might be returned 
            // on some WinNT entries, when iterating through 'Users' group members.
            // if (forceBind)
            //     this.adsObject.GetInfo();                
            _path = _adsObject.ADsPath;
            _useCache = useCache;

            _authenticationType = authenticationType;
            _credentials = new NetworkCredential(username, password);
            if (username == null)
                _userNameIsNull = true;

            if (password == null)
                _passwordIsNull = true;

            if (!useCache)
                CommitChanges();

            _options = new DirectoryEntryConfiguration(this);

            // We are starting from an already bound connection so make sure the options are set properly.
            // If this is an externallly managed com object then we don't want to change it's current behavior
            if (!AdsObjIsExternal)
            {
                InitADsObjectOptions();
            }
        }
Exemple #6
0
 internal DirectoryEntry(object adsObject, bool useCache, string username, string password, AuthenticationTypes authenticationType)
     : this(adsObject, useCache, username, password, authenticationType, false)
 {
 }
Exemple #7
0
        internal DirectoryEntry(string path, bool useCache, string username, string password, AuthenticationTypes authenticationType)
        {
            _path = path;
            _useCache = useCache;
            _credentials = new NetworkCredential(username, password);
            if (username == null)
                _userNameIsNull = true;

            if (password == null)
                _passwordIsNull = true;

            _authenticationType = authenticationType;

            _options = new DirectoryEntryConfiguration(this);
        }
        private static void UpdateGroupMembership(Principal group, DirectoryEntry de, NetCred credentials, AuthenticationTypes authTypes)
        {
            Debug.Assert(group.fakePrincipal == false);

            PrincipalCollection members = (PrincipalCollection)group.GetValueForProperty(PropertyNames.GroupMembers);

            UnsafeNativeMethods.IADsGroup iADsGroup = (UnsafeNativeMethods.IADsGroup)de.NativeObject;

            try
            {
                //
                // Process clear
                //
                if (members.Cleared)
                {
                    // Unfortunately, there's no quick way to clear a group's membership in SAM.
                    // So we remove each member in turn, by enumerating over the group membership
                    // and calling remove on each.

                    GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "UpdateGroupMembership: clearing {0}", de.Path);

                    // Prepare the COM Interopt enumeration
                    UnsafeNativeMethods.IADsMembers iADsMembers = iADsGroup.Members();
                    IEnumVARIANT enumerator = (IEnumVARIANT)iADsMembers._NewEnum;

                    object[] nativeMembers = new object[1];
                    int hr;

                    do
                    {
                        hr = enumerator.Next(1, nativeMembers, IntPtr.Zero);

                        if (hr == 0) // S_OK
                        {
                            // Found a member, remove it.
                            UnsafeNativeMethods.IADs iADs = (UnsafeNativeMethods.IADs)nativeMembers[0];
                            iADsGroup.Remove(iADs.ADsPath);
                        }
                    }
                    while (hr == 0);

                    // Either hr == S_FALSE (1), which means we completed the enumerator,
                    // or we encountered an error
                    if (hr != 1)
                    {
                        // Error occurred.
                        GlobalDebug.WriteLineIf(GlobalDebug.Warn, "SAMStoreCtx", "UpdateGroupMembership: error while clearing, hr={0}", hr);

                        throw new PrincipalOperationException(
                                        String.Format(
                                                CultureInfo.CurrentCulture,
                                                StringResources.SAMStoreCtxFailedToClearGroup,
                                                hr.ToString(CultureInfo.InvariantCulture)));
                    }
                }

                //
                // Process inserted members
                //
                List<Principal> insertedMembers = members.Inserted;

                // First, validate the members to be added
                foreach (Principal member in insertedMembers)
                {
                    Type memberType = member.GetType();

                    if ((memberType != typeof(UserPrincipal)) && (!memberType.IsSubclassOf(typeof(UserPrincipal))) &&
                         (memberType != typeof(ComputerPrincipal)) && (!memberType.IsSubclassOf(typeof(ComputerPrincipal))) &&
                         (memberType != typeof(GroupPrincipal)) && (!memberType.IsSubclassOf(typeof(GroupPrincipal))))
                    {
                        throw new InvalidOperationException(
                                        String.Format(CultureInfo.CurrentCulture, StringResources.StoreCtxUnsupportedPrincipalTypeForGroupInsert, memberType.ToString()));
                    }

                    // Can't inserted unpersisted principal
                    if (member.unpersisted)
                        throw new InvalidOperationException(StringResources.StoreCtxGroupHasUnpersistedInsertedPrincipal);

                    Debug.Assert(member.Context != null);

                    // There's no restriction on the type of principal to be inserted (AD/reg-SAM/MSAM), but it needs
                    // to have a SID IdentityClaim.  We'll check that as we go.
                }

                // Now add each member to the group
                foreach (Principal member in insertedMembers)
                {
                    // We'll add the member via its SID.  This works for both MSAM members and AD members.

                    // Build a SID ADsPath
                    string memberSidPath = GetSidADsPathFromPrincipal(member);

                    if (memberSidPath == null)
                        throw new InvalidOperationException(StringResources.SAMStoreCtxCouldntGetSIDForGroupMember);

                    GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "UpdateGroupMembership: inserting {0}", memberSidPath);

                    // Add the member to the group
                    iADsGroup.Add(memberSidPath);
                }

                //
                // Process removed members
                //
                List<Principal> removedMembers = members.Removed;

                foreach (Principal member in removedMembers)
                {
                    // Since we don't allow any of these to be inserted, none of them should ever
                    // show up in the removal list
                    Debug.Assert(member.unpersisted == false);

                    // If the collection was cleared, there should be no original members to remove
                    Debug.Assert(members.Cleared == false);

                    // Like insertion, we'll remove by SID.

                    // Build a SID ADsPath
                    string memberSidPath = GetSidADsPathFromPrincipal(member);

                    if (memberSidPath == null)
                        throw new InvalidOperationException(StringResources.SAMStoreCtxCouldntGetSIDForGroupMember);

                    GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "UpdateGroupMembership: removing {0}", memberSidPath);

                    // Remove the member from the group
                    iADsGroup.Remove(memberSidPath);
                }
            }
            catch (System.Runtime.InteropServices.COMException e)
            {
                GlobalDebug.WriteLineIf(GlobalDebug.Error,
                                        "SAMStoreCtx",
                                        "UpdateGroupMembership: caught COMException, message={0}, code={1}",
                                        e.Message,
                                        e.ErrorCode);

                // ADSI threw an exception trying to update the group membership
                throw ExceptionHelper.GetExceptionFromCOMException(e);
            }
        }
 internal DirectoryEntry(object adsObject, bool useCache, string username, string password, AuthenticationTypes authenticationType, bool AdsObjIsExternal)
 {
     this.path = "";
     this.useCache = true;
     this.authenticationType = AuthenticationTypes.Secure;
     this.adsObject = adsObject as System.DirectoryServices.Interop.UnsafeNativeMethods.IAds;
     if (this.adsObject == null)
     {
         throw new ArgumentException(Res.GetString("DSDoesNotImplementIADs"));
     }
     this.path = this.adsObject.ADsPath;
     this.useCache = useCache;
     this.authenticationType = authenticationType;
     this.credentials = new NetworkCredential(username, password);
     if (username == null)
     {
         this.userNameIsNull = true;
     }
     if (password == null)
     {
         this.passwordIsNull = true;
     }
     if (!useCache)
     {
         this.CommitChanges();
     }
     this.options = new DirectoryEntryConfiguration(this);
     if (!AdsObjIsExternal)
     {
         this.InitADsObjectOptions();
     }
 }
        internal DirectoryInformation(string adspath,
                                                            NetworkCredential credentials,
                                                            string connProtection,
                                                            int clientSearchTimeout,
                                                            int serverSearchTimeout,
                                                            bool enablePasswordReset)
        {

           //
           // all parameters have already been validated at this point
           //

            this.adspath = adspath;
            this.credentials = credentials;
            this.clientSearchTimeout = clientSearchTimeout;
            this.serverSearchTimeout = serverSearchTimeout;

            Debug.Assert(adspath != null);
            Debug.Assert(adspath.Length > 0);

            //
            // Provider must be LDAP
            //
            if (!(adspath.StartsWith("LDAP", StringComparison.Ordinal)))
                throw new ProviderException(SR.GetString(SR.ADMembership_OnlyLdap_supported));

            //
            // Parse out the server/domain information
            //
            NativeComInterfaces.IAdsPathname pathCracker = (NativeComInterfaces.IAdsPathname) new NativeComInterfaces.Pathname();

            try {
                pathCracker.Set(adspath, NativeComInterfaces.ADS_SETTYPE_FULL);
            }
            catch (COMException e)
            {
                if (e.ErrorCode == unchecked((int) 0x80005000))
                    throw new ProviderException(SR.GetString(SR.ADMembership_invalid_path));
                else
                    throw;
            }

            // Get the server and container names
            try
            {
                serverName = pathCracker.Retrieve(NativeComInterfaces.ADS_FORMAT_SERVER);
            }
            catch (COMException e)
            {
                if (e.ErrorCode == unchecked((int) 0x80005000))
                    throw new ProviderException(SR.GetString(SR.ADMembership_ServerlessADsPath_not_supported));
                else
                    throw;
            }
            Debug.Assert(serverName != null);

            creationContainerDN = containerDN = pathCracker.Retrieve(NativeComInterfaces.ADS_FORMAT_X500_DN);

            //
            // Parse out the port number if specified
            //
            int index = serverName.IndexOf(':');
            if (index != -1)
            {
                string tempStr = serverName;

                serverName = tempStr.Substring(0, index);

                Debug.Assert(tempStr.Length > index);
                port = Int32.Parse(tempStr.Substring(index + 1), NumberFormatInfo.InvariantInfo);
                portSpecified = true;
            }

            if (String.Compare(connProtection, "Secure", StringComparison.Ordinal) == 0)
            {
                //
                // The logic is as follows:
                // 1. Try Ssl first and check if concurrent binds are possible for validating users
                // 2. If Ssl is not supported, try signing and sealing
                // 3. If both the above are not supported, then we will fail
                //

                bool trySignAndSeal = false;
                bool trySslWithSecureAuth = false;

                // first try with simple bind
                if (!IsDefaultCredential())
                {

                    authenticationType = GetAuthenticationTypes(ActiveDirectoryConnectionProtection.Ssl, CredentialsType.NonWindows);
                    ldapAuthType = GetLdapAuthenticationTypes(ActiveDirectoryConnectionProtection.Ssl, CredentialsType.NonWindows);

                    try
                    {
                        rootdse = new DirectoryEntry(GetADsPath("rootdse"), GetUsername(), GetPassword(), authenticationType);
                        // this will force a bind
                        rootdse.RefreshCache();
                        this.connectionProtection = ActiveDirectoryConnectionProtection.Ssl;
                        if (!portSpecified)
                        {
                            port = SSL_PORT;
                            portSpecified = true;
                        }
                    }
                    catch (COMException ce)
                    {

                        if (ce.ErrorCode == unchecked((int) 0x8007052e))
                        {
                            //
                            // this could be an ADAM target with windows user (in that case simple bind will not work)
                            //
                            trySslWithSecureAuth = true;
                        }
                        else if (ce.ErrorCode == unchecked((int) 0x8007203a))
                        {
                            // server is not operational error, do nothing, we need to fall back to SignAndSeal
                            trySignAndSeal = true;
                        }
                        else
                            throw;
                     }
                }
                else
                {
                    // default credentials, so we have to do secure bind
                    trySslWithSecureAuth = true;
                }

                if (trySslWithSecureAuth)
                {

                    authenticationType = GetAuthenticationTypes(ActiveDirectoryConnectionProtection.Ssl, CredentialsType.Windows);
                    ldapAuthType = GetLdapAuthenticationTypes(ActiveDirectoryConnectionProtection.Ssl, CredentialsType.Windows);

                    try
                    {
                        rootdse = new DirectoryEntry(GetADsPath("rootdse"), GetUsername(), GetPassword(), authenticationType);
                        // this will force a bind
                        rootdse.RefreshCache();
                        this.connectionProtection = ActiveDirectoryConnectionProtection.Ssl;
                        if (!portSpecified)
                        {
                            port = SSL_PORT;
                            portSpecified = true;
                        }

                    }
                    catch (COMException ce)
                    {
                        if (ce.ErrorCode == unchecked((int) 0x8007203a))
                        {
                            // server is not operational error, do nothing, we need to fall back to SignAndSeal
                            trySignAndSeal = true;
                        }
                        else
                            throw;
                     }

                }

                if (trySignAndSeal)
                {
                    authenticationType = GetAuthenticationTypes(ActiveDirectoryConnectionProtection.SignAndSeal, CredentialsType.Windows);
                    ldapAuthType = GetLdapAuthenticationTypes(ActiveDirectoryConnectionProtection.SignAndSeal, CredentialsType.Windows);

                    try
                    {
                        rootdse = new DirectoryEntry(GetADsPath("rootdse"), GetUsername(), GetPassword(), authenticationType);
                        rootdse.RefreshCache();
                        this.connectionProtection = ActiveDirectoryConnectionProtection.SignAndSeal;
                    }
                    catch (COMException e)
                    {
                        throw new ProviderException(SR.GetString(SR.ADMembership_Secure_connection_not_established, e.Message), e);
                    }
                }
            }
            else
            {
                //
                // No connection protection
                //

                //
                // we will do a simple bind but we must ensure that the credentials are explicitly specified
                // since in the case of default credentials we cannot honor it (default credentials become anonymous in the case of
                // simple bind)
                //
                if (IsDefaultCredential())
                    throw new NotSupportedException(SR.GetString(SR.ADMembership_Default_Creds_not_supported));

                // simple bind
                authenticationType = GetAuthenticationTypes(connectionProtection, CredentialsType.NonWindows);
                ldapAuthType = GetLdapAuthenticationTypes(connectionProtection, CredentialsType.NonWindows);

                rootdse = new DirectoryEntry(GetADsPath("rootdse"), GetUsername(), GetPassword(), authenticationType);

            }

            //
            // Determine whether this is AD or ADAM by binding to the rootdse and
            // checking the supported capabilities
            //
            if (rootdse == null)
                rootdse = new DirectoryEntry(GetADsPath("RootDSE"), GetUsername(), GetPassword(), authenticationType);
            directoryType = GetDirectoryType();

            //
            // if the directory type is ADAM and the conntectionProtection was selected
            // as sign and seal, then we should throw an ProviderException. This is becuase validate user will always fail for ADAM
            // because ADAM does not support secure authentication for ADAM users.
            //
            if ((directoryType == DirectoryType.ADAM) && (this.connectionProtection == ActiveDirectoryConnectionProtection.SignAndSeal))
                throw new ProviderException(SR.GetString(SR.ADMembership_Ssl_connection_not_established));

            //
            // for AD, we need to block the GC ports
            //
            if ((directoryType == DirectoryType.AD) && ((port == GC_PORT) || (port == GC_SSL_PORT)))
                throw new ProviderException(SR.GetString(SR.ADMembership_GCPortsNotSupported));

            //
            // if container dn is null, we need to get the default naming context
            // (containerDN cannot be null for ADAM)
            //
            if (String.IsNullOrEmpty(containerDN))
            {
                if (directoryType == DirectoryType.AD)
                {
                    containerDN = (string)rootdse.Properties["defaultNamingContext"].Value;
                    if (containerDN == null)
                        throw new ProviderException(SR.GetString(SR.ADMembership_DefContainer_not_specified));

                    //
                    // we will create users in the default users container, check that it exists
                    //
                    string wkUsersContainerPath = GetADsPath("<WKGUID=" + GUID_USERS_CONTAINER_W + "," + containerDN + ">");
                    DirectoryEntry containerEntry = new DirectoryEntry(wkUsersContainerPath, GetUsername(), GetPassword(), authenticationType);

                    try
                    {
                        creationContainerDN = (string) PropertyManager.GetPropertyValue(containerEntry, "distinguishedName");
                    }
                    catch (COMException ce)
                    {
                        if (ce.ErrorCode == unchecked((int) 0x80072030))
                            throw new ProviderException(SR.GetString(SR.ADMembership_DefContainer_does_not_exist));
                        else
                            throw;
                    }
                }
                else
                {
                    // container must be specified for ADAM
                    throw new ProviderException(SR.GetString(SR.ADMembership_Container_must_be_specified));
                }
            }
            else
            {
                //
                // Normalize the container name (incase it was specified as GUID or WKGUID)
                //
                DirectoryEntry containerEntry = new DirectoryEntry(GetADsPath(containerDN), GetUsername(), GetPassword(), authenticationType);

                try
                {
                    creationContainerDN = containerDN = (string) PropertyManager.GetPropertyValue(containerEntry, "distinguishedName");
                }
                catch (COMException ce)
                {
                    if (ce.ErrorCode == unchecked((int) 0x80072030))
                        throw new ProviderException(SR.GetString(SR.ADMembership_Container_does_not_exist));
                    else
                        throw;
                }
            }

            //
            // Check if the specified path(container) exists on the specified server/domain
            // (NOTE: We need to do this using S.DS.Protocols rather than S.DS because we need to
            //            bypass the referral chasing which is automatic in S.DS)
            //

            LdapConnection tempConnection = new LdapConnection(new LdapDirectoryIdentifier(serverName + ":" + port), GetCredentialsWithDomain(credentials), ldapAuthType);
            tempConnection.SessionOptions.ProtocolVersion = 3;

            try
            {
                tempConnection.SessionOptions.ReferralChasing = System.DirectoryServices.Protocols.ReferralChasingOptions.None;
                SetSessionOptionsForSecureConnection(tempConnection, false /*useConcurrentBind */);
                tempConnection.Bind();


                SearchRequest request = new SearchRequest();
                request.DistinguishedName = containerDN;
                request.Filter = "(objectClass=*)";
                request.Scope = System.DirectoryServices.Protocols.SearchScope.Base;
                request.Attributes.Add("distinguishedName");
                request.Attributes.Add("objectClass");

                if (ServerSearchTimeout != -1)
                    request.TimeLimit = new TimeSpan(0, ServerSearchTimeout, 0);

                SearchResponse response;
                try
                {
                    response = (SearchResponse) tempConnection.SendRequest(request);
                    if (response.ResultCode == ResultCode.Referral || response.ResultCode ==  ResultCode.NoSuchObject)
                        throw new ProviderException(SR.GetString(SR.ADMembership_Container_does_not_exist));
                    else if (response.ResultCode != ResultCode.Success)
                        throw new ProviderException(response.ErrorMessage);
                }
                catch (DirectoryOperationException oe)
                {
                    SearchResponse errorResponse = (SearchResponse) oe.Response;
                    if (errorResponse.ResultCode == ResultCode.NoSuchObject)
                        throw new ProviderException(SR.GetString(SR.ADMembership_Container_does_not_exist));
                    else throw;
                }

                //
                // check that the container is of an object type that can be a superior of a user object
                //
                DirectoryAttribute objectClass = response.Entries[0].Attributes["objectClass"];
                if (!ContainerIsSuperiorOfUser(objectClass))
                    throw new ProviderException(SR.GetString(SR.ADMembership_Container_not_superior));

                //
                // Determine whether concurrent bind is supported
                //
                if ((connectionProtection == ActiveDirectoryConnectionProtection.None) || (connectionProtection == ActiveDirectoryConnectionProtection.Ssl))
                {
                    this.concurrentBindSupported = IsConcurrentBindSupported(tempConnection);
                }

            }
            finally
            {
                tempConnection.Dispose();
            }

            //
            // if this is ADAM, get the partition DN
            //
            if (directoryType == DirectoryType.ADAM)
            {
                adamPartitionDN = GetADAMPartitionFromContainer();
            }
            else
            {
                if (enablePasswordReset)
                {
                    // for AD, get the lockout duration for user account auto unlock
                    DirectoryEntry de = new DirectoryEntry(GetADsPath((string) PropertyManager.GetPropertyValue(rootdse, "defaultNamingContext")), GetUsername(), GetPassword(), AuthenticationTypes);
                    NativeComInterfaces.IAdsLargeInteger largeIntValue = (NativeComInterfaces.IAdsLargeInteger) PropertyManager.GetPropertyValue(de, "lockoutDuration");
                    Int64 int64Value = largeIntValue.HighPart * 0x100000000 + (uint) largeIntValue.LowPart;

                    // int64Value is the negative of the number of 100 nanoseconds interval that makes up the lockout duration
                    adLockoutDuration = new TimeSpan(-int64Value);
                }
            }
        }
 internal SearchResult(NetworkCredential parentCredentials, AuthenticationTypes parentAuthenticationType)
 {
     this.parentCredentials = parentCredentials;
     this.parentAuthenticationType = parentAuthenticationType;
 }
Exemple #12
0
        // Throws exception if ctxBase is not a computer object
        public SAMStoreCtx(DirectoryEntry ctxBase, bool ownCtxBase, string username, string password, ContextOptions options)
        {
            Debug.Assert(ctxBase != null);
            GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "Constructing SAMStoreCtx for {0}", ctxBase.Path);

            Debug.Assert(SAMUtils.IsOfObjectClass(ctxBase, "Computer"));

            _ctxBase = ctxBase;
            _ownCtxBase = ownCtxBase;

            if (username != null && password != null)
                _credentials = new NetCred(username, password);

            _contextOptions = options;
            _authTypes = SDSUtils.MapOptionsToAuthTypes(options);
        }
            internal ResultsEnumerator(SearchResultCollection results, string parentUserName, string parentPassword, AuthenticationTypes parentAuthenticationType)
            {
                if (parentUserName != null && parentPassword != null)
                    _parentCredentials = new NetworkCredential(parentUserName, parentPassword);

                _parentAuthenticationType = parentAuthenticationType;
                _results = results;
                _initialized = false;

                // get the app configuration information
                object o = PrivilegedConfigurationManager.GetSection("system.directoryservices");
                if (o != null && o is bool)
                {
                    _waitForResult = (bool)o;
                }
            }
        // {PropertyNames.GroupMembers,  "members",   null,                                                      new ToLdapConverterDelegate(GroupMembersToLdapConverter)},

        protected static void UpdateGroupMembership(Principal group, DirectoryEntry de, NetCred credentials, AuthenticationTypes authTypes)
        {
            Debug.Assert(group.fakePrincipal == false);

            PrincipalCollection members = (PrincipalCollection)group.GetValueForProperty(PropertyNames.GroupMembers);

            DirectoryEntry groupDe = null;

            try
            {
                //
                // Process clear
                //
                if (members.Cleared)
                {
                    DirectoryEntry copyOfDe = null;

                    try
                    {
                        GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "UpdateGroupMembership: clearing {0}", de.Path);

                        copyOfDe = SDSUtils.BuildDirectoryEntry(
                                                de.Path,
                                                credentials,
                                                authTypes);

                        Debug.Assert(copyOfDe != null);
                        copyOfDe.Properties["member"].Clear();
                        copyOfDe.CommitChanges();
                    }
                    finally
                    {
                        if (copyOfDe != null)
                            copyOfDe.Dispose();
                    }
                }

                //
                // Process inserted members
                //

                List<Principal> insertedMembers = members.Inserted;
                List<Principal> removedMembers = members.Removed;

                if (insertedMembers.Count > 0 || removedMembers.Count > 0)
                {
                    groupDe = SDSUtils.BuildDirectoryEntry(
                                            de.Path,
                                            credentials,
                                            authTypes);
                }

                // First, validate the members to be added
                foreach (Principal member in insertedMembers)
                {
                    Type memberType = member.GetType();
                    if ((memberType != typeof(UserPrincipal)) && (!memberType.IsSubclassOf(typeof(UserPrincipal))) &&
                        (memberType != typeof(ComputerPrincipal)) && (!memberType.IsSubclassOf(typeof(ComputerPrincipal))) &&
                        (memberType != typeof(GroupPrincipal)) && (!memberType.IsSubclassOf(typeof(GroupPrincipal))) &&
                        (!memberType.IsSubclassOf(typeof(AuthenticablePrincipal))))
                    {
                        throw new InvalidOperationException(
                                        String.Format(CultureInfo.CurrentCulture, StringResources.StoreCtxUnsupportedPrincipalTypeForGroupInsert, memberType.ToString()));
                    }
                    // Can't inserted unpersisted principal
                    if (member.unpersisted)
                        throw new InvalidOperationException(StringResources.StoreCtxGroupHasUnpersistedInsertedPrincipal);

                    Debug.Assert(member.Context != null);

                    // Can only insert AD principals (no reg-SAM/MSAM principals)
                    if (member.ContextType == ContextType.Machine)
                        throw new InvalidOperationException(StringResources.ADStoreCtxUnsupportedPrincipalContextForGroupInsert);
                }

                // Now add each member to the group
                foreach (Principal member in insertedMembers)
                {
                    // For objects in the current domain or any other domains in the forest we need to use the objects DN
                    // SID path would work for current domain but would not work for child or parent domains.
                    // For foreign objects we must use SID path e.g.  "<SID=...>" so that the necessary FPO gets autocreated by AD.
                    // It also works in the "fake principal" case (which are always represented as FPOs).
                    if (!member.fakePrincipal && ADUtils.ArePrincipalsInSameForest(group, member))
                    {
                        GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "UpdateGroupMembership: add {0}", member.DistinguishedName);

                        groupDe.Properties["member"].Add(member.DistinguishedName);
                    }
                    else
                    {
                        // Build a SID DN.  This needs to be a DN path not an ADSI sid path with the LDAP prefix.
                        string memberSidDN = GetSidPathFromPrincipal(member);

                        if (memberSidDN == null)
                            throw new PrincipalOperationException(StringResources.ADStoreCtxCouldntGetSIDForGroupMember);

                        GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "UpdateGroupMembership: add {0}", memberSidDN);

                        // Add the member to the group
                        groupDe.Properties["member"].Add(memberSidDN);
                    }
                }

                // If we had any members then commit them.
                if (insertedMembers.Count > 0)
                    groupDe.CommitChanges();

                //
                // Process removed members
                //

                foreach (Principal member in removedMembers)
                {
                    // Since we don't allow any of these to be inserted, none of them should ever
                    // show up in the removal list
                    Debug.Assert(member.unpersisted == false);
                    Debug.Assert(member.ContextType == ContextType.Domain || member.ContextType == ContextType.ApplicationDirectory);

                    // If the collection was cleared, there should be no original members to remove
                    Debug.Assert(members.Cleared == false);

                    // Since we are using PropertyValueCollection to do the item removal we are constrainted to items that are in the collection
                    // For principals that are in the same forest just use their DN to do the removal.  This is how they are represented in the member attr.
                    // For foreign principals we must represent them with their SID binding string since they are locally represented by an FSP object.
                    if (!member.fakePrincipal && ADUtils.ArePrincipalsInSameForest(group, member))
                    {
                        GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "UpdateGroupMembership: remove via DN {0}", member.DistinguishedName);

                        // Remove the member from the group

                        groupDe.Properties["member"].Remove(member.DistinguishedName);
                    }
                    else
                    {
                        // SID DN case

                        // Build a SID DN.
                        string memberSidDN = GetSidPathFromPrincipal(member);

                        if (memberSidDN == null)
                            throw new PrincipalOperationException(StringResources.ADStoreCtxCouldntGetSIDForGroupMember);

                        GlobalDebug.WriteLineIf(GlobalDebug.Info, "ADStoreCtx", "UpdateGroupMembership: remove via SID {0}", memberSidDN);

                        // Remove the member from the group
                        groupDe.Properties["member"].Remove(memberSidDN);
                    }
                }

                // If we used the collection to do a modification then commit it.
                if (removedMembers.Count > 0)
                    groupDe.CommitChanges();
            }
            catch (System.Runtime.InteropServices.COMException e)
            {
                throw ExceptionHelper.GetExceptionFromCOMException(e);
            }
            finally
            {
                if (null != groupDe)
                    groupDe.Dispose();
            }
        }