From 48e4eff077ed03201b812aaac59bdfdd2a0cf4ea Mon Sep 17 00:00:00 2001 From: rvazarkar Date: Fri, 28 Jun 2024 16:23:24 -0400 Subject: [PATCH] wip: add some missing functions --- src/CommonLib/ILdapUtilsNew.cs | 3 + src/CommonLib/LdapUtilsNew.cs | 154 ++++++++++++++++++++++++++++----- 2 files changed, 134 insertions(+), 23 deletions(-) diff --git a/src/CommonLib/ILdapUtilsNew.cs b/src/CommonLib/ILdapUtilsNew.cs index 4320a264..13dd628c 100644 --- a/src/CommonLib/ILdapUtilsNew.cs +++ b/src/CommonLib/ILdapUtilsNew.cs @@ -40,4 +40,7 @@ IAsyncEnumerable> RangedRetrieval(string distinguishedName, public Task<(bool Success, TypedPrincipal Principal)> ConvertLocalWellKnownPrincipal(SecurityIdentifier sid, string computerDomainSid, string computerDomain); + + public Task IsDomainController(string computerObjectId, string domainName); + public Task<(bool Success, TypedPrincipal Principal)> LookupDistinguishedName(string distinguishedName); } \ No newline at end of file diff --git a/src/CommonLib/LdapUtilsNew.cs b/src/CommonLib/LdapUtilsNew.cs index e614a690..afcb668f 100644 --- a/src/CommonLib/LdapUtilsNew.cs +++ b/src/CommonLib/LdapUtilsNew.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.DirectoryServices; +using System.DirectoryServices.AccountManagement; using System.DirectoryServices.ActiveDirectory; using System.DirectoryServices.Protocols; using System.Linq; @@ -37,6 +38,9 @@ private static readonly ConcurrentDictionary SeenWellKnownPrincipals = new(); private readonly ConcurrentDictionary _hostResolutionMap = new(StringComparer.OrdinalIgnoreCase); + + private readonly ConcurrentDictionary _distinguishedNameCache = + new(StringComparer.OrdinalIgnoreCase); private readonly ILogger _log; private readonly PortScanner _portScanner; private readonly NativeMethods _nativeMethods; @@ -516,12 +520,28 @@ public async IAsyncEnumerable> 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) { @@ -547,12 +567,28 @@ public async IAsyncEnumerable> 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( @@ -763,7 +799,7 @@ private SearchRequest CreateSearchRequest(string distinguishedName, string ldapF var entry = new DirectoryEntry($"LDAP://"); 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)); } @@ -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); } @@ -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 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); + } + } } } \ No newline at end of file