private void EnumerateInternalWithADWS(string distinguishedName, string filter, string[] properties, string scope, ReceiveItems callback)
        {
            bool          nTSecurityDescriptor = false;
            List <string> listproperties       = new List <string>();

            Enumerate enumerate = new Enumerate();

            enumerate.Filter                      = new FilterType();
            enumerate.Filter.LdapQuery            = new LdapQuery();
            enumerate.Filter.LdapQuery.BaseObject = distinguishedName;
            Trace.WriteLine("LdapQuery.BaseObject=" + enumerate.Filter.LdapQuery.BaseObject);

            enumerate.Filter.LdapQuery.Scope  = scope;
            enumerate.Filter.LdapQuery.Filter = filter;
            Trace.WriteLine("LdapQuery.Filter=" + enumerate.Filter.LdapQuery.Filter);

            if (properties != null)
            {
                listproperties.AddRange(properties);
                enumerate.Selection = new Selection();

                enumerate.Selection.SelectionProperty = BuildProperties(listproperties);
            }
            EnumerateResponse enumerateResponse = null;

            Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] Running enumeration");
            bool hasNewProperties = true;

            while (hasNewProperties)
            {
                try
                {
                    enumerateResponse = Search.Enumerate(enumerate);
                    hasNewProperties  = false;
                }
                catch (FaultException <schemas.microsoft.com._2008._1.ActiveDirectory.EnumerateFault> ex)
                {
                    // handle the case where the property is not available in the schema.
                    // an exception is thrown
                    // remove the litigious property and resume the query
                    Trace.WriteLine("The server doesn't support the property: " + ex.Detail.InvalidProperty);
                    int    postns   = ex.Detail.InvalidProperty.IndexOf(':');
                    string property = ex.Detail.InvalidProperty;
                    if (postns > 0)
                    {
                        property = ex.Detail.InvalidProperty.Substring(postns + 1);
                    }
                    if (!listproperties.Remove(property))
                    {
                        throw;
                    }
                    if (listproperties.Count == 0)
                    {
                        return;
                    }
                    enumerate.Selection.SelectionProperty = BuildProperties(listproperties);
                }
            }
            Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "]Enumeration successful");
            Trace.WriteLine("Enumeration expires at " + enumerateResponse.Expires);
            Trace.WriteLine("Enumeration context is " + String.Join(",", enumerateResponse.EnumerationContext.Text));

            // prepare the flag for the ntsecuritydescriptor
            foreach (string property in listproperties)
            {
                if (String.Compare("nTSecurityDescriptor", property, true) == 0)
                {
                    nTSecurityDescriptor = true;
                }
            }

            // do not fail if the expiration cannot be parsed
            DateTime expiration = DateTime.Now.AddMinutes(30);

            DateTime.TryParse(enumerateResponse.Expires, out expiration);

            bool bcontinue = true;
            int  pagenum   = 0;

            while (bcontinue)
            {
                if (expiration.AddMinutes(-5) < DateTime.Now)
                {
                    Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "]Renewing the enumeration (expiration)");
                    Renew renew = new Renew();
                    renew.EnumerationContext = enumerateResponse.EnumerationContext;
                    renew.Expires            = DateTime.Now.AddMinutes(20).ToString("O");
                    RenewResponse renewresponse = Search.Renew(renew);
                    Trace.WriteLine("New expiration at " + renewresponse.Expires);
                    DateTime.TryParse(renewresponse.Expires, out expiration);
                    Trace.WriteLine("New enumeration context " + String.Join(",", renewresponse.EnumerationContext.Text));
                    enumerateResponse.EnumerationContext = renewresponse.EnumerationContext;
                }
                Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "]Getting Enumerate page " + pagenum);
                Pull pull = new Pull();
                pull.EnumerationContext = enumerateResponse.EnumerationContext;
                pull.MaxElements        = "500";
                if (nTSecurityDescriptor || DomainScope)
                {
                    List <controlsControl> controls = new List <controlsControl>();
                    if (nTSecurityDescriptor)
                    {
                        // this is the flag https://msdn.microsoft.com/en-us/library/cc223323.aspx
                        // the last byte, 0x07, is OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
                        controlsControl control = new controlsControl();
                        controls.Add(control);
                        control.controlValue = Convert.ToBase64String(new byte[] { 0x30, 0x84, 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x07 });
                        control.criticality  = true;
                        control.type         = "1.2.840.113556.1.4.801";
                    }
                    if (DomainScope)
                    {
                        // this is the flag https://msdn.microsoft.com/en-us/library/cc223323.aspx
                        // the last byte, 0x07, is OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION
                        controlsControl control = new controlsControl();
                        controls.Add(control);
                        control.criticality = true;
                        control.type        = "1.2.840.113556.1.4.1339";
                    }
                    pull.controls = controls.ToArray();
                }

                PullResponse pullResponse = null;
                try
                {
                    pullResponse = Search.Pull(pull);
                }
                catch (FaultException ex)
                {
                    Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "]Pull unsuccessful");
                    Trace.WriteLine("Fault Exception: " + ex.Message);
                    Trace.WriteLine("Reason: " + ex.Reason);
                    var stringWriter  = new StringWriter();
                    var xmlTextWriter = new XmlTextWriter(stringWriter);
                    var messageFault  = ex.CreateMessageFault();
                    messageFault.WriteTo(xmlTextWriter, EnvelopeVersion.Soap12);
                    var stringValue = Convert.ToString(stringWriter);
                    Trace.WriteLine("Detail:");
                    Trace.WriteLine(stringValue);
                    throw new PingCastleException("An ADWS exception occured (fault:" + ex.Message + ";reason:" + ex.Reason + ").\r\nADWS is a faster protocol than LDAP but bound to a default 30 minutes limitation. If this error persists, we recommand to force the LDAP protocol. Run PingCastle with the following switches: --protocol LDAPOnly --interactive");
                }
                Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "]Pull successful");
                if (pullResponse.EndOfSequence != null)
                {
                    bcontinue = false;
                }
                callback(pullResponse.Items);
                pagenum++;
            }
            Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "]Releasing the enumeration context");
            Release relase = new Release();

            relase.EnumerationContext = enumerateResponse.EnumerationContext;
            Search.Release(relase);
        }
Exemple #2
0
        // translation securitydescriptor can take of lot of CPU
        public override void EnumerateUsingWorkerThread(string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback, string scope)
        {
            BlockingQueue <ItemListType> queue = new BlockingQueue <ItemListType>(600);
            // background thread
            Thread workingthread = null;

            try
            {
                workingthread = new Thread(
                    () =>
                {
                    ItemListType items = null;
                    for (; ;)
                    {
                        if (!queue.Dequeue(out items))
                        {
                            break;
                        }
                        foreach (XmlElement item in items.Any)
                        {
                            ADItem aditem = ADItem.Create(item);
                            try
                            {
                                callback(aditem);
                            }
                            catch (Exception ex)
                            {
                                Trace.WriteLine("Exception in workerthread:" + ex.Message);
                                Trace.WriteLine(ex.StackTrace);
                            }
                        }
                    }
                    Trace.WriteLine("Exiting worker thread");
                }
                    );

                ReceiveItems callbackInternal = (ItemListType items)
                                                =>
                {
                    if (items != null)
                    {
                        queue.Enqueue(items);
                    }
                }
                ;

                workingthread.Start();
                EnumerateInternalWithADWS(distinguishedName, filter, properties, scope, callbackInternal);
                Trace.WriteLine("Done enumerating objects at: " + DateTime.Now);
                queue.Quit();
                workingthread.Join();
                Trace.WriteLine("Enumeration using worker thread complete");
            }
            finally
            {
                queue.Quit();
                if (workingthread != null)
                {
                    if (workingthread.ThreadState == System.Threading.ThreadState.Running)
                    {
                        workingthread.Abort();
                    }
                }
            }
        }