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