1 19 20 package jcifs.smb; 21 22 import java.io.*; 23 import java.net.*; 24 import java.util.*; 25 26 import jcifs.*; 27 import jcifs.netbios.*; 28 import jcifs.util.*; 29 import jcifs.util.transport.*; 30 31 public class SmbTransport extends Transport implements SmbConstants { 32 33 static final byte[] BUF = new byte[0xFFFF]; 34 static final SmbComNegotiate NEGOTIATE_REQUEST = new SmbComNegotiate(); 35 static LogStream log = LogStream.getInstance(); 36 37 static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) { 38 return getSmbTransport( address, port, LADDR, LPORT ); 39 } 40 static synchronized SmbTransport getSmbTransport( UniAddress address, int port, 41 InetAddress localAddr, int localPort ) { 42 SmbTransport conn; 43 44 synchronized( CONNECTIONS ) { 45 if( SSN_LIMIT != 1 ) { 46 ListIterator iter = CONNECTIONS.listIterator(); 47 while( iter.hasNext() ) { 48 conn = (SmbTransport)iter.next(); 49 if( conn.matches( address, port, localAddr, localPort ) && 50 ( SSN_LIMIT == 0 || conn.sessions.size() < SSN_LIMIT )) { 51 return conn; 52 } 53 } 54 } 55 56 conn = new SmbTransport( address, port, localAddr, localPort ); 57 CONNECTIONS.add( 0, conn ); 58 } 59 60 return conn; 61 } 62 63 class ServerData { 64 byte flags; 65 int flags2; 66 int maxMpxCount; 67 int maxBufferSize; 68 int sessionKey; 69 int capabilities; 70 String oemDomainName; 71 int securityMode; 72 int security; 73 boolean encryptedPasswords; 74 boolean signaturesEnabled; 75 boolean signaturesRequired; 76 int maxNumberVcs; 77 int maxRawSize; 78 long serverTime; 79 int serverTimeZone; 80 int encryptionKeyLength; 81 byte[] encryptionKey; 82 } 83 84 InetAddress localAddr; 85 int localPort; 86 UniAddress address; 87 Socket socket; 88 int port, mid; 89 OutputStream out; 90 InputStream in; 91 byte[] sbuf = new byte[255]; 92 SmbComBlankResponse key = new SmbComBlankResponse(); 93 long sessionExpiration = System.currentTimeMillis() + SO_TIMEOUT; 94 LinkedList referrals = new LinkedList(); 95 SigningDigest digest = null; 96 LinkedList sessions = new LinkedList(); 97 ServerData server = new ServerData(); 98 99 int flags2 = FLAGS2; 100 int maxMpxCount = MAX_MPX_COUNT; 101 int snd_buf_size = SND_BUF_SIZE; 102 int rcv_buf_size = RCV_BUF_SIZE; 103 int capabilities = CAPABILITIES; 104 int sessionKey = 0x00000000; 105 boolean useUnicode = USE_UNICODE; 106 String tconHostName; 107 108 SmbTransport( UniAddress address, int port, InetAddress localAddr, int localPort ) { 109 this.address = address; 110 this.port = port; 111 this.localAddr = localAddr; 112 this.localPort = localPort; 113 } 114 115 synchronized SmbSession getSmbSession() { 116 return getSmbSession( new NtlmPasswordAuthentication( null, null, null )); 117 } 118 synchronized SmbSession getSmbSession( NtlmPasswordAuthentication auth ) { 119 SmbSession ssn; 120 long now; 121 122 ListIterator iter = sessions.listIterator(); 123 while( iter.hasNext() ) { 124 ssn = (SmbSession)iter.next(); 125 if( ssn.matches( auth )) { 126 ssn.auth = auth; 127 return ssn; 128 } 129 } 130 131 132 if (SO_TIMEOUT > 0 && sessionExpiration < (now = System.currentTimeMillis())) { 133 sessionExpiration = now + SO_TIMEOUT; 134 iter = sessions.listIterator(); 135 while( iter.hasNext() ) { 136 ssn = (SmbSession)iter.next(); 137 if( ssn.expiration < now ) { 138 ssn.logoff( false ); 139 } 140 } 141 } 142 143 ssn = new SmbSession( address, port, localAddr, localPort, auth ); 144 ssn.transport = this; 145 sessions.add( ssn ); 146 147 return ssn; 148 } 149 boolean matches( UniAddress address, int port, InetAddress localAddr, int localPort ) { 150 return address.equals( this.address ) && 151 (port == 0 || port == this.port || 152 153 (port == 445 && this.port == 139)) && 154 (localAddr == this.localAddr || 155 (localAddr != null && 156 localAddr.equals( this.localAddr ))) && 157 localPort == this.localPort; 158 } 159 boolean hasCapability( int cap ) throws SmbException { 160 try { 161 connect( RESPONSE_TIMEOUT ); 162 } catch( IOException ioe ) { 163 throw new SmbException( "", ioe ); 164 } 165 return (capabilities & cap) == cap; 166 } 167 boolean isSignatureSetupRequired( NtlmPasswordAuthentication auth ) { 168 return ( flags2 & ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES ) != 0 && 169 digest == null && 170 auth != NtlmPasswordAuthentication.NULL && 171 NtlmPasswordAuthentication.NULL.equals( auth ) == false; 172 } 173 174 void ssn139() throws IOException { 175 Name calledName = new Name( address.firstCalledName(), 0x20, null ); 176 do { 177 if (localAddr == null) { 178 socket = new Socket( address.getHostAddress(), 139 ); 179 } else { 180 socket = new Socket( address.getHostAddress(), 139, localAddr, localPort ); 181 } 182 socket.setSoTimeout( SO_TIMEOUT ); 183 out = socket.getOutputStream(); 184 in = socket.getInputStream(); 185 186 SessionServicePacket ssp = new SessionRequestPacket( calledName, 187 NbtAddress.getLocalName() ); 188 out.write( sbuf, 0, ssp.writeWireFormat( sbuf, 0 )); 189 if (readn( in, sbuf, 0, 4 ) < 4) { 190 throw new SmbException( "EOF during NetBIOS session request" ); 191 } 192 switch( sbuf[0] & 0xFF ) { 193 case SessionServicePacket.POSITIVE_SESSION_RESPONSE: 194 if( log.level > 2 ) 195 log.println( "session established ok with " + address ); 196 return; 197 case SessionServicePacket.NEGATIVE_SESSION_RESPONSE: 198 int errorCode = (int)( in.read() & 0xFF ); 199 switch (errorCode) { 200 case NbtException.CALLED_NOT_PRESENT: 201 case NbtException.NOT_LISTENING_CALLED: 202 socket.close(); 203 break; 204 default: 205 disconnect( true ); 206 throw new NbtException( NbtException.ERR_SSN_SRVC, errorCode ); 207 } 208 break; 209 case -1: 210 disconnect( true ); 211 throw new NbtException( NbtException.ERR_SSN_SRVC, 212 NbtException.CONNECTION_REFUSED ); 213 default: 214 disconnect( true ); 215 throw new NbtException( NbtException.ERR_SSN_SRVC, 0 ); 216 } 217 } while(( calledName.name = address.nextCalledName()) != null ); 218 219 throw new IOException( "Failed to establish session with " + address ); 220 } 221 private void negotiate( int port, ServerMessageBlock resp ) throws IOException { 222 227 synchronized (sbuf) { 228 232 if (NETBIOS_HOSTNAME != null && NETBIOS_HOSTNAME.equals( "" ) == false) { 233 port = 139; 234 } 235 if (port == 139) { 236 ssn139(); 237 } else { 238 if (port == 0) 239 port = DEFAULT_PORT; if (localAddr == null) { 241 socket = new Socket( address.getHostAddress(), port ); 242 } else { 243 socket = new Socket( address.getHostAddress(), port, localAddr, localPort ); 244 } 245 socket.setSoTimeout( SO_TIMEOUT ); 246 out = socket.getOutputStream(); 247 in = socket.getInputStream(); 248 } 249 250 if (++mid == 32000) mid = 1; 251 NEGOTIATE_REQUEST.mid = mid; 252 int n = NEGOTIATE_REQUEST.encode( sbuf, 4 ); 253 Encdec.enc_uint32be( n & 0xFFFF, sbuf, 0 ); 254 out.write( sbuf, 0, 4 + n ); 255 out.flush(); 256 259 if (peekKey() == null) 260 throw new IOException( "transport closed in negotiate" ); 261 int size = Encdec.dec_uint16be( sbuf, 2 ); 262 if (size < 33 || (4 + size) > sbuf.length ) { 263 throw new IOException( "Invalid payload size: " + size ); 264 } 265 readn( in, sbuf, 4 + 32, size - 32 ); 266 resp.decode( sbuf, 4 ); 267 } 268 } 269 public void connect() throws SmbException { 270 try { 271 super.connect( RESPONSE_TIMEOUT ); 272 } catch( TransportException te ) { 273 throw new SmbException( "", te ); 274 } 275 } 276 protected void doConnect() throws IOException { 277 280 281 SmbComNegotiateResponse resp = new SmbComNegotiateResponse( server ); 282 try { 283 negotiate( port, resp ); 284 } catch( ConnectException ce ) { 285 port = (port == 0 || port == DEFAULT_PORT) ? 139 : DEFAULT_PORT; 286 negotiate( port, resp ); 287 } 288 289 if( resp.dialectIndex > 10 ) { 290 throw new SmbException( "This client does not support the negotiated dialect." ); 291 } 292 293 294 295 tconHostName = address.getHostName(); 296 if (server.signaturesRequired || (server.signaturesEnabled && SIGNPREF)) { 297 flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES; 298 } else { 299 flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES; 300 } 301 maxMpxCount = Math.min( maxMpxCount, server.maxMpxCount ); 302 if (maxMpxCount < 1) maxMpxCount = 1; 303 snd_buf_size = Math.min( snd_buf_size, server.maxBufferSize ); 304 capabilities &= server.capabilities; 305 if ((capabilities & ServerMessageBlock.CAP_UNICODE) == 0) { 306 if (FORCE_UNICODE) { 308 capabilities |= ServerMessageBlock.CAP_UNICODE; 309 } else { 310 useUnicode = false; 311 flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE; 312 } 313 } 314 } 315 protected void doDisconnect( boolean hard ) throws IOException { 316 ListIterator iter = sessions.listIterator(); 317 while (iter.hasNext()) { 318 SmbSession ssn = (SmbSession)iter.next(); 319 ssn.logoff( hard ); 320 } 321 socket.shutdownOutput(); 322 out.close(); 323 in.close(); 324 socket.close(); 325 digest = null; 326 } 327 328 protected void makeKey( Request request ) throws IOException { 329 330 if (++mid == 32000) mid = 1; 331 ((ServerMessageBlock)request).mid = mid; 332 } 333 protected Request peekKey() throws IOException { 334 int n; 335 do { 336 if ((n = readn( in, sbuf, 0, 4 )) < 4) 337 return null; 338 } while (sbuf[0] == (byte)0x85); 339 340 if ((n = readn( in, sbuf, 4, 32 )) < 32) 341 return null; 342 if (log.level > 2) { 343 log.println( "New data read: " + this ); 344 jcifs.util.Hexdump.hexdump( log, sbuf, 4, 32 ); 345 } 346 347 for ( ;; ) { 348 354 355 if (sbuf[0] == (byte)0x00 && 356 sbuf[1] == (byte)0x00 && 357 sbuf[4] == (byte)0xFF && 358 sbuf[5] == (byte)'S' && 359 sbuf[6] == (byte)'M' && 360 sbuf[7] == (byte)'B') { 361 break; 362 } 363 364 365 for (int i = 0; i < 35; i++) { 366 sbuf[i] = sbuf[i + 1]; 367 } 368 int b; 369 if ((b = in.read()) == -1) return null; 370 sbuf[35] = (byte)b; 371 } 372 373 key.mid = Encdec.dec_uint16le( sbuf, 34 ); 374 375 380 381 return key; 382 } 383 384 protected void doSend( Request request ) throws IOException { 385 synchronized (BUF) { 386 ServerMessageBlock smb = (ServerMessageBlock)request; 387 int n = smb.encode( BUF, 4 ); 388 Encdec.enc_uint32be( n & 0xFFFF, BUF, 0 ); 389 if (log.level > 3) { 390 do { 391 log.println( smb ); 392 } while (smb instanceof AndXServerMessageBlock && 393 (smb = ((AndXServerMessageBlock)smb).andx) != null); 394 if (log.level > 5) { 395 Hexdump.hexdump( log, BUF, 4, n ); 396 } 397 } 398 out.write( BUF, 0, 4 + n ); 399 } 400 } 401 protected void doSend0( Request request ) throws IOException { 402 try { 403 doSend( request ); 404 } catch( IOException ioe ) { 405 if (log.level > 2) 406 ioe.printStackTrace( log ); 407 try { 408 disconnect( true ); 409 } catch( IOException ioe2 ) { 410 ioe2.printStackTrace( log ); 411 } 412 throw ioe; 413 } 414 } 415 416 protected void doRecv( Response response ) throws IOException { 417 ServerMessageBlock resp = (ServerMessageBlock)response; 418 resp.useUnicode = useUnicode; 419 420 synchronized (BUF) { 421 System.arraycopy( sbuf, 0, BUF, 0, 4 + HEADER_LENGTH ); 422 int size = Encdec.dec_uint16be( BUF, 2 ); 423 if (size < (HEADER_LENGTH + 1) || (4 + size) > rcv_buf_size ) { 424 throw new IOException( "Invalid payload size: " + size ); 425 } 426 if (resp.command == ServerMessageBlock.SMB_COM_READ_ANDX) { 427 SmbComReadAndXResponse r = (SmbComReadAndXResponse)resp; 428 int off = HEADER_LENGTH; 429 430 readn( in, BUF, 4 + off, 27 ); off += 27; 431 resp.decode( BUF, 4 ); 432 if (r.dataLength > 0) { 433 readn( in, BUF, 4 + off, r.dataOffset - off); 434 readn( in, r.b, r.off, r.dataLength ); 435 } 436 } else { 437 readn( in, BUF, 4 + 32, size - 32 ); 438 resp.decode( BUF, 4 ); 439 if (resp instanceof SmbComTransactionResponse) { 440 ((SmbComTransactionResponse)resp).nextElement(); 441 } 442 } 443 444 448 if (digest != null && resp.errorCode == 0) { 449 digest.verify( BUF, 4, resp ); 450 } 451 } 452 } 453 protected void doSkip() throws IOException { 454 int size = Encdec.dec_uint16be( sbuf, 2 ); 455 if (size < 33 || (4 + size) > rcv_buf_size ) { 456 457 in.skip( in.available() ); 458 } else { 459 in.skip( size - 32 ); 460 } 461 } 462 void checkStatus( ServerMessageBlock req, ServerMessageBlock resp ) throws SmbException { 463 resp.errorCode = SmbException.getStatusByCode( resp.errorCode ); 464 switch( resp.errorCode ) { 465 case NtStatus.NT_STATUS_OK: 466 break; 467 case NtStatus.NT_STATUS_ACCESS_DENIED: 468 case NtStatus.NT_STATUS_WRONG_PASSWORD: 469 case NtStatus.NT_STATUS_LOGON_FAILURE: 470 case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION: 471 case NtStatus.NT_STATUS_INVALID_LOGON_HOURS: 472 case NtStatus.NT_STATUS_INVALID_WORKSTATION: 473 case NtStatus.NT_STATUS_PASSWORD_EXPIRED: 474 case NtStatus.NT_STATUS_ACCOUNT_DISABLED: 475 case NtStatus.NT_STATUS_ACCOUNT_LOCKED_OUT: 476 case NtStatus.NT_STATUS_TRUSTED_DOMAIN_FAILURE: 477 throw new SmbAuthException( resp.errorCode ); 478 case NtStatus.NT_STATUS_PATH_NOT_COVERED: 479 if( req.auth == null ) { 480 throw new SmbException( resp.errorCode, null ); 481 } 482 DfsReferral dr = getDfsReferral( req.auth, req.path ); 483 referrals.add( dr ); 484 throw dr; 485 case 0x80000005: 486 break; 487 default: 488 throw new SmbException( resp.errorCode, null ); 489 } 490 if (resp.verifyFailed) { 491 throw new SmbException( "Signature verification failed." ); 492 } 493 } 494 void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { 495 496 connect(); 497 498 request.flags2 |= flags2; 499 request.useUnicode = useUnicode; 500 request.response = response; 501 if (request.digest == null) 502 request.digest = digest; 503 504 try { 505 if (response == null) { 506 doSend0( request ); 507 return; 508 } else if (request instanceof SmbComTransaction) { 509 response.command = request.command; 510 SmbComTransaction req = (SmbComTransaction)request; 511 SmbComTransactionResponse resp = (SmbComTransactionResponse)response; 512 513 req.maxBufferSize = snd_buf_size; 514 resp.reset(); 515 516 try { 517 BufferCache.getBuffers( req, resp ); 518 519 522 523 req.nextElement(); 524 if (req.hasMoreElements()) { 525 SmbComBlankResponse interim = new SmbComBlankResponse(); 526 super.sendrecv( req, interim, RESPONSE_TIMEOUT ); 527 if (interim.errorCode != 0) { 528 checkStatus( req, interim ); 529 } 530 req.nextElement(); 531 } else { 532 makeKey( req ); 533 } 534 535 synchronized (response_map) { 536 response.received = false; 537 resp.isReceived = false; 538 try { 539 response_map.put( req, resp ); 540 541 544 545 do { 546 doSend0( req ); 547 } while( req.hasMoreElements() && req.nextElement() != null ); 548 549 552 553 long timeout = RESPONSE_TIMEOUT; 554 resp.expiration = System.currentTimeMillis() + timeout; 555 while( resp.hasMoreElements() ) { 556 response_map.wait( timeout ); 557 timeout = resp.expiration - System.currentTimeMillis(); 558 if (timeout <= 0) { 559 throw new TransportException( this + 560 " timedout waiting for response to " + 561 req ); 562 } 563 } 564 if (response.errorCode != 0) { 565 checkStatus( req, resp ); 566 } 567 } catch( InterruptedException ie ) { 568 throw new TransportException( ie ); 569 } finally { 570 response_map.remove( req ); 571 } 572 } 573 } finally { 574 BufferCache.releaseBuffer( req.txn_buf ); 575 BufferCache.releaseBuffer( resp.txn_buf ); 576 } 577 578 } else { 579 response.command = request.command; 580 super.sendrecv( request, response, RESPONSE_TIMEOUT ); 581 } 582 } catch( SmbException se ) { 583 throw se; 584 } catch( IOException ioe ) { 585 throw new SmbException( "", ioe ); 586 } 587 588 checkStatus( request, response ); 589 } 590 public String toString() { 591 return super.toString() + "[" + address + ":" + port + "]"; 592 } 593 594 595 596 DfsReferral getDfsReferral( NtlmPasswordAuthentication auth, 597 String path ) throws SmbException { 598 String subpath, node, host; 599 DfsReferral dr = new DfsReferral(); 600 int p, n, i, s; 601 UniAddress addr; 602 603 SmbTree ipc = getSmbSession( auth ).getSmbTree( "IPC$", null ); 604 Trans2GetDfsReferralResponse resp = new Trans2GetDfsReferralResponse(); 605 ipc.send( new Trans2GetDfsReferral( path ), resp ); 606 607 subpath = path.substring( 0, resp.pathConsumed ); 608 node = resp.referral.node; 609 if( subpath.charAt( 0 ) != '\\' || 610 (i = subpath.indexOf( '\\', 1 )) < 2 || 611 (p = subpath.indexOf( '\\', i + 1 )) < (i + 2) || 612 node.charAt( 0 ) != '\\' || 613 (s = node.indexOf( '\\', 1 )) < 2) { 614 throw new SmbException( "Invalid DFS path: " + path ); 615 } 616 if ((n = node.indexOf( '\\', s + 1 )) == -1) { 617 n = node.length(); 618 } 619 620 dr.path = subpath.substring( p ); 621 dr.node = node.substring( 0, n ); 622 dr.nodepath = node.substring( n ); 623 dr.server = node.substring( 1, s ); 624 dr.share = node.substring( s + 1, n ); 625 dr.resolveHashes = auth.hashesExternal; 626 628 return dr; 629 } 630 DfsReferral lookupReferral( String unc ) { 631 synchronized( referrals ) { 632 DfsReferral dr; 633 ListIterator iter = referrals.listIterator(); 634 int i, len; 635 636 while( iter.hasNext() ) { 637 dr = (DfsReferral)iter.next(); 638 len = dr.path.length(); 639 for( i = 0; i < len && i < unc.length(); i++ ) { 640 if( dr.path.charAt( i ) != unc.charAt( i )) { 641 break; 642 } 643 } 644 if( i == len && (len == unc.length() || unc.charAt( len ) == '\\')) { 645 return dr; 646 } 647 } 648 } 649 650 return null; 651 } 652 } 653 654 | Popular Tags |