diff options
Diffstat (limited to 'Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs')
| -rw-r--r-- | Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs | 900 |
1 files changed, 900 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs b/Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs new file mode 100644 index 000000000..a6ad59fb1 --- /dev/null +++ b/Emby.Server.Implementations/IO/SharpCifs/Smb/SID.cs @@ -0,0 +1,900 @@ +// This code is derived from jcifs smb client library <jcifs at samba dot org> +// Ported by J. Arturo <webmaster at komodosoft dot net> +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using SharpCifs.Dcerpc; +using SharpCifs.Dcerpc.Msrpc; +using SharpCifs.Util; +using SharpCifs.Util.Sharpen; +using Hashtable = SharpCifs.Util.Sharpen.Hashtable; //not System.Collections.Hashtable + +namespace SharpCifs.Smb +{ + /// <summary> + /// A Windows SID is a numeric identifier used to represent Windows + /// accounts. + /// </summary> + /// <remarks> + /// A Windows SID is a numeric identifier used to represent Windows + /// accounts. SIDs are commonly represented using a textual format such as + /// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt> but they may + /// also be resolved to yield the name of the associated Windows account + /// such as <tt>Administrators</tt> or <tt>MYDOM\alice</tt>. + /// <p> + /// Consider the following output of <tt>examples/SidLookup.java</tt>: + /// <pre> + /// toString: S-1-5-21-4133388617-793952518-2001621813-512 + /// toDisplayString: WNET\Domain Admins + /// getType: 2 + /// getTypeText: Domain group + /// getDomainName: WNET + /// getAccountName: Domain Admins + /// </pre> + /// </remarks> + public class Sid : Rpc.SidT + { + public const int SidTypeUseNone = Lsarpc.SidNameUseNone; + + public const int SidTypeUser = Lsarpc.SidNameUser; + + public const int SidTypeDomGrp = Lsarpc.SidNameDomGrp; + + public const int SidTypeDomain = Lsarpc.SidNameDomain; + + public const int SidTypeAlias = Lsarpc.SidNameAlias; + + public const int SidTypeWknGrp = Lsarpc.SidNameWknGrp; + + public const int SidTypeDeleted = Lsarpc.SidNameDeleted; + + public const int SidTypeInvalid = Lsarpc.SidNameInvalid; + + public const int SidTypeUnknown = Lsarpc.SidNameUnknown; + + internal static readonly string[] SidTypeNames = { "0", "User", "Domain group" + , "Domain", "Local group", "Builtin group", "Deleted", "Invalid", "Unknown" }; + + public const int SidFlagResolveSids = unchecked(0x0001); + + public static Sid Everyone; + + public static Sid CreatorOwner; + + public static Sid SYSTEM; + + static Sid() + { + try + { + Everyone = new Sid("S-1-1-0"); + CreatorOwner = new Sid("S-1-3-0"); + SYSTEM = new Sid("S-1-5-18"); + } + catch (SmbException) + { + } + } + + internal static Hashtable SidCache = new Hashtable(); + + /// <exception cref="System.IO.IOException"></exception> + internal static void ResolveSids(DcerpcHandle handle, LsaPolicyHandle policyHandle + , Sid[] sids) + { + MsrpcLookupSids rpc = new MsrpcLookupSids(policyHandle, sids); + handle.Sendrecv(rpc); + switch (rpc.Retval) + { + case 0: + case NtStatus.NtStatusNoneMapped: + case unchecked(0x00000107): + { + // NT_STATUS_SOME_NOT_MAPPED + break; + } + + default: + { + throw new SmbException(rpc.Retval, false); + } + } + for (int si = 0; si < sids.Length; si++) + { + sids[si].Type = rpc.Names.Names[si].SidType; + sids[si].DomainName = null; + switch (sids[si].Type) + { + case SidTypeUser: + case SidTypeDomGrp: + case SidTypeDomain: + case SidTypeAlias: + case SidTypeWknGrp: + { + int sidIndex = rpc.Names.Names[si].SidIndex; + Rpc.Unicode_string ustr = rpc.Domains.Domains[sidIndex].Name; + sids[si].DomainName = (new UnicodeString(ustr, false)).ToString(); + break; + } + } + sids[si].AcctName = (new UnicodeString(rpc.Names.Names[si].Name, false)).ToString + (); + sids[si].OriginServer = null; + sids[si].OriginAuth = null; + } + } + + /// <exception cref="System.IO.IOException"></exception> + internal static void ResolveSids0(string authorityServerName, NtlmPasswordAuthentication + auth, Sid[] sids) + { + DcerpcHandle handle = null; + LsaPolicyHandle policyHandle = null; + lock (SidCache) + { + try + { + handle = DcerpcHandle.GetHandle("ncacn_np:" + authorityServerName + "[\\PIPE\\lsarpc]" + , auth); + string server = authorityServerName; + int dot = server.IndexOf('.'); + if (dot > 0 && char.IsDigit(server[0]) == false) + { + server = Runtime.Substring(server, 0, dot); + } + policyHandle = new LsaPolicyHandle(handle, "\\\\" + server, unchecked(0x00000800)); + ResolveSids(handle, policyHandle, sids); + } + finally + { + if (handle != null) + { + if (policyHandle != null) + { + policyHandle.Close(); + } + handle.Close(); + } + } + } + } + + /// <exception cref="System.IO.IOException"></exception> + public static void ResolveSids(string authorityServerName, NtlmPasswordAuthentication + auth, Sid[] sids, int offset, int length) + { + List<object> list = new List<object>();//new List<object>(sids.Length); + int si; + lock (SidCache) + { + for (si = 0; si < length; si++) + { + Sid sid = (Sid)SidCache.Get(sids[offset + si]); + if (sid != null) + { + sids[offset + si].Type = sid.Type; + sids[offset + si].DomainName = sid.DomainName; + sids[offset + si].AcctName = sid.AcctName; + } + else + { + list.Add(sids[offset + si]); + } + } + if (list.Count > 0) + { + //sids = (Jcifs.Smb.SID[])Sharpen.Collections.ToArray(list, new Jcifs.Smb.SID[0]); + sids = (Sid[])list.ToArray(); + ResolveSids0(authorityServerName, auth, sids); + for (si = 0; si < sids.Length; si++) + { + SidCache.Put(sids[si], sids[si]); + } + } + } + } + + /// <summary>Resolve an array of SIDs using a cache and at most one MSRPC request.</summary> + /// <remarks> + /// Resolve an array of SIDs using a cache and at most one MSRPC request. + /// <p> + /// This method will attempt + /// to resolve SIDs using a cache and cache the results of any SIDs that + /// required resolving with the authority. SID cache entries are currently not + /// expired because under normal circumstances SID information never changes. + /// </remarks> + /// <param name="authorityServerName">The hostname of the server that should be queried. For maximum efficiency this should be the hostname of a domain controller however a member server will work as well and a domain controller may not return names for SIDs corresponding to local accounts for which the domain controller is not an authority. + /// </param> + /// <param name="auth">The credentials that should be used to communicate with the named server. As usual, <tt>null</tt> indicates that default credentials should be used. + /// </param> + /// <param name="sids">The SIDs that should be resolved. After this function is called, the names associated with the SIDs may be queried with the <tt>toDisplayString</tt>, <tt>getDomainName</tt>, and <tt>getAccountName</tt> methods. + /// </param> + /// <exception cref="System.IO.IOException"></exception> + public static void ResolveSids(string authorityServerName, NtlmPasswordAuthentication + auth, Sid[] sids) + { + List<object> list = new List<object>();//new List<object>(sids.Length); + int si; + lock (SidCache) + { + for (si = 0; si < sids.Length; si++) + { + Sid sid = (Sid)SidCache.Get(sids[si]); + if (sid != null) + { + sids[si].Type = sid.Type; + sids[si].DomainName = sid.DomainName; + sids[si].AcctName = sid.AcctName; + } + else + { + list.Add(sids[si]); + } + } + if (list.Count > 0) + { + //sids = (Jcifs.Smb.SID[])Sharpen.Collections.ToArray(list, new Jcifs.Smb.SID[0]); + sids = (Sid[]) list.ToArray(); + ResolveSids0(authorityServerName, auth, sids); + for (si = 0; si < sids.Length; si++) + { + SidCache.Put(sids[si], sids[si]); + } + } + } + } + + /// <exception cref="System.IO.IOException"></exception> + public static Sid GetServerSid(string server, NtlmPasswordAuthentication + auth) + { + DcerpcHandle handle = null; + LsaPolicyHandle policyHandle = null; + Lsarpc.LsarDomainInfo info = new Lsarpc.LsarDomainInfo(); + MsrpcQueryInformationPolicy rpc; + lock (SidCache) + { + try + { + handle = DcerpcHandle.GetHandle("ncacn_np:" + server + "[\\PIPE\\lsarpc]", auth); + // NetApp doesn't like the 'generic' access mask values + policyHandle = new LsaPolicyHandle(handle, null, unchecked(0x00000001)); + rpc = new MsrpcQueryInformationPolicy(policyHandle, Lsarpc.PolicyInfoAccountDomain + , info); + handle.Sendrecv(rpc); + if (rpc.Retval != 0) + { + throw new SmbException(rpc.Retval, false); + } + return new Sid(info.Sid, SidTypeDomain, (new UnicodeString + (info.Name, false)).ToString(), null, false); + } + finally + { + if (handle != null) + { + if (policyHandle != null) + { + policyHandle.Close(); + } + handle.Close(); + } + } + } + } + + public static byte[] ToByteArray(Rpc.SidT sid) + { + byte[] dst = new byte[1 + 1 + 6 + sid.SubAuthorityCount * 4]; + int di = 0; + dst[di++] = sid.Revision; + dst[di++] = sid.SubAuthorityCount; + Array.Copy(sid.IdentifierAuthority, 0, dst, di, 6); + di += 6; + for (int ii = 0; ii < sid.SubAuthorityCount; ii++) + { + Encdec.Enc_uint32le(sid.SubAuthority[ii], dst, di); + di += 4; + } + return dst; + } + + internal int Type; + + internal string DomainName; + + internal string AcctName; + + internal string OriginServer; + + internal NtlmPasswordAuthentication OriginAuth; + + public Sid(byte[] src, int si) + { + Revision = src[si++]; + SubAuthorityCount = src[si++]; + IdentifierAuthority = new byte[6]; + Array.Copy(src, si, IdentifierAuthority, 0, 6); + si += 6; + if (SubAuthorityCount > 100) + { + throw new RuntimeException("Invalid SID sub_authority_count"); + } + SubAuthority = new int[SubAuthorityCount]; + for (int i = 0; i < SubAuthorityCount; i++) + { + SubAuthority[i] = ServerMessageBlock.ReadInt4(src, si); + si += 4; + } + } + + /// <summary> + /// Construct a SID from it's textual representation such as + /// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>. + /// </summary> + /// <remarks> + /// Construct a SID from it's textual representation such as + /// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>. + /// </remarks> + /// <exception cref="SharpCifs.Smb.SmbException"></exception> + public Sid(string textual) + { + StringTokenizer st = new StringTokenizer(textual, "-"); + if (st.CountTokens() < 3 || !st.NextToken().Equals("S")) + { + // need S-N-M + throw new SmbException("Bad textual SID format: " + textual); + } + Revision = byte.Parse(st.NextToken()); + string tmp = st.NextToken(); + long id = 0; + if (tmp.StartsWith("0x")) + { + //id = long.Parse(Sharpen.Runtime.Substring(tmp, 2), 16); + id = long.Parse(Runtime.Substring(tmp, 2)); + } + else + { + id = long.Parse(tmp); + } + IdentifierAuthority = new byte[6]; + for (int i = 5; id > 0; i--) + { + IdentifierAuthority[i] = unchecked((byte)(id % 256)); + id >>= 8; + } + SubAuthorityCount = unchecked((byte)st.CountTokens()); + if (SubAuthorityCount > 0) + { + SubAuthority = new int[SubAuthorityCount]; + for (int i1 = 0; i1 < SubAuthorityCount; i1++) + { + SubAuthority[i1] = (int)(long.Parse(st.NextToken()) & unchecked(0xFFFFFFFFL)); + } + } + } + + /// <summary> + /// Construct a SID from a domain SID and an RID + /// (relative identifier). + /// </summary> + /// <remarks> + /// Construct a SID from a domain SID and an RID + /// (relative identifier). For example, a domain SID + /// <tt>S-1-5-21-1496946806-2192648263-3843101252</tt> and RID <tt>1029</tt> would + /// yield the SID <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>. + /// </remarks> + public Sid(Sid domsid, int rid) + { + Revision = domsid.Revision; + IdentifierAuthority = domsid.IdentifierAuthority; + SubAuthorityCount = unchecked((byte)(domsid.SubAuthorityCount + 1)); + SubAuthority = new int[SubAuthorityCount]; + int i; + for (i = 0; i < domsid.SubAuthorityCount; i++) + { + SubAuthority[i] = domsid.SubAuthority[i]; + } + SubAuthority[i] = rid; + } + + public Sid(Rpc.SidT sid, int type, string domainName, string acctName, bool decrementAuthority + ) + { + Revision = sid.Revision; + SubAuthorityCount = sid.SubAuthorityCount; + IdentifierAuthority = sid.IdentifierAuthority; + SubAuthority = sid.SubAuthority; + this.Type = type; + this.DomainName = domainName; + this.AcctName = acctName; + if (decrementAuthority) + { + SubAuthorityCount--; + SubAuthority = new int[SubAuthorityCount]; + for (int i = 0; i < SubAuthorityCount; i++) + { + SubAuthority[i] = sid.SubAuthority[i]; + } + } + } + + public virtual Sid GetDomainSid() + { + return new Sid(this, SidTypeDomain, DomainName, null, GetType() + != SidTypeDomain); + } + + public virtual int GetRid() + { + if (GetType() == SidTypeDomain) + { + throw new ArgumentException("This SID is a domain sid"); + } + return SubAuthority[SubAuthorityCount - 1]; + } + + /// <summary>Returns the type of this SID indicating the state or type of account.</summary> + /// <remarks> + /// Returns the type of this SID indicating the state or type of account. + /// <p> + /// SID types are described in the following table. + /// <tt> + /// <table> + /// <tr><th>Type</th><th>Name</th></tr> + /// <tr><td>SID_TYPE_USE_NONE</td><td>0</td></tr> + /// <tr><td>SID_TYPE_USER</td><td>User</td></tr> + /// <tr><td>SID_TYPE_DOM_GRP</td><td>Domain group</td></tr> + /// <tr><td>SID_TYPE_DOMAIN</td><td>Domain</td></tr> + /// <tr><td>SID_TYPE_ALIAS</td><td>Local group</td></tr> + /// <tr><td>SID_TYPE_WKN_GRP</td><td>Builtin group</td></tr> + /// <tr><td>SID_TYPE_DELETED</td><td>Deleted</td></tr> + /// <tr><td>SID_TYPE_INVALID</td><td>Invalid</td></tr> + /// <tr><td>SID_TYPE_UNKNOWN</td><td>Unknown</td></tr> + /// </table> + /// </tt> + /// </remarks> + public virtual int GetType() + { + if (OriginServer != null) + { + ResolveWeak(); + } + return Type; + } + + /// <summary> + /// Return text represeting the SID type suitable for display to + /// users. + /// </summary> + /// <remarks> + /// Return text represeting the SID type suitable for display to + /// users. Text includes 'User', 'Domain group', 'Local group', etc. + /// </remarks> + public virtual string GetTypeText() + { + if (OriginServer != null) + { + ResolveWeak(); + } + return SidTypeNames[Type]; + } + + /// <summary> + /// Return the domain name of this SID unless it could not be + /// resolved in which case the numeric representation is returned. + /// </summary> + /// <remarks> + /// Return the domain name of this SID unless it could not be + /// resolved in which case the numeric representation is returned. + /// </remarks> + public virtual string GetDomainName() + { + if (OriginServer != null) + { + ResolveWeak(); + } + if (Type == SidTypeUnknown) + { + string full = ToString(); + return Runtime.Substring(full, 0, full.Length - GetAccountName().Length - + 1); + } + return DomainName; + } + + /// <summary> + /// Return the sAMAccountName of this SID unless it could not + /// be resolved in which case the numeric RID is returned. + /// </summary> + /// <remarks> + /// Return the sAMAccountName of this SID unless it could not + /// be resolved in which case the numeric RID is returned. If this + /// SID is a domain SID, this method will return an empty String. + /// </remarks> + public virtual string GetAccountName() + { + if (OriginServer != null) + { + ResolveWeak(); + } + if (Type == SidTypeUnknown) + { + return string.Empty + SubAuthority[SubAuthorityCount - 1]; + } + if (Type == SidTypeDomain) + { + return string.Empty; + } + return AcctName; + } + + public override int GetHashCode() + { + int hcode = IdentifierAuthority[5]; + for (int i = 0; i < SubAuthorityCount; i++) + { + hcode += 65599 * SubAuthority[i]; + } + return hcode; + } + + public override bool Equals(object obj) + { + if (obj is Sid) + { + Sid sid = (Sid)obj; + if (sid == this) + { + return true; + } + if (sid.SubAuthorityCount == SubAuthorityCount) + { + int i = SubAuthorityCount; + while (i-- > 0) + { + if (sid.SubAuthority[i] != SubAuthority[i]) + { + return false; + } + } + for (i = 0; i < 6; i++) + { + if (sid.IdentifierAuthority[i] != IdentifierAuthority[i]) + { + return false; + } + } + return sid.Revision == Revision; + } + } + return false; + } + + /// <summary> + /// Return the numeric representation of this sid such as + /// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>. + /// </summary> + /// <remarks> + /// Return the numeric representation of this sid such as + /// <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>. + /// </remarks> + public override string ToString() + { + string ret = "S-" + (Revision & unchecked(0xFF)) + "-"; + if (IdentifierAuthority[0] != unchecked(0) || IdentifierAuthority[1] != unchecked( + 0)) + { + ret += "0x"; + ret += Hexdump.ToHexString(IdentifierAuthority, 0, 6); + } + else + { + int shift = 0; + long id = 0; + for (int i = 5; i > 1; i--) + { + id += (IdentifierAuthority[i] & unchecked(0xFFL)) << shift; + shift += 8; + } + ret += id; + } + for (int i1 = 0; i1 < SubAuthorityCount; i1++) + { + ret += "-" + (SubAuthority[i1] & unchecked(0xFFFFFFFFL)); + } + return ret; + } + + /// <summary> + /// Return a String representing this SID ideal for display to + /// users. + /// </summary> + /// <remarks> + /// Return a String representing this SID ideal for display to + /// users. This method should return the same text that the ACL + /// editor in Windows would display. + /// <p> + /// Specifically, if the SID has + /// been resolved and it is not a domain SID or builtin account, + /// the full DOMAIN\name form of the account will be + /// returned (e.g. MYDOM\alice or MYDOM\Domain Users). + /// If the SID has been resolved but it is is a domain SID, + /// only the domain name will be returned (e.g. MYDOM). + /// If the SID has been resolved but it is a builtin account, + /// only the name component will be returned (e.g. SYSTEM). + /// If the sid cannot be resolved the numeric representation from + /// toString() is returned. + /// </remarks> + public virtual string ToDisplayString() + { + if (OriginServer != null) + { + ResolveWeak(); + } + if (DomainName != null) + { + string str; + if (Type == SidTypeDomain) + { + str = DomainName; + } + else + { + if (Type == SidTypeWknGrp || DomainName.Equals("BUILTIN")) + { + if (Type == SidTypeUnknown) + { + str = ToString(); + } + else + { + str = AcctName; + } + } + else + { + str = DomainName + "\\" + AcctName; + } + } + return str; + } + return ToString(); + } + + /// <summary>Manually resolve this SID.</summary> + /// <remarks> + /// Manually resolve this SID. Normally SIDs are automatically + /// resolved. However, if a SID is constructed explicitly using a SID + /// constructor, JCIFS will have no knowledge of the server that created the + /// SID and therefore cannot possibly resolve it automatically. In this case, + /// this method will be necessary. + /// </remarks> + /// <param name="authorityServerName">The FQDN of the server that is an authority for the SID. + /// </param> + /// <param name="auth">Credentials suitable for accessing the SID's information.</param> + /// <exception cref="System.IO.IOException"></exception> + public virtual void Resolve(string authorityServerName, NtlmPasswordAuthentication + auth) + { + Sid[] sids = new Sid[1]; + sids[0] = this; + ResolveSids(authorityServerName, auth, sids); + } + + internal virtual void ResolveWeak() + { + if (OriginServer != null) + { + try + { + Resolve(OriginServer, OriginAuth); + } + catch (IOException) + { + } + finally + { + OriginServer = null; + OriginAuth = null; + } + } + } + + /// <exception cref="System.IO.IOException"></exception> + internal static Sid[] GetGroupMemberSids0(DcerpcHandle handle, SamrDomainHandle + domainHandle, Sid domsid, int rid, int flags) + { + SamrAliasHandle aliasHandle = null; + Lsarpc.LsarSidArray sidarray = new Lsarpc.LsarSidArray(); + MsrpcGetMembersInAlias rpc = null; + try + { + aliasHandle = new SamrAliasHandle(handle, domainHandle, unchecked(0x0002000c), rid); + rpc = new MsrpcGetMembersInAlias(aliasHandle, sidarray); + handle.Sendrecv(rpc); + if (rpc.Retval != 0) + { + throw new SmbException(rpc.Retval, false); + } + Sid[] sids = new Sid[rpc.Sids.NumSids]; + string originServer = handle.GetServer(); + NtlmPasswordAuthentication originAuth = (NtlmPasswordAuthentication)handle.GetPrincipal + (); + for (int i = 0; i < sids.Length; i++) + { + sids[i] = new Sid(rpc.Sids.Sids[i].Sid, 0, null, null, false); + sids[i].OriginServer = originServer; + sids[i].OriginAuth = originAuth; + } + if (sids.Length > 0 && (flags & SidFlagResolveSids) != 0) + { + ResolveSids(originServer, originAuth, sids); + } + return sids; + } + finally + { + if (aliasHandle != null) + { + aliasHandle.Close(); + } + } + } + + /// <exception cref="System.IO.IOException"></exception> + public virtual Sid[] GetGroupMemberSids(string authorityServerName, NtlmPasswordAuthentication + auth, int flags) + { + if (Type != SidTypeDomGrp && Type != SidTypeAlias) + { + return new Sid[0]; + } + DcerpcHandle handle = null; + SamrPolicyHandle policyHandle = null; + SamrDomainHandle domainHandle = null; + Sid domsid = GetDomainSid(); + lock (SidCache) + { + try + { + handle = DcerpcHandle.GetHandle("ncacn_np:" + authorityServerName + "[\\PIPE\\samr]" + , auth); + policyHandle = new SamrPolicyHandle(handle, authorityServerName, unchecked(0x00000030)); + domainHandle = new SamrDomainHandle(handle, policyHandle, unchecked(0x00000200), domsid); + return GetGroupMemberSids0(handle, domainHandle, domsid, GetRid(), + flags); + } + finally + { + if (handle != null) + { + if (policyHandle != null) + { + if (domainHandle != null) + { + domainHandle.Close(); + } + policyHandle.Close(); + } + handle.Close(); + } + } + } + } + + /// <summary> + /// This specialized method returns a Map of users and local groups for the + /// target server where keys are SIDs representing an account and each value + /// is an List<object> of SIDs represents the local groups that the account is + /// a member of. + /// </summary> + /// <remarks> + /// This specialized method returns a Map of users and local groups for the + /// target server where keys are SIDs representing an account and each value + /// is an List<object> of SIDs represents the local groups that the account is + /// a member of. + /// <p/> + /// This method is designed to assist with computing access control for a + /// given user when the target object's ACL has local groups. Local groups + /// are not listed in a user's group membership (e.g. as represented by the + /// tokenGroups constructed attribute retrived via LDAP). + /// <p/> + /// Domain groups nested inside a local group are currently not expanded. In + /// this case the key (SID) type will be SID_TYPE_DOM_GRP rather than + /// SID_TYPE_USER. + /// </remarks> + /// <param name="authorityServerName">The server from which the local groups will be queried. + /// </param> + /// <param name="auth">The credentials required to query groups and group members.</param> + /// <param name="flags"> + /// Flags that control the behavior of the operation. When all + /// name associated with SIDs will be required, the SID_FLAG_RESOLVE_SIDS + /// flag should be used which causes all group member SIDs to be resolved + /// together in a single more efficient operation. + /// </param> + /// <exception cref="System.IO.IOException"></exception> + internal static Hashtable GetLocalGroupsMap(string authorityServerName, NtlmPasswordAuthentication + auth, int flags) + { + Sid domsid = GetServerSid(authorityServerName, auth); + DcerpcHandle handle = null; + SamrPolicyHandle policyHandle = null; + SamrDomainHandle domainHandle = null; + Samr.SamrSamArray sam = new Samr.SamrSamArray(); + MsrpcEnumerateAliasesInDomain rpc; + lock (SidCache) + { + try + { + handle = DcerpcHandle.GetHandle("ncacn_np:" + authorityServerName + "[\\PIPE\\samr]" + , auth); + policyHandle = new SamrPolicyHandle(handle, authorityServerName, unchecked(0x02000000)); + domainHandle = new SamrDomainHandle(handle, policyHandle, unchecked(0x02000000), domsid); + rpc = new MsrpcEnumerateAliasesInDomain(domainHandle, unchecked(0xFFFF), sam + ); + handle.Sendrecv(rpc); + if (rpc.Retval != 0) + { + throw new SmbException(rpc.Retval, false); + } + Hashtable map = new Hashtable(); + for (int ei = 0; ei < rpc.Sam.Count; ei++) + { + Samr.SamrSamEntry entry = rpc.Sam.Entries[ei]; + Sid[] mems = GetGroupMemberSids0(handle, domainHandle, domsid + , entry.Idx, flags); + Sid groupSid = new Sid(domsid, entry.Idx); + groupSid.Type = SidTypeAlias; + groupSid.DomainName = domsid.GetDomainName(); + groupSid.AcctName = (new UnicodeString(entry.Name, false)).ToString(); + for (int mi = 0; mi < mems.Length; mi++) + { + List<object> groups = (List<object>)map.Get(mems[mi]); + if (groups == null) + { + groups = new List<object>(); + map.Put(mems[mi], groups); + } + if (!groups.Contains(groupSid)) + { + groups.Add(groupSid); + } + } + } + return map; + } + finally + { + if (handle != null) + { + if (policyHandle != null) + { + if (domainHandle != null) + { + domainHandle.Close(); + } + policyHandle.Close(); + } + handle.Close(); + } + } + } + } + } +} |
