diff --git a/src/Runtime/ObjectProcessors.cs b/src/Runtime/ObjectProcessors.cs index 66c975f..c54fe14 100644 --- a/src/Runtime/ObjectProcessors.cs +++ b/src/Runtime/ObjectProcessors.cs @@ -137,6 +137,8 @@ internal async Task ProcessObject(IDirectoryObject entry, ResolvedSe return await ProcessSiteServerObject(entry, resolvedSearchResult); case Label.SiteSubnet: return await ProcessSiteSubnetObject(entry, resolvedSearchResult); + case Label.DMSA: + return await ProcessDMSAObject(entry, resolvedSearchResult); case Label.Base: return null; default: @@ -248,6 +250,46 @@ await _containerProcessor.GetContainingObject(dn) is (true, var container)) return ret; } + private async Task ProcessDMSAObject(IDirectoryObject entry, + ResolvedSearchResult resolvedSearchResult) { + var ret = new DMSA { + ObjectIdentifier = resolvedSearchResult.ObjectId, + Properties = new Dictionary(GetCommonProperties(entry, resolvedSearchResult)) { + { "samaccountname", entry.GetProperty(LDAPProperties.SAMAccountName) } + } + }; + + if (_methods.HasFlag(CollectionMethod.ACL)) { + var aces = await _aclProcessor.ProcessACL(resolvedSearchResult, entry, true) + .ToArrayAsync(cancellationToken: _cancellationToken); + ret.Properties.Add("doesanyacegrantownerrights", aces.Any(ace => ace.IsPermissionForOwnerRightsSid)); + ret.Properties.Add("doesanyinheritedacegrantownerrights", + aces.Any(ace => ace.IsInheritedPermissionForOwnerRightsSid)); + ret.Aces = aces; + ret.IsACLProtected = _aclProcessor.IsACLProtected(entry); + ret.Properties.Add("isaclprotected", ret.IsACLProtected); + } + + if (_methods.HasFlag(CollectionMethod.ObjectProps)) { + if (entry.TryGetProperty(LDAPProperties.ManagedAccountPrecededByLink, out var predecessor) && + await _context.LDAPUtils.ResolveDistinguishedName(predecessor) is (true, var principal)) { + ret.PrecededBy = principal; + } + + if (_context.Flags.CollectAllProperties) { + ret.Properties = ContextUtils.Merge(_ldapPropertyProcessor.ParseAllProperties(entry), + ret.Properties); + } + } + + if (_methods.HasFlag(CollectionMethod.Container) && + await _containerProcessor.GetContainingObject(entry) is (true, var container)) { + ret.ContainedBy = container; + } + + return ret; + } + private async Task ProcessComputerObject( IDirectoryObject entry, ResolvedSearchResult resolvedSearchResult @@ -327,7 +369,7 @@ await _containerProcessor.GetContainingObject(dn) is (true, var container)) { } if (resolvedSearchResult.IsDomainController) - ProcessDomainController(resolvedSearchResult, ret, apiName); + await ProcessDomainController(resolvedSearchResult, ret, apiName); var trimmedSamAccountName = samAccountName?.TrimEnd('$'); @@ -453,7 +495,7 @@ private RegistryProcessor GetRegistryProcessor(ResolvedSearchResult resolvedSear })).Value; } - private async void ProcessDomainController(ResolvedSearchResult resolvedSearchResult, Computer ret, + private async Task ProcessDomainController(ResolvedSearchResult resolvedSearchResult, Computer ret, string apiName) { _log.LogDebug("Processing DC: {dc}", apiName); @@ -464,7 +506,9 @@ private async void ProcessDomainController(ResolvedSearchResult resolvedSearchRe StrongCertificateBindingEnforcement = _dcRegistryProcessor.GetStrongCertificateBindingEnforcement(apiName), VulnerableNetlogonSecurityDescriptor = - _dcRegistryProcessor.GetVulnerableNetlogonSecurityDescriptor(apiName) + _dcRegistryProcessor.GetVulnerableNetlogonSecurityDescriptor(apiName), + CurrentBuildNumber = _dcRegistryProcessor.GetCurrentBuildNumber(apiName), + CurrentBuildRevision = _dcRegistryProcessor.GetCurrentBuildRevision(apiName) }; ret.DCRegistryData = dCRegistryData; diff --git a/src/Runtime/OutputWriter.cs b/src/Runtime/OutputWriter.cs index 32c2aa1..0e65cd3 100644 --- a/src/Runtime/OutputWriter.cs +++ b/src/Runtime/OutputWriter.cs @@ -37,6 +37,7 @@ public class OutputWriter private readonly JsonDataWriter _siteOutput; private readonly JsonDataWriter _siteServerOutput; private readonly JsonDataWriter _siteSubnetOutput; + private readonly JsonDataWriter _dmsaOutput; private int _completedCount; @@ -63,6 +64,7 @@ public OutputWriter(IContext context, Channel outputChannel) _siteOutput = new JsonDataWriter(_context, DataType.Sites); _siteServerOutput = new JsonDataWriter(_context, DataType.SiteServers); _siteSubnetOutput = new JsonDataWriter(_context, DataType.SiteSubnets); + _dmsaOutput = new JsonDataWriter(_context, DataType.DMSAs); _runTimer = new Stopwatch(); _statusTimer = new Timer(_context.StatusInterval); @@ -160,6 +162,9 @@ internal async Task StartWriter() case SiteSubnet siteSubnet: await _siteSubnetOutput.AcceptObject(siteSubnet); break; + case DMSA dmsa: + await _dmsaOutput.AcceptObject(dmsa); + break; default: throw new ArgumentOutOfRangeException(nameof(item)); } @@ -187,6 +192,7 @@ private async Task FlushWriters() await _siteOutput.FlushWriter(); await _siteServerOutput.FlushWriter(); await _siteSubnetOutput.FlushWriter(); + await _dmsaOutput.FlushWriter(); CloseOutput(); var fileName = ZipFiles(); return fileName; @@ -218,6 +224,7 @@ private string ZipFiles() _enterpriseCAOutput.GetFilename(), _nTAuthStoreOutput.GetFilename(), _certTemplateOutput.GetFilename(), _issuancePolicyOutput.GetFilename(), _siteOutput.GetFilename(), _siteServerOutput.GetFilename(), _siteSubnetOutput.GetFilename(), + _dmsaOutput.GetFilename(), }); foreach (var entry in fileList.Where(x => !string.IsNullOrEmpty(x))) @@ -245,4 +252,4 @@ private string ZipFiles() return resolvedFileName; } } -} \ No newline at end of file +}