/// <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(ISearchResultEntry entry)
        {
            var flag  = IsTextUnicodeFlags.IS_TEXT_UNICODE_STATISTICS;
            var props = new Dictionary <string, object>();

            foreach (var property in entry.PropertyNames())
            {
                if (ReservedAttributes.Contains(property))
                {
                    continue;
                }

                var collCount = entry.PropCount(property);
                if (collCount == 0)
                {
                    continue;
                }

                if (collCount == 1)
                {
                    var testBytes = entry.GetByteProperty(property);

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

                    var testString = entry.GetProperty(property);

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

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

            return(props);
        }
Example #2
0
        private async Task <User> ProcessUserObject(ISearchResultEntry entry,
                                                    ResolvedSearchResult resolvedSearchResult)
        {
            var ret = new User
            {
                ObjectIdentifier = resolvedSearchResult.ObjectId
            };

            ret.Properties.Add("domain", resolvedSearchResult.Domain);
            ret.Properties.Add("name", resolvedSearchResult.DisplayName);
            ret.Properties.Add("distinguishedname", entry.DistinguishedName.ToUpper());
            ret.Properties.Add("domainsid", resolvedSearchResult.DomainSid);

            if ((_methods & ResolvedCollectionMethod.ACL) != 0)
            {
                var aces = _aclProcessor.ProcessACL(resolvedSearchResult, entry);
                var gmsa = entry.GetByteProperty(LDAPProperties.GroupMSAMembership);
                ret.Aces           = aces.Concat(_aclProcessor.ProcessGMSAReaders(gmsa, resolvedSearchResult.Domain)).ToArray();
                ret.IsACLProtected = _aclProcessor.IsACLProtected(entry);
            }

            if ((_methods & ResolvedCollectionMethod.Group) != 0)
            {
                var pg = entry.GetProperty(LDAPProperties.PrimaryGroupID);
                ret.PrimaryGroupSID = GroupProcessor.GetPrimaryGroupInfo(pg, resolvedSearchResult.ObjectId);
            }

            if ((_methods & ResolvedCollectionMethod.ObjectProps) != 0)
            {
                var userProps = await _ldapPropertyProcessor.ReadUserProperties(entry);

                ret.Properties        = ContextUtils.Merge(ret.Properties, userProps.Props);
                ret.HasSIDHistory     = userProps.SidHistory;
                ret.AllowedToDelegate = userProps.AllowedToDelegate;
            }

            if ((_methods & ResolvedCollectionMethod.SPNTargets) != 0)
            {
                var spn = entry.GetArrayProperty(LDAPProperties.ServicePrincipalNames);

                var targets    = new List <SPNPrivilege>();
                var enumerator = _spnProcessor.ReadSPNTargets(spn, entry.DistinguishedName)
                                 .GetAsyncEnumerator(_cancellationToken);

                while (await enumerator.MoveNextAsync())
                {
                    targets.Add(enumerator.Current);
                }

                ret.SPNTargets = targets.ToArray();
            }

            return(ret);
        }
        /// <summary>
        ///     Reads specific LDAP properties related to Computers
        /// </summary>
        /// <param name="entry"></param>
        /// <returns></returns>
        public async Task <ComputerProperties> ReadComputerProperties(ISearchResultEntry entry)
        {
            var compProps = new ComputerProperties();
            var props     = GetCommonProps(entry);

            var  uac = entry.GetProperty(LDAPProperties.UserAccountControl);
            bool enabled, unconstrained, trustedToAuth;

            if (int.TryParse(uac, out var flag))
            {
                var flags = (UacFlags)flag;
                enabled       = (flags & UacFlags.AccountDisable) == 0;
                unconstrained = (flags & UacFlags.TrustedForDelegation) == UacFlags.TrustedForDelegation;
                trustedToAuth = (flags & 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.GetArrayProperty(LDAPProperties.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 _utils.ResolveHostToSid(hname, domain);

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

            compProps.AllowedToDelegate = comps.Distinct().ToArray();

            var allowedToActPrincipals = new List <TypedPrincipal>();
            var rawAllowedToAct        = entry.GetByteProperty(LDAPProperties.AllowedToActOnBehalfOfOtherIdentity);

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

            compProps.AllowedToAct = allowedToActPrincipals.ToArray();

            props.Add("enabled", enabled);
            props.Add("unconstraineddelegation", unconstrained);
            props.Add("trustedtoauth", trustedToAuth);
            props.Add("lastlogon", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.LastLogon)));
            props.Add("lastlogontimestamp",
                      Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.LastLogonTimestamp)));
            props.Add("pwdlastset", Helpers.ConvertFileTimeToUnixEpoch(entry.GetProperty(LDAPProperties.PasswordLastSet)));
            props.Add("serviceprincipalnames", entry.GetArrayProperty(LDAPProperties.ServicePrincipalNames));
            var os = entry.GetProperty(LDAPProperties.OperatingSystem);
            var sp = entry.GetProperty(LDAPProperties.ServicePack);

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

            props.Add("operatingsystem", os);

            var sh                   = entry.GetByteArrayProperty(LDAPProperties.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;
                }

                sidHistoryList.Add(sSid);

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

                sidHistoryPrincipals.Add(res);
            }

            compProps.SidHistory = sidHistoryPrincipals.ToArray();

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

            compProps.Props = props;

            return(compProps);
        }