< Summary

Class:SharpHoundRPC.Wrappers.SAMServer
Assembly:SharpHoundRPC
File(s):D:\a\SharpHoundCommon\SharpHoundCommon\src\SharpHoundRPC\Wrappers\SAMServer.cs
Covered lines:0
Uncovered lines:77
Coverable lines:77
Total lines:137
Line coverage:0% (0 of 77)
Covered branches:0
Total branches:34
Branch coverage:0% (0 of 34)

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%100%
OpenServer(...)0%200%
GetDomains()0%200%
LookupDomain(...)0%200%
GetMachineSid(...)0%1400%
LookupPrincipalBySid(...)0%200%
OpenDomain(...)0%600%
OpenDomain(...)0%400%
Dispose(...)0%200%

File(s)

D:\a\SharpHoundCommon\SharpHoundCommon\src\SharpHoundRPC\Wrappers\SAMServer.cs

#LineLine coverage
 1using System.Collections.Concurrent;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Security.Principal;
 5using SharpHoundRPC.Handles;
 6using SharpHoundRPC.SAMRPCNative;
 7using SharpHoundRPC.Shared;
 8
 9namespace SharpHoundRPC.Wrappers
 10{
 11    public class SAMServer : SAMBase, ISAMServer
 12    {
 13        private readonly ConcurrentDictionary<string, SAMDomain> _domainHandleCache;
 14        private SecurityIdentifier _cachedMachineSid;
 15
 016        public SAMServer(SAMHandle handle, string computerName) : base(handle)
 017        {
 018            _domainHandleCache = new ConcurrentDictionary<string, SAMDomain>();
 019            ComputerName = computerName;
 020        }
 21
 022        public string ComputerName { get; }
 23
 24        public static Result<SAMServer> OpenServer(string computerName, SAMEnums.SamAccessMasks requestedConnectAccess =
 25            SAMEnums.SamAccessMasks.SamServerConnect |
 26            SAMEnums.SamAccessMasks
 27                .SamServerEnumerateDomains |
 28            SAMEnums.SamAccessMasks.SamServerLookupDomain)
 029        {
 030            var (status, handle) = SAMMethods.SamConnect(computerName, requestedConnectAccess);
 31
 032            return status.IsError()
 033                ? status
 034                : new SAMServer(handle, computerName);
 035        }
 36
 37        public Result<IEnumerable<(string Name, int Rid)>> GetDomains()
 038        {
 039            var (status, rids, count) = SAMMethods.SamEnumerateDomainsInSamServer(Handle);
 040            if (status.IsError()) return status;
 41
 042            var ret = Result<IEnumerable<(string Name, int Rid)>>.Ok(rids
 043                .GetEnumerable<SAMStructs.SamRidEnumeration>(count).Select(x => (x.Name.ToString(), x.Rid)));
 044            return ret;
 045        }
 46
 47        public Result<SecurityIdentifier> LookupDomain(string name)
 048        {
 049            var (status, sid) = SAMMethods.SamLookupDomainInSamServer(Handle, name);
 050            using (sid)
 051            {
 052                return status.IsError() ? status : sid.GetData<SecurityIdentifier>();
 53            }
 054        }
 55
 56        public Result<SecurityIdentifier> GetMachineSid(string testName = null)
 057        {
 058            if (_cachedMachineSid != null)
 059                return _cachedMachineSid;
 60
 061            SecurityIdentifier sid = null;
 62
 063            if (testName != null)
 064            {
 065                var result = LookupDomain(testName);
 066                if (result.IsSuccess) sid = result.Value;
 067            }
 68
 069            if (sid == null)
 070            {
 071                var domainResult = GetDomains();
 072                if (domainResult.IsSuccess)
 073                {
 074                    var result = LookupDomain(domainResult.Value.FirstOrDefault().Name);
 075                    if (result.IsSuccess) sid = result.Value;
 076                }
 077            }
 78
 079            if (sid == null) return "Unable to get machine sid";
 080            _cachedMachineSid = sid;
 081            return sid;
 082        }
 83
 84        public Result<(string Name, SharedEnums.SidNameUse Type)> LookupPrincipalBySid(
 85            SecurityIdentifier securityIdentifier)
 086        {
 087            var openDomainResult = OpenDomain(securityIdentifier);
 088            if (openDomainResult.IsFailed) return $"OpenDomain returned {openDomainResult.Status}";
 89
 090            var domain = openDomainResult.Value;
 91
 092            return domain.LookupPrincipalByRid(securityIdentifier.Rid());
 093        }
 94
 95        public Result<ISAMDomain> OpenDomain(string domainName, SAMEnums.DomainAccessMask requestedDomainAccess =
 96            SAMEnums.DomainAccessMask.Lookup |
 97            SAMEnums.DomainAccessMask.ListAccounts)
 098        {
 099            var lookupResult = LookupDomain(domainName);
 0100            if (lookupResult.IsFailed) return $"LookupDomain returned {lookupResult.Error}";
 101
 0102            var sid = lookupResult.Value;
 103
 0104            if (_domainHandleCache.TryGetValue(sid.Value, out var domain)) return domain;
 105
 0106            var (status, domainHandle) = SAMMethods.SamOpenDomain(Handle, requestedDomainAccess, sid.GetBytes());
 0107            if (status.IsError()) return status;
 108
 0109            domain = new SAMDomain(domainHandle);
 110
 0111            _domainHandleCache.TryAdd(sid.Value, domain);
 0112            return domain;
 0113        }
 114
 115        public Result<ISAMDomain> OpenDomain(SecurityIdentifier securityIdentifier,
 116            SAMEnums.DomainAccessMask requestedDomainAccess =
 117                SAMEnums.DomainAccessMask.Lookup |
 118                SAMEnums.DomainAccessMask.ListAccounts)
 0119        {
 0120            if (_domainHandleCache.TryGetValue(securityIdentifier.Value, out var domain)) return domain;
 121
 0122            var (status, domainHandle) =
 0123                SAMMethods.SamOpenDomain(Handle, requestedDomainAccess, securityIdentifier.GetBytes());
 0124            if (status.IsError()) return status.ToString();
 125
 0126            domain = new SAMDomain(domainHandle);
 0127            _domainHandleCache.TryAdd(securityIdentifier.Value, domain);
 0128            return domain;
 0129        }
 130
 131        protected override void Dispose(bool disposing)
 0132        {
 0133            foreach (var domainHandle in _domainHandleCache.Values) domainHandle.Dispose();
 0134            base.Dispose(disposing);
 0135        }
 136    }
 137}