Skip to content

Commit

Permalink
wip: add some missing functions
Browse files Browse the repository at this point in the history
  • Loading branch information
rvazarkar committed Jun 28, 2024
1 parent 6d9003f commit 48e4eff
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 23 deletions.
3 changes: 3 additions & 0 deletions src/CommonLib/ILdapUtilsNew.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ IAsyncEnumerable<Result<string>> RangedRetrieval(string distinguishedName,

public Task<(bool Success, TypedPrincipal Principal)> ConvertLocalWellKnownPrincipal(SecurityIdentifier sid,
string computerDomainSid, string computerDomain);

public Task<bool> IsDomainController(string computerObjectId, string domainName);
public Task<(bool Success, TypedPrincipal Principal)> LookupDistinguishedName(string distinguishedName);
}
154 changes: 131 additions & 23 deletions src/CommonLib/LdapUtilsNew.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;

Check failure on line 5 in src/CommonLib/LdapUtilsNew.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'AccountManagement' does not exist in the namespace 'System.DirectoryServices' (are you missing an assembly reference?)

Check failure on line 5 in src/CommonLib/LdapUtilsNew.cs

View workflow job for this annotation

GitHub Actions / build

The type or namespace name 'AccountManagement' does not exist in the namespace 'System.DirectoryServices' (are you missing an assembly reference?)
using System.DirectoryServices.ActiveDirectory;
using System.DirectoryServices.Protocols;
using System.Linq;
Expand Down Expand Up @@ -37,6 +38,9 @@ private static readonly ConcurrentDictionary<string, ResolvedWellKnownPrincipal>
SeenWellKnownPrincipals = new();

private readonly ConcurrentDictionary<string, string> _hostResolutionMap = new(StringComparer.OrdinalIgnoreCase);

private readonly ConcurrentDictionary<string, TypedPrincipal> _distinguishedNameCache =
new(StringComparer.OrdinalIgnoreCase);
private readonly ILogger _log;
private readonly PortScanner _portScanner;
private readonly NativeMethods _nativeMethods;
Expand Down Expand Up @@ -516,12 +520,28 @@ public async IAsyncEnumerable<LdapResult<ISearchResultEntry>> PagedQuery(LdapQue
Cache.AddType(sid, type);
return (true, type);
}

return (false, Label.Base);
}
catch {
return (false, Label.Base);
//pass
}

using (var ctx = new PrincipalContext(ContextType.Domain)) {
try {
var principal = Principal.FindByIdentity(ctx, IdentityType.Sid, sid);
if (principal != null) {
var entry = (DirectoryEntry)principal.GetUnderlyingObject();
if (entry.GetLabel(out type)) {
Cache.AddType(sid, type);
return (true, type);
}
}
}
catch {
//pass
}
}

return (false, Label.Base);
}

private async Task<(bool Success, Label type)> LookupGuidType(string guid, string domain) {
Expand All @@ -547,12 +567,28 @@ public async IAsyncEnumerable<LdapResult<ISearchResultEntry>> PagedQuery(LdapQue
Cache.AddType(guid, type);
return (true, type);
}

return (false, Label.Base);
}
catch {
return (false, Label.Base);
//pass
}

using (var ctx = new PrincipalContext(ContextType.Domain)) {
try {
var principal = Principal.FindByIdentity(ctx, IdentityType.Guid, guid);
if (principal != null) {
var entry = (DirectoryEntry)principal.GetUnderlyingObject();
if (entry.GetLabel(out type)) {
Cache.AddType(guid, type);
return (true, type);
}
}
}
catch {
//pass
}
}

return (false, Label.Base);
}

public async Task<(bool Success, TypedPrincipal WellKnownPrincipal)> GetWellKnownPrincipal(
Expand Down Expand Up @@ -763,7 +799,7 @@ private SearchRequest CreateSearchRequest(string distinguishedName, string ldapF
var entry = new DirectoryEntry($"LDAP://<SID={domainSid}>");
entry.RefreshCache(new[] { LDAPProperties.DistinguishedName });
var dn = entry.GetProperty(LDAPProperties.DistinguishedName);
if (!string.IsNullOrEmpty(dn)) {
if (!string.IsNullOrWhiteSpace(dn)) {
Cache.AddDomainSidMapping(domainSid, Helpers.DistinguishedNameToDomain(dn));
return (true, Helpers.DistinguishedNameToDomain(dn));
}
Expand All @@ -777,6 +813,22 @@ private SearchRequest CreateSearchRequest(string distinguishedName, string ldapF
return (true, domainName);
}

using (var ctx = new PrincipalContext(ContextType.Domain)) {
try {
var principal = Principal.FindByIdentity(ctx, IdentityType.Sid, sid);
if (principal != null) {
var dn = principal.DistinguishedName;
if (!string.IsNullOrWhiteSpace(dn)) {
Cache.AddDomainSidMapping(domainSid, Helpers.DistinguishedNameToDomain(dn));
return (true, Helpers.DistinguishedNameToDomain(dn));
}
}
}
catch {
//pass
}
}

return (false, string.Empty);
}

Expand Down Expand Up @@ -1237,29 +1289,85 @@ public ActiveDirectorySecurityDescriptor MakeSecurityDescriptor() {
}

public async Task<(bool Success, TypedPrincipal Principal)> ConvertLocalWellKnownPrincipal(SecurityIdentifier sid, string computerDomainSid, string computerDomain) {
if (WellKnownPrincipal.GetWellKnownPrincipal(sid.Value, out var common))
if (!WellKnownPrincipal.GetWellKnownPrincipal(sid.Value, out var common)) return (false, null);
//The everyone and auth users principals are special and will be converted to the domain equivalent
if (sid.Value is "S-1-1-0" or "S-1-5-11")
{
//The everyone and auth users principals are special and will be converted to the domain equivalent
if (sid.Value is "S-1-1-0" or "S-1-5-11")
return await GetWellKnownPrincipal(sid.Value, computerDomain);
}

//Use the computer object id + the RID of the sid we looked up to create our new principal
var principal = new TypedPrincipal
{
ObjectIdentifier = $"{computerDomainSid}-{sid.Rid()}",
ObjectType = common.ObjectType switch
{
return await GetWellKnownPrincipal(sid.Value, computerDomain);
Label.User => Label.LocalUser,
Label.Group => Label.LocalGroup,
_ => common.ObjectType
}
};

//Use the computer object id + the RID of the sid we looked up to create our new principal
var principal = new TypedPrincipal
{
ObjectIdentifier = $"{computerDomainSid}-{sid.Rid()}",
ObjectType = common.ObjectType switch
{
Label.User => Label.LocalUser,
Label.Group => Label.LocalGroup,
_ => common.ObjectType
}
};
return (true, principal);

}

public async Task<bool> IsDomainController(string computerObjectId, string domainName)
{
var filter = new LDAPFilter().AddFilter(CommonFilters.SpecificSID(computerObjectId), true)
.AddFilter(CommonFilters.DomainControllers, true);
var result = await Query(new LdapQueryParameters() {
DomainName = domainName,
Attributes = CommonProperties.ObjectID,
LDAPFilter = filter.GetFilter(),
}).DefaultIfEmpty(null).FirstOrDefaultAsync();
return result is { IsSuccess: true };
}

public async Task<(bool Success, TypedPrincipal Principal)> LookupDistinguishedName(string distinguishedName) {
if (_distinguishedNameCache.TryGetValue(distinguishedName, out var principal)) {
return (true, principal);
}

return (false, null);
var domain = Helpers.DistinguishedNameToDomain(distinguishedName);
var result = await Query(new LdapQueryParameters {
DomainName = domain,
Attributes = CommonProperties.TypeResolutionProps,
SearchBase = distinguishedName,
SearchScope = SearchScope.Base,
LDAPFilter = new LDAPFilter().AddAllObjects().GetFilter()
}).DefaultIfEmpty(null).FirstOrDefaultAsync();

if (result is { IsSuccess: true }) {
var entry = result.Value;
var id = entry.GetObjectIdentifier();
if (id == null) {
return (false, default);
}

if (await GetWellKnownPrincipal(id, domain) is (true, var wellKnownPrincipal)) {
_distinguishedNameCache.TryAdd(distinguishedName, wellKnownPrincipal);
return (true, wellKnownPrincipal);
}

var type = entry.GetLabel();
principal = new TypedPrincipal(id, type);
_distinguishedNameCache.TryAdd(distinguishedName, principal);
return (true, principal);
}

using (var ctx = new PrincipalContext(ContextType.Domain)) {
try {
var lookupPrincipal = Principal.FindByIdentity(ctx, IdentityType.DistinguishedName, distinguishedName);
if (lookupPrincipal != null && ((DirectoryEntry)lookupPrincipal.GetUnderlyingObject()).GetTypedPrincipal(out principal)) {
return (true, principal);
}

return (false, default);
}
catch {
return (false, default);
}
}
}
}

0 comments on commit 48e4eff

Please sign in to comment.