Skip to content

Commit

Permalink
PingCastle 2.6.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
vletoux committed Jan 30, 2019
1 parent a30c639 commit 7b63f84
Show file tree
Hide file tree
Showing 199 changed files with 16,284 additions and 9,157 deletions.
20 changes: 14 additions & 6 deletions ADWS/ADConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
//
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Text;

namespace PingCastle.ADWS
{
public abstract class ADConnection
public abstract class ADConnection : IADConnection
{

public abstract void Enumerate(string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback, string scope);
public abstract void EnumerateUsingWorkerThread(string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback, string scope);
public abstract void EstablishConnection();

public string Server { get; set; }
Expand Down Expand Up @@ -52,10 +52,18 @@ public static string EscapeLDAP(string input)

public static string EncodeSidToString(string sid)
{
var realsid = new System.Security.Principal.SecurityIdentifier(sid);
var bytesid = new byte[realsid.BinaryLength];
realsid.GetBinaryForm(bytesid, 0);
return "\\" + BitConverter.ToString(bytesid).Replace("-", "\\");
try
{
var realsid = new System.Security.Principal.SecurityIdentifier(sid);
var bytesid = new byte[realsid.BinaryLength];
realsid.GetBinaryForm(bytesid, 0);
return "\\" + BitConverter.ToString(bytesid).Replace("-", "\\");
}
catch (ArgumentException)
{
Trace.WriteLine("Unable to encode " + sid);
throw;
}
}
}
}
7 changes: 4 additions & 3 deletions ADWS/ADDomainInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,10 @@ private static int ExtractIntValue(XmlNode item)
public static ADDomainInfo Create(DirectoryEntry rootDSE)
{
ADDomainInfo info = new ADDomainInfo();
info.DefaultNamingContext = rootDSE.Properties["defaultNamingContext"].Value as string;
info.ConfigurationNamingContext = rootDSE.Properties["configurationNamingContext"].Value as string;
info.DnsHostName = rootDSE.Properties["dnsHostName"].Value as string;
Trace.WriteLine("rootDse property count: " + rootDSE.Properties.Count);
info.DefaultNamingContext = rootDSE.Properties["defaultNamingContext"].Value as string;
info.ConfigurationNamingContext = rootDSE.Properties["configurationNamingContext"].Value as string;
info.DnsHostName = rootDSE.Properties["dnsHostName"].Value as string;
if (rootDSE.Properties.Contains("domainFunctionality"))
info.DomainFunctionality = int.Parse(rootDSE.Properties["domainFunctionality"].Value as string);
if (rootDSE.Properties.Contains("forestFunctionality"))
Expand Down
14 changes: 14 additions & 0 deletions ADWS/ADItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public class ReplPropertyMetaDataItem
public byte[] SchemaInfo { get; set; }
public string ScriptPath { get; set; }
public SecurityIdentifier SecurityIdentifier { get; set; }
public string[] ServicePrincipalName { get; set; }
public SecurityIdentifier[] SIDHistory { get; set; }
public string[] SiteObjectBL { get; set; }
public int TrustAttributes { get; set; }
Expand Down Expand Up @@ -435,6 +436,9 @@ public static ADItem Create(XmlElement item)
case "securityIdentifier":
aditem.SecurityIdentifier = ExtractSIDValue(child);
break;
case "servicePrincipalName":
aditem.ServicePrincipalName = ExtractStringArrayValue(child);
break;
case "sIDHistory":
aditem.SIDHistory = ExtractSIDArrayValue(child);
break;
Expand Down Expand Up @@ -646,6 +650,16 @@ public static ADItem Create(SearchResult sr, bool nTSecurityDescriptor)
case "securityidentifier":
aditem.SecurityIdentifier = new SecurityIdentifier((byte[])sr.Properties[name][0], 0);
break;
case "serviceprincipalname":
{
List<string> list = new List<string>();
foreach (string data in sr.Properties[name])
{
list.Add(data);
}
aditem.ServicePrincipalName = list.ToArray();
}
break;
case "sidhistory":
{
List<SecurityIdentifier> list = new List<SecurityIdentifier>();
Expand Down
76 changes: 14 additions & 62 deletions ADWS/ADWSConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,72 +327,24 @@ public override void Enumerate(string distinguishedName, string filter, string[]
{
foreach (XmlElement item in items.Any)
{
ADItem aditem = ADItem.Create(item);
callback(aditem);
}
}
}
);
}

// 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 = null;
try
{
ADItem aditem = ADItem.Create(item);
try
{
callback(aditem);
}
catch (Exception ex)
{
Trace.WriteLine("Exception in workerthread:" + ex.Message);
Trace.WriteLine(ex.StackTrace);
}
aditem = ADItem.Create(item);
}
catch (Exception ex)
{
Console.WriteLine("Warning: unable to process element (" + ex.Message + ")\r\n" + item.OuterXml);
Trace.WriteLine("Warning: unable to process element\r\n" + item.OuterXml);
Trace.WriteLine("Exception: " + ex.Message);
Trace.WriteLine(ex.StackTrace);
}
if (aditem != null)
callback(aditem);
}
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();
}
);
}

XmlQualifiedName[] BuildProperties(List<string> properties)
Expand Down Expand Up @@ -535,7 +487,7 @@ private void EnumerateInternalWithADWS(string distinguishedName, string filter,
var stringValue = Convert.ToString(stringWriter);
Trace.WriteLine("Detail:");
Trace.WriteLine(stringValue);
throw new ApplicationException("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");
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)
Expand Down
33 changes: 28 additions & 5 deletions ADWS/ADWebService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ public ADWebService(string server, int port, NetworkCredential credential)

public NetworkCredential Credential { get; set; }

private ADConnection connection { get; set; }
private IADConnection connection { get; set; }
private IADConnection fallBackConnection { get; set; }

#region connection establishment
private void EstablishConnection()
Expand Down Expand Up @@ -91,6 +92,7 @@ private void EstablishConnection()
adwsConnection.EstablishConnection();
Trace.WriteLine("ADWS connection successful");
connection = adwsConnection;
fallBackConnection = new LDAPConnection(adwsConnection.Server, adwsConnection.Port, Credential);
}
catch (Exception ex)
{
Expand All @@ -117,6 +119,7 @@ private void EstablishConnection()
ldapConnection.EstablishConnection();
Trace.WriteLine("LDAP connection successful");
connection = ldapConnection;
fallBackConnection = new ADWSConnection(adwsConnection.Server, adwsConnection.Port, Credential);
}
catch (Exception ex)
{
Expand Down Expand Up @@ -232,17 +235,37 @@ public List<OUExploration> BuildOUExplorationList(string OU, int NumberOfDepthFo

public void Enumerate(string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback)
{
Enumerate(distinguishedName, filter, properties, callback, "Subtree");
Enumerate(null, distinguishedName, filter, properties, callback, "Subtree");
}

public void Enumerate(string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback, string scope)
{
connection.Enumerate(distinguishedName, filter, properties, callback, scope);
Enumerate(null, distinguishedName, filter, properties, callback, scope);
}

public void EnumerateUsingWorkerThread(string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback, string scope)
public delegate void Action();

public void Enumerate(Action preambleWithReentry, string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback, string scope)
{
connection.EnumerateUsingWorkerThread(distinguishedName, filter, properties, callback, scope);
if (preambleWithReentry != null)
preambleWithReentry();
try
{
connection.Enumerate(distinguishedName, filter, properties, callback, scope);
}
catch (Exception ex)
{
Trace.WriteLine("Exception: " + ex.Message);
Trace.WriteLine("StackTrace: " + ex.StackTrace);
if (fallBackConnection == null)
throw;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("The AD query failed. Using the alternative protocol (" + fallBackConnection.GetType().Name + ")");
Console.ResetColor();
if (preambleWithReentry != null)
preambleWithReentry();
fallBackConnection.Enumerate(distinguishedName, filter, properties, callback, scope);
}
}

#region IDispose
Expand Down
2 changes: 1 addition & 1 deletion Healthcheck/DomainLocator.cs → ADWS/DomainLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
using System.Security.Permissions;
using System.Text;

namespace PingCastle.Healthcheck
namespace PingCastle.ADWS
{
public class DomainLocator
{
Expand Down
14 changes: 14 additions & 0 deletions ADWS/IADConnection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace PingCastle.ADWS
{
public interface IADConnection
{
ADDomainInfo GetDomainInfo();

void Enumerate(string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback, string scope);

}
}
34 changes: 24 additions & 10 deletions ADWS/LDAPConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,6 @@ public override void Enumerate(string distinguishedName, string filter, string[]
EnumerateInternalWithLDAP(distinguishedName, filter, properties, scope, callback);
}

public override void EnumerateUsingWorkerThread(string distinguishedName, string filter, string[] properties, WorkOnReturnedObjectByADWS callback, string scope)
{
EnumerateInternalWithLDAP(distinguishedName, filter, properties, scope, callback);
}


[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
private void EnumerateInternalWithLDAP(string distinguishedName, string filter, string[] properties, string scope, WorkOnReturnedObjectByADWS callback)
{
Expand All @@ -46,11 +40,11 @@ private void EnumerateInternalWithLDAP(string distinguishedName, string filter,
{
if (Credential == null)
{
entry = new DirectoryEntry(@"LDAP://" + Server + "/" + distinguishedName, null, null, AuthenticationTypes.ServerBind | AuthenticationTypes.Secure);
entry = new DirectoryEntry(@"LDAP://" + Server + (Port == 0 ? null : ":" + Port) + "/" + distinguishedName, null, null, AuthenticationTypes.ServerBind | AuthenticationTypes.Secure | (Port == 636 ? AuthenticationTypes.SecureSocketsLayer:0));
}
else
{
entry = new DirectoryEntry(@"LDAP://" + Server + "/" + distinguishedName, Credential.UserName, Credential.Password, AuthenticationTypes.ServerBind | AuthenticationTypes.Secure);
entry = new DirectoryEntry(@"LDAP://" + Server + (Port == 0 ? null : ":" + Port) + "/" + distinguishedName, Credential.UserName, Credential.Password, AuthenticationTypes.ServerBind | AuthenticationTypes.Secure | (Port == 636 ? AuthenticationTypes.SecureSocketsLayer : 0));
}

DirectorySearcher clsDS = new DirectorySearcher(entry);
Expand Down Expand Up @@ -83,8 +77,20 @@ private void EnumerateInternalWithLDAP(string distinguishedName, string filter,
Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "]Calling FindAll");
foreach (SearchResult sr in clsDS.FindAll())
{
ADItem aditem = ADItem.Create(sr, nTSecurityDescriptor);
callback(aditem);
ADItem aditem = null;
try
{
aditem = ADItem.Create(sr, nTSecurityDescriptor);
}
catch (Exception ex)
{
Console.WriteLine("Warning: unable to process element (" + ex.Message + ")\r\n" + sr.Path);
Trace.WriteLine("Warning: unable to process element\r\n" + sr.Path);
Trace.WriteLine("Exception: " + ex.Message);
Trace.WriteLine(ex.StackTrace);
}
if (aditem != null)
callback(aditem);
numberOfObjectAlreadyExtracted++;
}
Trace.WriteLine("[" + DateTime.Now.ToLongTimeString() + "]Enumeration successful");
Expand Down Expand Up @@ -114,6 +120,14 @@ protected override ADDomainInfo GetDomainInfoInternal()
private ADDomainInfo GetLDAPDomainInfo()
{
DirectoryEntry rootDse = new DirectoryEntry("LDAP://" + Server + "/RootDSE");
if (Credential == null)
{
rootDse = new DirectoryEntry(@"LDAP://" + Server + (Port == 0 ? null : ":" + Port) + "/RootDSE", null, null, AuthenticationTypes.ServerBind | AuthenticationTypes.Secure | (Port == 636 ? AuthenticationTypes.SecureSocketsLayer : 0));
}
else
{
rootDse = new DirectoryEntry(@"LDAP://" + Server + (Port == 0 ? null : ":" + Port) + "/RootDSE", Credential.UserName, Credential.Password, AuthenticationTypes.ServerBind | AuthenticationTypes.Secure | (Port == 636 ? AuthenticationTypes.SecureSocketsLayer : 0));
}
return ADDomainInfo.Create(rootDse);
}

Expand Down
Loading

0 comments on commit 7b63f84

Please sign in to comment.