/// <summary>
        /// Attempts to parse all LDAP attributes outside of the ones already collected and converts them to a human readable format using a best guess
        /// </summary>
        /// <param name="entry"></param>
        private static Dictionary <string, object> ParseAllProperties(SearchResultEntry entry)
        {
            var flag  = IsTextUnicodeFlags.IS_TEXT_UNICODE_STATISTICS;
            var props = new Dictionary <string, object>();

            foreach (var property in entry.Attributes.AttributeNames)
            {
                var propName = property.ToString().ToLower();
                if (ReservedAttributes.Contains(propName))
                {
                    continue;
                }

                var collection = entry.Attributes[propName];
                if (collection.Count == 0)
                {
                    continue;
                }

                if (collection.Count == 1)
                {
                    var testBytes = entry.GetPropertyAsBytes(propName);

                    if (testBytes == null || testBytes.Length == 0 || !IsTextUnicode(testBytes, testBytes.Length, ref flag))
                    {
                        continue;
                    }

                    var testString = entry.GetProperty(propName);

                    if (!string.IsNullOrEmpty(testString))
                    {
                        if (propName == "badpasswordtime")
                        {
                            props.Add(propName, Helpers.ConvertFileTimeToUnixEpoch(testString));
                        }
                        else
                        {
                            props.Add(propName, BestGuessConvert(testString));
                        }
                    }
                }
                else
                {
                    var arrBytes = entry.GetPropertyAsArrayOfBytes(propName);
                    if (arrBytes.Length == 0 || !IsTextUnicode(arrBytes[0], arrBytes[0].Length, ref flag))
                    {
                        continue;
                    }

                    var arr = entry.GetPropertyAsArray(propName);
                    if (arr.Length > 0)
                    {
                        props.Add(propName, arr.Select(BestGuessConvert).ToArray());
                    }
                }
            }

            return(props);
        }
 public byte[][] GetByteArrayProperty(string propertyName)
 {
     return(_entry.GetPropertyAsArrayOfBytes(propertyName));
 }
        public static async Task <ComputerProperties> ReadComputerProperties(SearchResultEntry entry)
        {
            var compProps = new ComputerProperties();
            var props     = new Dictionary <string, object>();

            var  uac = entry.GetProperty("useraccountcontrol");
            bool enabled, unconstrained, trustedToAuth;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UAC.UacFlags)flag;
                enabled       = (flags & UAC.UacFlags.AccountDisable) == 0;
                unconstrained = (flags & UAC.UacFlags.TrustedForDelegation) == UAC.UacFlags.TrustedForDelegation;
                trustedToAuth = (flags & UAC.UacFlags.TrustedToAuthForDelegation) != 0;
            }
            else
            {
                unconstrained = false;
                enabled       = true;
                trustedToAuth = false;
            }

            var domain = Helpers.DistinguishedNameToDomain(entry.DistinguishedName);

            var comps = new List <TypedPrincipal>();

            if (trustedToAuth)
            {
                var delegates = entry.GetPropertyAsArray("msds-allowedToDelegateTo");
                props.Add("allowedtodelegate", delegates);

                foreach (var d in delegates)
                {
                    var hname = d.Contains("/") ? d.Split('/')[1] : d;
                    hname = hname.Split(':')[0];
                    var resolvedHost = await LDAPUtils.ResolveHostToSid(hname, domain);

                    if (resolvedHost.Contains(".") || resolvedHost.Contains("S-1"))
                    {
                        comps.Add(new TypedPrincipal
                        {
                            ObjectIdentifier = resolvedHost,
                            ObjectType       = Label.Computer
                        });
                    }
                }
            }

            compProps.AllowedToDelegate = comps.ToArray();

            var allowedToActPrincipals = new List <TypedPrincipal>();
            var rawAllowedToAct        = entry.GetPropertyAsBytes("msDS-AllowedToActOnBehalfOfOtherIdentity");

            if (rawAllowedToAct != null)
            {
                var sd = new ActiveDirectorySecurity();
                sd.SetSecurityDescriptorBinaryForm(rawAllowedToAct, AccessControlSections.Access);
                foreach (ActiveDirectoryAccessRule rule in sd.GetAccessRules(true, true, typeof(SecurityIdentifier)))
                {
                    var res = LDAPUtils.ResolveIDAndType(rule.IdentityReference.Value, domain);
                    allowedToActPrincipals.Add(res);
                }
            }

            compProps.AllowedToAct = allowedToActPrincipals.ToArray();

            props.Add("enabled", enabled);
            props.Add("unconstraineddelegation", unconstrained);
            props.Add("lastlogon", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty("lastlogon")));
            props.Add("lastlogontimestamp", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty("lastlogontimestamp")));
            props.Add("pwdlastset", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty("pwdlastset")));
            props.Add("serviceprincipalnames", entry.GetPropertyAsArray("serviceprincipalname"));
            var os = entry.GetProperty("operatingsystem");
            var sp = entry.GetProperty("operatingsystemservicepack");

            if (sp != null)
            {
                os = $"{os} {sp}";
            }

            props.Add("operatingsystem", os);
            props.Add("description", entry.GetProperty("description"));

            var sh                   = entry.GetPropertyAsArrayOfBytes("sidhistory");
            var sidHistoryList       = new List <string>();
            var sidHistoryPrincipals = new List <TypedPrincipal>();

            foreach (var sid in sh)
            {
                string sSid;
                try
                {
                    sSid = new SecurityIdentifier(sid, 0).Value;
                }
                catch
                {
                    continue;
                }

                var res = LDAPUtils.ResolveIDAndType(sSid, domain);

                sidHistoryPrincipals.Add(res);
            }

            compProps.SidHistory = sidHistoryPrincipals.ToArray();

            props.Add("sidhistory", sidHistoryList.ToArray());

            compProps.Props = props;

            return(compProps);
        }
        public static async Task <UserProperties> ReadUserProperties(SearchResultEntry entry)
        {
            var userProps = new UserProperties();
            var props     = new Dictionary <string, object>
            {
                { "description", entry.GetProperty("description") }
            };

            var  uac = entry.GetProperty("useraccountcontrol");
            bool enabled, trustedToAuth, sensitive, dontReqPreAuth, passwdNotReq, unconstrained, pwdNeverExpires;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UAC.UacFlags)flag;
                enabled         = (flags & UAC.UacFlags.AccountDisable) == 0;
                trustedToAuth   = (flags & UAC.UacFlags.TrustedToAuthForDelegation) != 0;
                sensitive       = (flags & UAC.UacFlags.NotDelegated) != 0;
                dontReqPreAuth  = (flags & UAC.UacFlags.DontReqPreauth) != 0;
                passwdNotReq    = (flags & UAC.UacFlags.PasswordNotRequired) != 0;
                unconstrained   = (flags & UAC.UacFlags.TrustedForDelegation) != 0;
                pwdNeverExpires = (flags & UAC.UacFlags.DontExpirePassword) != 0;
            }
            else
            {
                trustedToAuth   = false;
                enabled         = true;
                sensitive       = false;
                dontReqPreAuth  = false;
                passwdNotReq    = false;
                unconstrained   = false;
                pwdNeverExpires = false;
            }

            props.Add("sensitive", sensitive);
            props.Add("dontreqpreauth", dontReqPreAuth);
            props.Add("passwordnotreqd", passwdNotReq);
            props.Add("unconstraineddelegation", unconstrained);
            props.Add("pwdneverexpires", pwdNeverExpires);
            props.Add("enabled", enabled);
            var domain = Helpers.DistinguishedNameToDomain(entry.DistinguishedName);

            var comps = new List <TypedPrincipal>();

            if (trustedToAuth)
            {
                var delegates = entry.GetPropertyAsArray("msds-allowedToDelegateTo");
                props.Add("allowedtodelegate", delegates);

                foreach (var d in delegates)
                {
                    var hname = d.Contains("/") ? d.Split('/')[1] : d;
                    hname = hname.Split(':')[0];
                    var resolvedHost = await LDAPUtils.ResolveHostToSid(hname, domain);

                    if (resolvedHost.Contains(".") || resolvedHost.Contains("S-1"))
                    {
                        comps.Add(new TypedPrincipal
                        {
                            ObjectIdentifier = resolvedHost,
                            ObjectType       = Label.Computer
                        });
                    }
                }
            }

            userProps.AllowedToDelegate = comps.ToArray();

            props.Add("lastlogon", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty("lastlogon")));
            props.Add("lastlogontimestamp", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty("lastlogontimestamp")));
            props.Add("pwdlastset", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty("pwdlastset")));
            var spn = entry.GetPropertyAsArray("serviceprincipalname");

            props.Add("serviceprincipalnames", spn);
            props.Add("hasspn", spn.Length > 0);
            props.Add("displayname", entry.GetProperty("displayname"));
            props.Add("email", entry.GetProperty("mail"));
            props.Add("title", entry.GetProperty("title"));
            props.Add("homedirectory", entry.GetProperty("homedirectory"));
            props.Add("description", entry.GetProperty("description"));
            props.Add("userpassword", entry.GetProperty("userpassword"));

            var ac = entry.GetProperty("admincount");

            if (ac != null)
            {
                var a = int.Parse(ac);
                props.Add("admincount", a != 0);
            }
            else
            {
                props.Add("admincount", false);
            }

            var sh                   = entry.GetPropertyAsArrayOfBytes("sidhistory");
            var sidHistoryList       = new List <string>();
            var sidHistoryPrincipals = new List <TypedPrincipal>();

            foreach (var sid in sh)
            {
                string sSid;
                try
                {
                    sSid = new SecurityIdentifier(sid, 0).Value;
                }
                catch
                {
                    continue;
                }

                var res = LDAPUtils.ResolveIDAndType(sSid, domain);

                sidHistoryPrincipals.Add(res);
            }

            userProps.SidHistory = sidHistoryPrincipals.ToArray();

            props.Add("sidhistory", sidHistoryList.ToArray());

            userProps.Props = props;

            return(userProps);
        }