1 /* jcifs smb client library in Java
2  * Copyright (C) 2006  "Michael B. Allen" <jcifs at samba dot org>
3  *                     "Eric Glass" <jcifs at samba dot org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 
20 package jcifs.smb;
21 
22 import java.util.*;
23 import java.io.IOException;
24 
25 import jcifs.util.Hexdump;
26 import jcifs.dcerpc.*;
27 import jcifs.dcerpc.msrpc.*;
28 
29 /**
30  * A Windows SID is a numeric identifier used to represent Windows
31  * accounts. SIDs are commonly represented using a textual format such as
32  * <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt> but they may
33  * also be resolved to yield the name of the associated Windows account
34  * such as <tt>Administrators</tt> or <tt>MYDOM\alice</tt>.
35  * <p>
36  * Consider the following output of <tt>examples/SidLookup.java</tt>:
37  * <pre>
38  *        toString: S-1-5-21-4133388617-793952518-2001621813-512
39  * toDisplayString: WNET\Domain Admins
40  *         getType: 2
41  *     getTypeText: Domain group
42  *   getDomainName: WNET
43  *  getAccountName: Domain Admins
44  * </pre>
45  */
46 
47 public class SID extends rpc.sid_t {
48 
49     public static final int SID_TYPE_USE_NONE = lsarpc.SID_NAME_USE_NONE;
50     public static final int SID_TYPE_USER    = lsarpc.SID_NAME_USER;
51     public static final int SID_TYPE_DOM_GRP = lsarpc.SID_NAME_DOM_GRP;
52     public static final int SID_TYPE_DOMAIN  = lsarpc.SID_NAME_DOMAIN;
53     public static final int SID_TYPE_ALIAS   = lsarpc.SID_NAME_ALIAS;
54     public static final int SID_TYPE_WKN_GRP = lsarpc.SID_NAME_WKN_GRP;
55     public static final int SID_TYPE_DELETED = lsarpc.SID_NAME_DELETED;
56     public static final int SID_TYPE_INVALID = lsarpc.SID_NAME_INVALID;
57     public static final int SID_TYPE_UNKNOWN = lsarpc.SID_NAME_UNKNOWN;
58 
59     static final String[] SID_TYPE_NAMES = {
60         "0",
61         "User",
62         "Domain group",
63         "Domain",
64         "Local group",
65         "Builtin group",
66         "Deleted",
67         "Invalid",
68         "Unknown"
69     };
70 
71     public static final int SID_FLAG_RESOLVE_SIDS = 0x0001;
72 
73     public static SID EVERYONE = null;
74     public static SID CREATOR_OWNER = null;
75     public static SID SYSTEM = null;
76 
77     static {
78         try {
79             EVERYONE = new SID("S-1-1-0");
80             CREATOR_OWNER = new SID("S-1-3-0");
81             SYSTEM = new SID("S-1-5-18");
82         } catch (SmbException se) {
83         }
84     }
85 
86     static Map sid_cache = new HashMap();
87 
resolveSids(DcerpcHandle handle, LsaPolicyHandle policyHandle, SID[] sids)88     static void resolveSids(DcerpcHandle handle,
89                 LsaPolicyHandle policyHandle,
90                 SID[] sids) throws IOException {
91         MsrpcLookupSids rpc = new MsrpcLookupSids(policyHandle, sids);
92         handle.sendrecv(rpc);
93         switch (rpc.retval) {
94             case 0:
95             case NtStatus.NT_STATUS_NONE_MAPPED:
96             case 0x00000107: // NT_STATUS_SOME_NOT_MAPPED
97                 break;
98             default:
99                 throw new SmbException(rpc.retval, false);
100         }
101 
102         for (int si = 0; si < sids.length; si++) {
103             sids[si].type = rpc.names.names[si].sid_type;
104             sids[si].domainName = null;
105 
106             switch (sids[si].type) {
107                 case SID_TYPE_USER:
108                 case SID_TYPE_DOM_GRP:
109                 case SID_TYPE_DOMAIN:
110                 case SID_TYPE_ALIAS:
111                 case SID_TYPE_WKN_GRP:
112                     int sid_index = rpc.names.names[si].sid_index;
113                     rpc.unicode_string ustr = rpc.domains.domains[sid_index].name;
114                     sids[si].domainName = (new UnicodeString(ustr, false)).toString();
115                     break;
116             }
117 
118             sids[si].acctName = (new UnicodeString(rpc.names.names[si].name, false)).toString();
119             sids[si].origin_server = null;
120             sids[si].origin_auth = null;
121         }
122     }
resolveSids0(String authorityServerName, NtlmPasswordAuthentication auth, SID[] sids)123     static void resolveSids0(String authorityServerName,
124                 NtlmPasswordAuthentication auth,
125                 SID[] sids) throws IOException {
126         DcerpcHandle handle = null;
127         LsaPolicyHandle policyHandle = null;
128 
129 synchronized (sid_cache) {
130         try {
131             handle = DcerpcHandle.getHandle("ncacn_np:" + authorityServerName +
132                     "[\\PIPE\\lsarpc]", auth);
133             String server = authorityServerName;
134             int dot = server.indexOf('.');
135             if (dot > 0 && Character.isDigit(server.charAt(0)) == false)
136                 server = server.substring(0, dot);
137             policyHandle = new LsaPolicyHandle(handle, "\\\\" + server, 0x00000800);
138             SID.resolveSids(handle, policyHandle, sids);
139         } finally {
140             if (handle != null) {
141                 if (policyHandle != null) {
142                     policyHandle.close();
143                 }
144                 handle.close();
145             }
146         }
147 }
148     }
149 
resolveSids(String authorityServerName, NtlmPasswordAuthentication auth, SID[] sids, int offset, int length)150     static public void resolveSids(String authorityServerName,
151                 NtlmPasswordAuthentication auth,
152                 SID[] sids,
153                 int offset,
154                 int length) throws IOException {
155         ArrayList list = new ArrayList(sids.length);
156         int si;
157 
158 synchronized (sid_cache) {
159         for (si = 0; si < length; si++) {
160             SID sid = (SID)sid_cache.get(sids[offset + si]);
161             if (sid != null) {
162                 sids[offset + si].type = sid.type;
163                 sids[offset + si].domainName = sid.domainName;
164                 sids[offset + si].acctName = sid.acctName;
165             } else {
166                 list.add(sids[offset + si]);
167             }
168         }
169 
170         if (list.size() > 0) {
171             sids = (SID[])list.toArray(new SID[0]);
172             SID.resolveSids0(authorityServerName, auth, sids);
173             for (si = 0; si < sids.length; si++) {
174                 sid_cache.put(sids[si], sids[si]);
175             }
176         }
177 }
178     }
179     /**
180      * Resolve an array of SIDs using a cache and at most one MSRPC request.
181      * <p>
182      * This method will attempt
183      * to resolve SIDs using a cache and cache the results of any SIDs that
184      * required resolving with the authority. SID cache entries are currently not
185      * expired because under normal circumstances SID information never changes.
186      *
187      * @param 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.
188      * @param 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.
189      * @param 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.
190      */
resolveSids(String authorityServerName, NtlmPasswordAuthentication auth, SID[] sids)191     static public void resolveSids(String authorityServerName,
192                 NtlmPasswordAuthentication auth,
193                 SID[] sids) throws IOException {
194         ArrayList list = new ArrayList(sids.length);
195         int si;
196 
197 synchronized (sid_cache) {
198         for (si = 0; si < sids.length; si++) {
199             SID sid = (SID)sid_cache.get(sids[si]);
200             if (sid != null) {
201                 sids[si].type = sid.type;
202                 sids[si].domainName = sid.domainName;
203                 sids[si].acctName = sid.acctName;
204             } else {
205                 list.add(sids[si]);
206             }
207         }
208 
209         if (list.size() > 0) {
210             sids = (SID[])list.toArray(new SID[0]);
211             SID.resolveSids0(authorityServerName, auth, sids);
212             for (si = 0; si < sids.length; si++) {
213                 sid_cache.put(sids[si], sids[si]);
214             }
215         }
216 }
217     }
getServerSid(String server, NtlmPasswordAuthentication auth)218     public static SID getServerSid(String server,
219                     NtlmPasswordAuthentication auth) throws IOException {
220         DcerpcHandle handle = null;
221         LsaPolicyHandle policyHandle = null;
222         lsarpc.LsarDomainInfo info = new lsarpc.LsarDomainInfo();
223         MsrpcQueryInformationPolicy rpc;
224 
225 synchronized (sid_cache) {
226         try {
227             handle = DcerpcHandle.getHandle("ncacn_np:" + server +
228                     "[\\PIPE\\lsarpc]", auth);
229             // NetApp doesn't like the 'generic' access mask values
230             policyHandle = new LsaPolicyHandle(handle, null, 0x00000001);
231             rpc = new MsrpcQueryInformationPolicy(policyHandle,
232                         (short)lsarpc.POLICY_INFO_ACCOUNT_DOMAIN,
233                         info);
234             handle.sendrecv(rpc);
235             if (rpc.retval != 0)
236                 throw new SmbException(rpc.retval, false);
237 
238             return new SID(info.sid,
239                         SID.SID_TYPE_DOMAIN,
240                         (new UnicodeString(info.name, false)).toString(),
241                         null,
242                         false);
243         } finally {
244             if (handle != null) {
245                 if (policyHandle != null) {
246                     policyHandle.close();
247                 }
248                 handle.close();
249             }
250         }
251 }
252     }
toByteArray(rpc.sid_t sid)253     public static byte[] toByteArray(rpc.sid_t sid) {
254         byte[] dst = new byte[1 + 1 + 6 + sid.sub_authority_count * 4];
255         int di = 0;
256         dst[di++] = sid.revision;
257         dst[di++] = sid.sub_authority_count;
258         System.arraycopy(sid.identifier_authority, 0, dst, di, 6);
259         di += 6;
260         for (int ii = 0; ii < sid.sub_authority_count; ii++) {
261             jcifs.util.Encdec.enc_uint32le(sid.sub_authority[ii], dst, di);
262             di += 4;
263         }
264         return dst;
265     }
266 
267     int type;
268     String domainName = null;
269     String acctName = null;
270     String origin_server = null;
271     NtlmPasswordAuthentication origin_auth = null;
272 
273     /*
274      * Construct a SID from it's binary representation.
275      */
SID(byte[] src, int si)276     public SID(byte[] src, int si) {
277         revision = src[si++];
278         sub_authority_count = src[si++];
279         identifier_authority = new byte[6];
280         System.arraycopy(src, si, identifier_authority, 0, 6);
281         si += 6;
282         if (sub_authority_count > 100)
283             throw new RuntimeException( "Invalid SID sub_authority_count" );
284         sub_authority = new int[sub_authority_count];
285         for (int i = 0; i < sub_authority_count; i++) {
286             sub_authority[i] = ServerMessageBlock.readInt4( src, si );
287             si += 4;
288         }
289     }
290     /**
291      * Construct a SID from it's textual representation such as
292      * <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>.
293      */
SID(String textual)294     public SID(String textual) throws SmbException {
295         StringTokenizer st = new StringTokenizer(textual, "-");
296         if (st.countTokens() < 3 || !st.nextToken().equals("S"))
297             // need S-N-M
298             throw new SmbException("Bad textual SID format: " + textual);
299 
300         this.revision = Byte.parseByte(st.nextToken());
301         String tmp = st.nextToken();
302         long id = 0;
303         if (tmp.startsWith("0x"))
304             id = Long.parseLong(tmp.substring(2), 16);
305         else
306             id = Long.parseLong(tmp);
307 
308         this.identifier_authority = new byte[6];
309         for (int i = 5; id > 0;  i--) {
310             this.identifier_authority[i] = (byte) (id % 256);
311             id >>= 8;
312         }
313 
314         this.sub_authority_count = (byte) st.countTokens();
315         if (this.sub_authority_count > 0) {
316             this.sub_authority = new int[this.sub_authority_count];
317             for (int i = 0; i < this.sub_authority_count; i++)
318                 this.sub_authority[i] = (int)(Long.parseLong(st.nextToken()) & 0xFFFFFFFFL);
319         }
320     }
321 
322     /**
323      * Construct a SID from a domain SID and an RID
324      * (relative identifier). For example, a domain SID
325      * <tt>S-1-5-21-1496946806-2192648263-3843101252</tt> and RID <tt>1029</tt> would
326      * yield the SID <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>.
327      */
SID(SID domsid, int rid)328     public SID(SID domsid, int rid) {
329         this.revision = domsid.revision;
330         this.identifier_authority = domsid.identifier_authority;
331         this.sub_authority_count = (byte)(domsid.sub_authority_count + 1);
332         this.sub_authority = new int[this.sub_authority_count];
333         int i;
334         for (i = 0; i < domsid.sub_authority_count; i++) {
335             this.sub_authority[i] = domsid.sub_authority[i];
336         }
337         this.sub_authority[i] = rid;
338     }
SID(rpc.sid_t sid, int type, String domainName, String acctName, boolean decrementAuthority)339     public SID(rpc.sid_t sid,
340                     int type,
341                     String domainName,
342                     String acctName,
343                     boolean decrementAuthority) {
344         this.revision = sid.revision;
345         this.sub_authority_count = sid.sub_authority_count;
346         this.identifier_authority = sid.identifier_authority;
347         this.sub_authority = sid.sub_authority;
348         this.type = type;
349         this.domainName = domainName;
350         this.acctName = acctName;
351 
352         if (decrementAuthority) {
353             this.sub_authority_count--;
354             this.sub_authority = new int[sub_authority_count];
355             for (int i = 0; i < this.sub_authority_count; i++) {
356                 this.sub_authority[i] = sid.sub_authority[i];
357             }
358         }
359     }
360 
getDomainSid()361     public SID getDomainSid() {
362         return new SID(this,
363                     SID_TYPE_DOMAIN,
364                     this.domainName,
365                     null,
366                     getType() != SID_TYPE_DOMAIN);
367     }
getRid()368     public int getRid() {
369         if (getType() == SID_TYPE_DOMAIN)
370             throw new IllegalArgumentException("This SID is a domain sid");
371         return sub_authority[sub_authority_count - 1];
372     }
373 
374     /**
375      * Returns the type of this SID indicating the state or type of account.
376      * <p>
377      * SID types are described in the following table.
378      * <tt>
379      * <table>
380      * <tr><th>Type</th><th>Name</th></tr>
381      * <tr><td>SID_TYPE_USE_NONE</td><td>0</td></tr>
382      * <tr><td>SID_TYPE_USER</td><td>User</td></tr>
383      * <tr><td>SID_TYPE_DOM_GRP</td><td>Domain group</td></tr>
384      * <tr><td>SID_TYPE_DOMAIN</td><td>Domain</td></tr>
385      * <tr><td>SID_TYPE_ALIAS</td><td>Local group</td></tr>
386      * <tr><td>SID_TYPE_WKN_GRP</td><td>Builtin group</td></tr>
387      * <tr><td>SID_TYPE_DELETED</td><td>Deleted</td></tr>
388      * <tr><td>SID_TYPE_INVALID</td><td>Invalid</td></tr>
389      * <tr><td>SID_TYPE_UNKNOWN</td><td>Unknown</td></tr>
390      * </table>
391      * </tt>
392      */
getType()393     public int getType() {
394         if (origin_server != null)
395             resolveWeak();
396         return type;
397     }
398 
399     /**
400      * Return text represeting the SID type suitable for display to
401      * users. Text includes 'User', 'Domain group', 'Local group', etc.
402      */
getTypeText()403     public String getTypeText() {
404         if (origin_server != null)
405             resolveWeak();
406         return SID_TYPE_NAMES[type];
407     }
408 
409     /**
410      * Return the domain name of this SID unless it could not be
411      * resolved in which case the numeric representation is returned.
412      */
getDomainName()413     public String getDomainName() {
414         if (origin_server != null)
415             resolveWeak();
416         if (type == SID_TYPE_UNKNOWN) {
417             String full = toString();
418             return full.substring(0, full.length() - getAccountName().length() - 1);
419         }
420         return domainName;
421     }
422 
423     /**
424      * Return the sAMAccountName of this SID unless it could not
425      * be resolved in which case the numeric RID is returned. If this
426      * SID is a domain SID, this method will return an empty String.
427      */
getAccountName()428     public String getAccountName() {
429         if (origin_server != null)
430             resolveWeak();
431         if (type == SID_TYPE_UNKNOWN)
432             return "" + sub_authority[sub_authority_count - 1];
433         if (type == SID_TYPE_DOMAIN)
434             return "";
435         return acctName;
436     }
437 
hashCode()438     public int hashCode() {
439         int hcode = identifier_authority[5];
440         for (int i = 0; i < sub_authority_count; i++) {
441             hcode += 65599 * sub_authority[i];
442         }
443         return hcode;
444     }
equals(Object obj)445     public boolean equals(Object obj) {
446         if (obj instanceof SID) {
447             SID sid = (SID)obj;
448             if (sid == this)
449                 return true;
450             if (sid.sub_authority_count == sub_authority_count) {
451                 int i = sub_authority_count;
452                 while (i-- > 0) {
453                     if (sid.sub_authority[i] != sub_authority[i]) {
454                         return false;
455                     }
456                 }
457                 for (i = 0; i < 6; i++) {
458                     if (sid.identifier_authority[i] != identifier_authority[i]) {
459                         return false;
460                     }
461                 }
462 
463                 return sid.revision == revision;
464             }
465         }
466         return false;
467     }
468 
469     /**
470      * Return the numeric representation of this sid such as
471      * <tt>S-1-5-21-1496946806-2192648263-3843101252-1029</tt>.
472      */
toString()473     public String toString() {
474         String ret = "S-" + (revision & 0xFF) + "-";
475 
476         if (identifier_authority[0] != (byte)0 || identifier_authority[1] != (byte)0) {
477             ret += "0x";
478             ret += Hexdump.toHexString(identifier_authority, 0, 6);
479         } else {
480             long shift = 0;
481             long id = 0;
482             for (int i = 5; i > 1; i--) {
483                 id += (identifier_authority[i] & 0xFFL) << shift;
484                 shift += 8;
485             }
486             ret += id;
487         }
488 
489         for (int i = 0; i < sub_authority_count ; i++)
490             ret += "-" + (sub_authority[i] & 0xFFFFFFFFL);
491 
492         return ret;
493     }
494 
495     /**
496      * Return a String representing this SID ideal for display to
497      * users. This method should return the same text that the ACL
498      * editor in Windows would display.
499      * <p>
500      * Specifically, if the SID has
501      * been resolved and it is not a domain SID or builtin account,
502      * the full DOMAIN\name form of the account will be
503      * returned (e.g. MYDOM\alice or MYDOM\Domain Users).
504      * If the SID has been resolved but it is is a domain SID,
505      * only the domain name will be returned (e.g. MYDOM).
506      * If the SID has been resolved but it is a builtin account,
507      * only the name component will be returned (e.g. SYSTEM).
508      * If the sid cannot be resolved the numeric representation from
509      * toString() is returned.
510      */
toDisplayString()511     public String toDisplayString() {
512         if (origin_server != null)
513             resolveWeak();
514         if (domainName != null) {
515             String str;
516 
517             if (type == SID_TYPE_DOMAIN) {
518                 str = domainName;
519             } else if (type == SID_TYPE_WKN_GRP ||
520                         domainName.equals("BUILTIN")) {
521                 if (type == SID_TYPE_UNKNOWN) {
522                     str = toString();
523                 } else {
524                     str = acctName;
525                 }
526             } else {
527                 str = domainName + "\\" + acctName;
528             }
529 
530             return str;
531         }
532         return toString();
533     }
534 
535     /**
536      * Manually resolve this SID. Normally SIDs are automatically
537      * resolved. However, if a SID is constructed explicitly using a SID
538      * constructor, JCIFS will have no knowledge of the server that created the
539      * SID and therefore cannot possibly resolve it automatically. In this case,
540      * this method will be necessary.
541      *
542      * @param authorityServerName The FQDN of the server that is an authority for the SID.
543      * @param auth Credentials suitable for accessing the SID's information.
544      */
resolve(String authorityServerName, NtlmPasswordAuthentication auth)545     public void resolve(String authorityServerName,
546                     NtlmPasswordAuthentication auth) throws IOException {
547         SID[] sids = new SID[1];
548         sids[0] = this;
549         SID.resolveSids(authorityServerName, auth, sids);
550     }
551 
resolveWeak()552     void resolveWeak() {
553         if (origin_server != null) {
554             try {
555                 resolve(origin_server, origin_auth);
556             } catch(IOException ioe) {
557             } finally {
558                 origin_server = null;
559                 origin_auth = null;
560             }
561         }
562     }
563 
getGroupMemberSids0(DcerpcHandle handle, SamrDomainHandle domainHandle, SID domsid, int rid, int flags)564     static SID[] getGroupMemberSids0(DcerpcHandle handle,
565                     SamrDomainHandle domainHandle,
566                     SID domsid,
567                     int rid,
568                     int flags) throws IOException {
569         SamrAliasHandle aliasHandle = null;
570         lsarpc.LsarSidArray sidarray = new lsarpc.LsarSidArray();
571         MsrpcGetMembersInAlias rpc = null;
572 
573         try {
574             aliasHandle = new SamrAliasHandle(handle, domainHandle, 0x0002000c, rid);
575             rpc = new MsrpcGetMembersInAlias(aliasHandle, sidarray);
576             handle.sendrecv(rpc);
577             if (rpc.retval != 0)
578                 throw new SmbException(rpc.retval, false);
579             SID[] sids = new SID[rpc.sids.num_sids];
580 
581             String origin_server = handle.getServer();
582             NtlmPasswordAuthentication origin_auth =
583                         (NtlmPasswordAuthentication)handle.getPrincipal();
584 
585             for (int i = 0; i < sids.length; i++) {
586                 sids[i] = new SID(rpc.sids.sids[i].sid,
587                             0,
588                             null,
589                             null,
590                             false);
591                 sids[i].origin_server = origin_server;
592                 sids[i].origin_auth = origin_auth;
593             }
594             if (sids.length > 0 && (flags & SID_FLAG_RESOLVE_SIDS) != 0) {
595                 SID.resolveSids(origin_server, origin_auth, sids);
596             }
597             return sids;
598         } finally {
599             if (aliasHandle != null) {
600                 aliasHandle.close();
601             }
602         }
603     }
604 
getGroupMemberSids(String authorityServerName, NtlmPasswordAuthentication auth, int flags)605     public SID[] getGroupMemberSids(String authorityServerName,
606                     NtlmPasswordAuthentication auth,
607                     int flags) throws IOException {
608         if (type != SID_TYPE_DOM_GRP && type != SID_TYPE_ALIAS)
609             return new SID[0];
610 
611         DcerpcHandle handle = null;
612         SamrPolicyHandle policyHandle = null;
613         SamrDomainHandle domainHandle = null;
614         SID domsid = getDomainSid();
615 
616 synchronized (sid_cache) {
617         try {
618             handle = DcerpcHandle.getHandle("ncacn_np:" + authorityServerName +
619                     "[\\PIPE\\samr]", auth);
620             policyHandle = new SamrPolicyHandle(handle, authorityServerName, 0x00000030);
621             domainHandle = new SamrDomainHandle(handle, policyHandle, 0x00000200, domsid);
622             return SID.getGroupMemberSids0(handle,
623                         domainHandle,
624                         domsid,
625                         getRid(),
626                         flags);
627         } finally {
628             if (handle != null) {
629                 if (policyHandle != null) {
630                     if (domainHandle != null) {
631                         domainHandle.close();
632                     }
633                     policyHandle.close();
634                 }
635                 handle.close();
636             }
637         }
638 }
639     }
640 
641     /**
642      * This specialized method returns a Map of users and local groups for the
643      * target server where keys are SIDs representing an account and each value
644      * is an ArrayList of SIDs represents the local groups that the account is
645      * a member of.
646      * <p/>
647      * This method is designed to assist with computing access control for a
648      * given user when the target object's ACL has local groups. Local groups
649      * are not listed in a user's group membership (e.g. as represented by the
650      * tokenGroups constructed attribute retrived via LDAP).
651      * <p/>
652      * Domain groups nested inside a local group are currently not expanded. In
653      * this case the key (SID) type will be SID_TYPE_DOM_GRP rather than
654      * SID_TYPE_USER.
655      *
656      * @param authorityServerName The server from which the local groups will be queried.
657      * @param auth The credentials required to query groups and group members.
658      * @param flags Flags that control the behavior of the operation. When all
659      * name associated with SIDs will be required, the SID_FLAG_RESOLVE_SIDS
660      * flag should be used which causes all group member SIDs to be resolved
661      * together in a single more efficient operation.
662      */
getLocalGroupsMap(String authorityServerName, NtlmPasswordAuthentication auth, int flags)663     static Map getLocalGroupsMap(String authorityServerName,
664                     NtlmPasswordAuthentication auth,
665                     int flags) throws IOException {
666         SID domsid = SID.getServerSid(authorityServerName, auth);
667         DcerpcHandle handle = null;
668         SamrPolicyHandle policyHandle = null;
669         SamrDomainHandle domainHandle = null;
670         samr.SamrSamArray sam = new samr.SamrSamArray();
671         MsrpcEnumerateAliasesInDomain rpc;
672 
673 synchronized (sid_cache) {
674         try {
675             handle = DcerpcHandle.getHandle("ncacn_np:" + authorityServerName +
676                     "[\\PIPE\\samr]", auth);
677             policyHandle = new SamrPolicyHandle(handle, authorityServerName, 0x02000000);
678             domainHandle = new SamrDomainHandle(handle, policyHandle, 0x02000000, domsid);
679             rpc = new MsrpcEnumerateAliasesInDomain(domainHandle, 0xFFFF, sam);
680             handle.sendrecv(rpc);
681             if (rpc.retval != 0)
682                 throw new SmbException(rpc.retval, false);
683 
684             Map map = new HashMap();
685 
686             for (int ei = 0; ei < rpc.sam.count; ei++) {
687                 samr.SamrSamEntry entry = rpc.sam.entries[ei];
688 
689                 SID[] mems = SID.getGroupMemberSids0(handle,
690                             domainHandle,
691                             domsid,
692                             entry.idx,
693                             flags);
694                 SID groupSid = new SID(domsid, entry.idx);
695                 groupSid.type = SID_TYPE_ALIAS;
696                 groupSid.domainName = domsid.getDomainName();
697                 groupSid.acctName = (new UnicodeString(entry.name, false)).toString();
698 
699                 for (int mi = 0; mi < mems.length; mi++) {
700                     ArrayList groups = (ArrayList)map.get(mems[mi]);
701                     if (groups == null) {
702                         groups = new ArrayList();
703                         map.put(mems[mi], groups);
704                     }
705                     if (!groups.contains(groupSid))
706                         groups.add(groupSid);
707                 }
708             }
709 
710             return map;
711         } finally {
712             if (handle != null) {
713                 if (policyHandle != null) {
714                     if (domainHandle != null) {
715                         domainHandle.close();
716                     }
717                     policyHandle.close();
718                 }
719                 handle.close();
720             }
721         }
722 }
723     }
724 }
725 
726