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); }
// 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(); } } } }