private List <SecurityDescriptorTarget> ConvertToTargets(OUPrincipalMapping entry) { List <SecurityDescriptorTarget> targets = new List <SecurityDescriptorTarget>(); this.PopulateTargets(entry, targets); return(targets); }
protected ImportResults PerformComputerDiscovery(IComputerPrincipalProvider provider) { OUPrincipalMapping ou = new OUPrincipalMapping($"LDAP://{settings.ImportOU}", settings.ImportOU); ImportResults results = new ImportResults { DiscoveryErrors = new List <DiscoveryError>(), }; principalCache = new ConcurrentDictionary <SecurityIdentifier, ISecurityPrincipal>(); this.PerformComputerDiscovery(ou, provider, results.DiscoveryErrors); principalCache.Clear(); results.Targets = this.ConvertToTargets(ou); return(results); }
private SecurityDescriptorTarget ConvertToTarget(OUPrincipalMapping entry, HashSet <SecurityIdentifier> admins) { this.logger.LogTrace("Creating new target for OU {ou} with the following principals\r\n{admins}", entry.AdsPath, string.Join(", ", admins)); SecurityDescriptorTarget target = new SecurityDescriptorTarget() { AuthorizationMode = AuthorizationMode.SecurityDescriptor, Description = settings.RuleDescription?.Replace("{targetName}", entry.OUName, StringComparison.OrdinalIgnoreCase), Target = entry.OUName, Type = TargetType.Container, Id = Guid.NewGuid().ToString(), Notifications = settings.Notifications, Jit = new SecurityDescriptorTargetJitDetails() { AuthorizingGroup = settings.JitAuthorizingGroup, ExpireAfter = settings.JitExpireAfter }, Laps = new SecurityDescriptorTargetLapsDetails() { ExpireAfter = settings.LapsExpireAfter } }; AccessMask mask = 0; mask |= settings.AllowLaps ? AccessMask.LocalAdminPassword : 0; mask |= settings.AllowJit ? AccessMask.Jit : 0; mask |= settings.AllowLapsHistory ? AccessMask.LocalAdminPasswordHistory : 0; mask |= settings.AllowBitLocker ? AccessMask.BitLocker : 0; DiscretionaryAcl acl = new DiscretionaryAcl(false, false, admins.Count); foreach (var sid in admins) { acl.AddAccess(AccessControlType.Allow, sid, (int)mask, InheritanceFlags.None, PropagationFlags.None); } CommonSecurityDescriptor sd = new CommonSecurityDescriptor(false, false, ControlFlags.DiscretionaryAclPresent, new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null), null, null, acl); target.SecurityDescriptor = sd.GetSddlForm(AccessControlSections.All); return(target); }
private void PopulateTargets(OUPrincipalMapping entry, List <SecurityDescriptorTarget> targets) { bool canConsolidate = !(settings.DoNotConsolidate || (settings.DoNotConsolidateOnError && entry.HasDescendantsWithErrors)); this.logger.LogTrace(@"Processing OU Path: {ou} Consolidating: {consolidating} DoNotConsolidate flag: {DoNotConsolidate} DoNotConsolidateOnError flag : {DoNotConsolidateOnError} HasDescendantsWithErrors: {HasDescendantsWithErrors} ParentHasDescendantsWithErrors: {ParentHasDescendantsWithErrors} Computers: {ComputerCount} : {Computers} CommonPrincipalsFromDescendants: {CommonPrincipalsFromDescendantsCount} : {CommonPrincipalsFromDescendants} PrincipalsUniqueToThisLevel: {PrincipalsUniqueToThisLevelCount} : {PrincipalsUniqueToThisLevel} ", entry.AdsPath, canConsolidate, settings.DoNotConsolidate, settings.DoNotConsolidateOnError, entry.HasDescendantsWithErrors, entry.Parent?.HasDescendantsWithErrors, entry.Computers.Count, string.Join(", ", entry.Computers.Select(t => t.PrincipalName)), entry.CommonPrincipalsFromDescendants.Count, string.Join(", ", entry.CommonPrincipalsFromDescendants), entry.PrincipalsUniqueToThisLevel.Count, string.Join(", ", entry.PrincipalsUniqueToThisLevel) ); if (canConsolidate) { HashSet <SecurityIdentifier> admins; if (settings.DoNotConsolidateOnError && (entry.Parent?.HasDescendantsWithErrors ?? false)) { // The parent OU is in error, so we cannot remove common principals that the parent may have admins = entry.CommonPrincipalsFromDescendants; this.logger.LogTrace("Permissions for the OU {OU} will not be consolidated against the parent OU because the parent OU one or more descendant errors", entry.AdsPath); } else { // Principals that are present on the parent OU are removed from the principal set here admins = entry.PrincipalsUniqueToThisLevel; this.logger.LogTrace("Permissions for the OU {OU} will be consolidated against its parent", entry.AdsPath); } if (admins.Count > 0) { targets.Add(this.ConvertToTarget(entry, admins)); } else { this.logger.LogTrace("There were no principals that require a rule being created for {target}", entry.AdsPath); } } foreach (var computer in entry.Computers) { this.logger.LogTrace(@"Processing computer Principal: {computer} Consolidating: {consolidating} DoNotConsolidate flag: {DoNotConsolidate} DoNotConsolidateOnError flag : {DoNotConsolidateOnError} HasError: {HasError} IsMissing: {IsMissing} ParentHasErrors: {ParentHasDescendantsWithErrors} DiscoveryErrors: {DiscoveryErrorCount} : {DiscoveryErrors} Principals: {PrincipalsCount} : {Principals} PrincipalsUniqueToThisLevel: {PrincipalsUniqueToThisLevelCount} : {PrincipalsUniqueToThisLevel} ", computer.PrincipalName, canConsolidate, settings.DoNotConsolidate, settings.DoNotConsolidateOnError, computer.HasError, computer.IsMissing, entry.HasDescendantsWithErrors, computer.DiscoveryErrors.Count, string.Join(", ", computer.DiscoveryErrors?.Select(t => t.Message)), computer.Principals.Count, string.Join(", ", computer.Principals), computer.PrincipalsUniqueToThisLevel.Count, string.Join(", ", computer.PrincipalsUniqueToThisLevel) ); if (computer.HasError) { this.logger.LogTrace("Skipping permissions for computer {computer} due to discovery errors", computer.PrincipalName); continue; } HashSet <SecurityIdentifier> admins; if (settings.DoNotConsolidate) { admins = computer.Principals; this.logger.LogTrace("Permissions for computer {computer} will not be consolidated because consolidation has been disabled", computer.PrincipalName); } else if (settings.DoNotConsolidateOnError && entry.HasDescendantsWithErrors) { admins = computer.Principals; this.logger.LogTrace("Permissions for computer {computer} will not be consolidated because the parent OU has decendant errors", computer.PrincipalName); } else { admins = computer.PrincipalsUniqueToThisLevel; this.logger.LogTrace("Permissions for computer {computer} can be consolidated", computer.PrincipalName); } if (admins.Count > 0) { targets.Add(this.ConvertToTarget(computer, admins)); } else { this.logger.LogTrace("There were no principals that require a rule being created for {target}", computer.PrincipalName); } } foreach (var ou in entry.DescendantOUs) { this.PopulateTargets(ou, targets); } }
private void PerformComputerDiscovery(OUPrincipalMapping ou, IComputerPrincipalProvider principalProvider, List <DiscoveryError> discoveryErrors) { settings.CancellationToken.ThrowIfCancellationRequested(); foreach (SearchResult computer in this.GetComputersFromOU(ou.AdsPath, false, principalProvider)) { settings.CancellationToken.ThrowIfCancellationRequested(); string computerName = computer.GetPropertyString("msDS-PrincipalName"); try { this.OnItemProcessStart?.Invoke(this, new ImportProcessingEventArgs(computerName)); if (this.ShouldFilterComputer(computer)) { this.logger.LogTrace("Filtering computer {computer}", computerName); continue; } this.logger.LogTrace("Found computer {computer} in ou {ou}", computerName, ou.OUName); ComputerPrincipalMapping ce = new ComputerPrincipalMapping(computer, ou); ou.Computers.Add(ce); try { HashSet <SecurityIdentifier> principalsForComputer = new HashSet <SecurityIdentifier>(principalProvider.GetPrincipalsForComputer(computer, settings.FilterLocalAccounts)); this.logger.LogTrace("Got {number} principals from computer {computer}", principalsForComputer.Count, computerName); foreach (var principal in principalsForComputer) { settings.CancellationToken.ThrowIfCancellationRequested(); if (this.ShouldFilter(principal, out DiscoveryError filterReason)) { if (filterReason != null) { filterReason.Target = computerName; ce.DiscoveryErrors.Add(filterReason); this.logger.LogTrace("Filtering principal {principal} with reason: {reason}", principal.ToString(), filterReason); } } else { ce.Principals.Add(principal); } } } catch (OperationCanceledException) { return; } catch (Exception ex) { this.logger.LogTrace(ex, "Failed to get principals from computer {computer}", computerName); ce.HasError = true; ce.Exception = ex; ce.IsMissing = ex is ObjectNotFoundException; ce.DiscoveryErrors.Add(new DiscoveryError() { Target = computerName, Message = ex.Message, Type = DiscoveryErrorType.Error }); } if (ce.DiscoveryErrors.Count > 0) { discoveryErrors.AddRange(ce.DiscoveryErrors); } } finally { this.OnItemProcessFinish?.Invoke(this, new ImportProcessingEventArgs(computerName)); } } foreach (var childOU in this.GetOUs(ou.AdsPath, false)) { settings.CancellationToken.ThrowIfCancellationRequested(); this.logger.LogTrace("Found ou {ou}", childOU.GetPropertyString("distinguishedName")); OUPrincipalMapping childou = new OUPrincipalMapping(childOU, ou); ou.DescendantOUs.Add(childou); this.PerformComputerDiscovery(childou, principalProvider, discoveryErrors); } }
internal OUPrincipalMapping(SearchResult result, OUPrincipalMapping parent) { this.AdsPath = result.Path; this.OUName = result.GetPropertyString("distinguishedName"); this.Parent = parent; }
internal ComputerPrincipalMapping(SearchResult computer, OUPrincipalMapping parent) { this.Parent = parent; this.computer = computer; }