public static DsObjectInformation Get(string domain, string object_class)
        {
            var schema_class = DirectoryServiceUtils.GetSchemaClass(domain, object_class);

            if (schema_class == null)
            {
                return(null);
            }
            var ret = new DsObjectInformation();

            ret.SchemaClass = schema_class;
            var classes = DirectoryServiceUtils.GetSchemaClasses(domain, object_class, true);

            ret.InferiorClasses = schema_class.PossibleInferiors.Select(i => DirectoryServiceUtils.GetSchemaClass(domain, i)).ToList();
            ret.Attributes      = classes.SelectMany(c => c.Attributes.Select(a => DirectoryServiceUtils.GetSchemaAttribute(domain, a.Name))).Distinct().ToList();
            ret.ExtendedRights  = DirectoryServiceUtils.GetExtendedRights(domain, schema_class.SchemaId).ToList();

            ret.ObjectTypes = new Dictionary <Guid, IDirectoryServiceObjectTree>();
            ret.ObjectTypes[ret.SchemaClass.SchemaId] = ret.SchemaClass;
            AddObjectTypes(ret.ObjectTypes, ret.InferiorClasses);
            AddObjectTypes(ret.ObjectTypes, ret.Attributes);
            AddObjectTypes(ret.ObjectTypes, ret.ExtendedRights);

            return(ret);
        }
        private void GetAccessCheckResult(string dn, string name, bool is_deleted, DsObjectInformation obj_info, SecurityDescriptor sd, Sid object_sid)
        {
            for (int i = 0; i < _context.Count; ++i)
            {
                var        ctx                    = _context[i];
                var        token_info             = _token_info[i];
                var        granted_access_no_type = AccessCheckSingle(ctx, sd, object_sid, null);
                var        granted_access         = AccessCheckSingle(ctx, sd, object_sid, obj_info.SchemaClass);
                AccessMask max_granted_access     = granted_access_no_type | granted_access;

                var rights_results = new List <DsObjectTypeAccessCheckResult <DirectoryServiceExtendedRight> >();
                var class_results  = new List <DsObjectTypeAccessCheckResult <DirectoryServiceSchemaClass> >();
                var attr_results   = new List <DsObjectTypeAccessCheckResult <DirectoryServiceSchemaAttribute> >();

                MapResults(AccessCheck(ctx, sd, object_sid, obj_info.GetInferiorClasses()), obj_info, rights_results, class_results, attr_results, ref max_granted_access);
                MapResults(AccessCheck(ctx, sd, object_sid, obj_info.GetExtendedRights()), obj_info, rights_results, class_results, attr_results, ref max_granted_access);
                MapResults(AccessCheck(ctx, sd, object_sid, obj_info.GetAttributes()), obj_info, rights_results, class_results, attr_results, ref max_granted_access);

                if (max_granted_access.IsEmpty && !AllowEmptyAccess)
                {
                    continue;
                }

                WriteObject(new DsObjectAccessCheckResult(dn, name, obj_info.SchemaClass, is_deleted,
                                                          Domain, granted_access, granted_access_no_type,
                                                          max_granted_access, rights_results.Where(r => r.Object.IsPropertySet),
                                                          rights_results.Where(r => r.Object.IsControl),
                                                          rights_results.Where(r => r.Object.IsValidatedWrite),
                                                          class_results,
                                                          attr_results,
                                                          sd, token_info));
            }
        }
        private void MapResults(IEnumerable <AuthZAccessCheckResult> results, DsObjectInformation obj_info,
                                List <DsObjectTypeAccessCheckResult <DirectoryServiceExtendedRight> > rights,
                                List <DsObjectTypeAccessCheckResult <DirectoryServiceSchemaClass> > classes,
                                List <DsObjectTypeAccessCheckResult <DirectoryServiceSchemaAttribute> > attrs,
                                ref AccessMask max_granted_access)
        {
            foreach (var result in results.Where(r => r.Level > 0))
            {
                if (result.GrantedAccess.IsEmpty && !AllowEmptyAccess)
                {
                    continue;
                }

                if (!obj_info.ObjectTypes.TryGetValue(result.ObjectType, out IDirectoryServiceObjectTree value))
                {
                    continue;
                }

                max_granted_access |= result.GrantedAccess;

                if (value is DirectoryServiceExtendedRight right)
                {
                    rights.Add(new DsObjectTypeAccessCheckResult <DirectoryServiceExtendedRight>(right, result));
                }
                else if (value is DirectoryServiceSchemaClass schema_class)
                {
                    classes.Add(new DsObjectTypeAccessCheckResult <DirectoryServiceSchemaClass>(schema_class, result));
                }
                else if (value is DirectoryServiceSchemaAttribute attr_class)
                {
                    attrs.Add(new DsObjectTypeAccessCheckResult <DirectoryServiceSchemaAttribute>(attr_class, result));
                }
            }
        }
        private void RunAccessCheck(DirectoryEntry root, string filter, bool recurse, bool recurse_subtree, int current_depth)
        {
            if (current_depth < 0)
            {
                return;
            }

            SearchScope scope = recurse ? SearchScope.OneLevel : (recurse_subtree ? SearchScope.Subtree : SearchScope.Base);

            foreach (var result in FindAllDirectoryEntries(root, scope, IncludeDeleted, filter, kDistinguishedName, kObjectClass,
                                                           kStructuralObjectClass, kNTSecurityDescriptor, kObjectSid, kName, kIsDeleted))
            {
                if (Stopping)
                {
                    return;
                }

                string dn = GetPropertyValue <string>(result, kDistinguishedName);
                if (string.IsNullOrWhiteSpace(dn))
                {
                    WriteWarning($"Couldn't get DN for '{result.Path}'");
                    continue;
                }

                if (!IncludePath(dn))
                {
                    continue;
                }

                WriteProgress($"Checking {dn}");

                string name = GetPropertyValue <string>(result, kName);

                var sd = GetObjectSecurityDescriptor(result);
                if (sd == null)
                {
                    WriteWarning($"Couldn't get security descriptor '{dn}'");
                    continue;
                }

                string obj_class = GetObjectClass(result);
                if (string.IsNullOrWhiteSpace(obj_class))
                {
                    WriteWarning($"Couldn't get object class for '{dn}'");
                    continue;
                }

                var obj_info = _cached_info.GetOrAdd(obj_class, n => DsObjectInformation.Get(Domain, n));
                if (obj_info == null)
                {
                    WriteWarning($"Couldn't get object information for '{dn}'");
                    continue;
                }

                string[] structural_obj_classes = GetPropertyValues <string>(result, kStructuralObjectClass);
                string[] obj_classes            = GetPropertyValues <string>(result, kObjectClass);
                List <DsObjectInformation> dynamic_aux_classes = new List <DsObjectInformation>();

                if (obj_classes.Length > structural_obj_classes.Length)
                {
                    foreach (var dynamic_aux_class in obj_classes.Where(c => !obj_info.ClassNames.Contains(c)).Distinct())
                    {
                        dynamic_aux_classes.Add(_cached_info.GetOrAdd(dynamic_aux_class, n => DsObjectInformation.Get(Domain, n)));
                    }
                }

                GetAccessCheckResult(dn, name, GetIsDeleted(result), obj_info, dynamic_aux_classes, sd, GetObjectSid(result));
            }

            if (Stopping)
            {
                return;
            }

            if (recurse)
            {
                foreach (DirectoryEntry entry in root.Children)
                {
                    if (Stopping)
                    {
                        return;
                    }

                    using (entry)
                    {
                        RunAccessCheck(entry, filter, recurse, recurse_subtree, current_depth - 1);
                    }
                }
            }
        }