📄 smbtransport.java
字号:
/* jcifs smb client library in Java
* Copyright (C) 2005 "Michael B. Allen" <jcifs at samba dot org>
* "Eric Glass" <jcifs at samba dot org>
*
* 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
*/
package jcifs.smb;
import java.io.*;
import java.net.*;
import java.util.*;
import jcifs.*;
import jcifs.netbios.*;
import jcifs.util.*;
import jcifs.util.transport.*;
public class SmbTransport extends Transport implements SmbConstants {
static final byte[] BUF = new byte[0xFFFF];
static final SmbComNegotiate NEGOTIATE_REQUEST = new SmbComNegotiate();
static LogStream log = LogStream.getInstance();
static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
return getSmbTransport( address, port, LADDR, LPORT );
}
static synchronized SmbTransport getSmbTransport( UniAddress address, int port,
InetAddress localAddr, int localPort ) {
SmbTransport conn;
synchronized( CONNECTIONS ) {
if( SSN_LIMIT != 1 ) {
ListIterator iter = CONNECTIONS.listIterator();
while( iter.hasNext() ) {
conn = (SmbTransport)iter.next();
if( conn.matches( address, port, localAddr, localPort ) &&
( SSN_LIMIT == 0 || conn.sessions.size() < SSN_LIMIT )) {
return conn;
}
}
}
conn = new SmbTransport( address, port, localAddr, localPort );
CONNECTIONS.add( 0, conn );
}
return conn;
}
class ServerData {
byte flags;
int flags2;
int maxMpxCount;
int maxBufferSize;
int sessionKey;
int capabilities;
String oemDomainName;
int securityMode;
int security;
boolean encryptedPasswords;
boolean signaturesEnabled;
boolean signaturesRequired;
int maxNumberVcs;
int maxRawSize;
long serverTime;
int serverTimeZone;
int encryptionKeyLength;
byte[] encryptionKey;
}
InetAddress localAddr;
int localPort;
UniAddress address;
Socket socket;
int port, mid;
OutputStream out;
InputStream in;
byte[] sbuf = new byte[255]; /* small local buffer */
SmbComBlankResponse key = new SmbComBlankResponse();
long sessionExpiration = System.currentTimeMillis() + SO_TIMEOUT;
LinkedList referrals = new LinkedList();
SigningDigest digest = null;
LinkedList sessions = new LinkedList();
ServerData server = new ServerData();
/* Negotiated values */
int flags2 = FLAGS2;
int maxMpxCount = MAX_MPX_COUNT;
int snd_buf_size = SND_BUF_SIZE;
int rcv_buf_size = RCV_BUF_SIZE;
int capabilities = CAPABILITIES;
int sessionKey = 0x00000000;
boolean useUnicode = USE_UNICODE;
String tconHostName;
SmbTransport( UniAddress address, int port, InetAddress localAddr, int localPort ) {
this.address = address;
this.port = port;
this.localAddr = localAddr;
this.localPort = localPort;
}
synchronized SmbSession getSmbSession() {
return getSmbSession( new NtlmPasswordAuthentication( null, null, null ));
}
synchronized SmbSession getSmbSession( NtlmPasswordAuthentication auth ) {
SmbSession ssn;
long now;
ListIterator iter = sessions.listIterator();
while( iter.hasNext() ) {
ssn = (SmbSession)iter.next();
if( ssn.matches( auth )) {
ssn.auth = auth;
return ssn;
}
}
/* logoff old sessions */
if (SO_TIMEOUT > 0 && sessionExpiration < (now = System.currentTimeMillis())) {
sessionExpiration = now + SO_TIMEOUT;
iter = sessions.listIterator();
while( iter.hasNext() ) {
ssn = (SmbSession)iter.next();
if( ssn.expiration < now ) {
ssn.logoff( false );
}
}
}
ssn = new SmbSession( address, port, localAddr, localPort, auth );
ssn.transport = this;
sessions.add( ssn );
return ssn;
}
boolean matches( UniAddress address, int port, InetAddress localAddr, int localPort ) {
return address.equals( this.address ) &&
(port == 0 || port == this.port ||
/* port 139 is ok if 445 was requested */
(port == 445 && this.port == 139)) &&
(localAddr == this.localAddr ||
(localAddr != null &&
localAddr.equals( this.localAddr ))) &&
localPort == this.localPort;
}
boolean hasCapability( int cap ) throws SmbException {
try {
connect( RESPONSE_TIMEOUT );
} catch( IOException ioe ) {
throw new SmbException( "", ioe );
}
return (capabilities & cap) == cap;
}
boolean isSignatureSetupRequired( NtlmPasswordAuthentication auth ) {
return ( flags2 & ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES ) != 0 &&
digest == null &&
auth != NtlmPasswordAuthentication.NULL &&
NtlmPasswordAuthentication.NULL.equals( auth ) == false;
}
void ssn139() throws IOException {
Name calledName = new Name( address.firstCalledName(), 0x20, null );
do {
if (localAddr == null) {
socket = new Socket( address.getHostAddress(), 139 );
} else {
socket = new Socket( address.getHostAddress(), 139, localAddr, localPort );
}
socket.setSoTimeout( SO_TIMEOUT );
out = socket.getOutputStream();
in = socket.getInputStream();
SessionServicePacket ssp = new SessionRequestPacket( calledName,
NbtAddress.getLocalName() );
out.write( sbuf, 0, ssp.writeWireFormat( sbuf, 0 ));
if (readn( in, sbuf, 0, 4 ) < 4) {
throw new SmbException( "EOF during NetBIOS session request" );
}
switch( sbuf[0] & 0xFF ) {
case SessionServicePacket.POSITIVE_SESSION_RESPONSE:
if( log.level > 2 )
log.println( "session established ok with " + address );
return;
case SessionServicePacket.NEGATIVE_SESSION_RESPONSE:
int errorCode = (int)( in.read() & 0xFF );
switch (errorCode) {
case NbtException.CALLED_NOT_PRESENT:
case NbtException.NOT_LISTENING_CALLED:
socket.close();
break;
default:
disconnect( true );
throw new NbtException( NbtException.ERR_SSN_SRVC, errorCode );
}
break;
case -1:
disconnect( true );
throw new NbtException( NbtException.ERR_SSN_SRVC,
NbtException.CONNECTION_REFUSED );
default:
disconnect( true );
throw new NbtException( NbtException.ERR_SSN_SRVC, 0 );
}
} while(( calledName.name = address.nextCalledName()) != null );
throw new IOException( "Failed to establish session with " + address );
}
private void negotiate( int port, ServerMessageBlock resp ) throws IOException {
/* We cannot use Transport.sendrecv() yet because
* the Transport thread is not setup until doConnect()
* returns and we want to supress all communication
* until we have properly negotiated.
*/
synchronized (sbuf) {
/* If jcifs.netbios.hostname is set this *probably* means there
* is a policy regarding which hosts a user can connect from. This
* requires communicating over port 139 rather than 445.
*/
if (NETBIOS_HOSTNAME != null && NETBIOS_HOSTNAME.equals( "" ) == false) {
port = 139;
}
if (port == 139) {
ssn139();
} else {
if (port == 0)
port = DEFAULT_PORT; // 445
if (localAddr == null) {
socket = new Socket( address.getHostAddress(), port );
} else {
socket = new Socket( address.getHostAddress(), port, localAddr, localPort );
}
socket.setSoTimeout( SO_TIMEOUT );
out = socket.getOutputStream();
in = socket.getInputStream();
}
if (++mid == 32000) mid = 1;
NEGOTIATE_REQUEST.mid = mid;
int n = NEGOTIATE_REQUEST.encode( sbuf, 4 );
Encdec.enc_uint32be( n & 0xFFFF, sbuf, 0 ); /* 4 byte ssn msg header */
out.write( sbuf, 0, 4 + n );
out.flush();
/* Note the Transport thread isn't running yet so we can
* read from the socket here.
*/
if (peekKey() == null) /* try to read header */
throw new IOException( "transport closed in negotiate" );
int size = Encdec.dec_uint16be( sbuf, 2 );
if (size < 33 || (4 + size) > sbuf.length ) {
throw new IOException( "Invalid payload size: " + size );
}
readn( in, sbuf, 4 + 32, size - 32 );
resp.decode( sbuf, 4 );
}
}
public void connect() throws SmbException {
try {
super.connect( RESPONSE_TIMEOUT );
} catch( TransportException te ) {
throw new SmbException( "", te );
}
}
protected void doConnect() throws IOException {
/*
* Negotiate Protocol Request / Response
*/
SmbComNegotiateResponse resp = new SmbComNegotiateResponse( server );
try {
negotiate( port, resp );
} catch( ConnectException ce ) {
port = (port == 0 || port == DEFAULT_PORT) ? 139 : DEFAULT_PORT;
negotiate( port, resp );
}
if( resp.dialectIndex > 10 ) {
throw new SmbException( "This client does not support the negotiated dialect." );
}
/* Adjust negotiated values */
tconHostName = address.getHostName();
if (server.signaturesRequired || (server.signaturesEnabled && SIGNPREF)) {
flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
} else {
flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
}
maxMpxCount = Math.min( maxMpxCount, server.maxMpxCount );
if (maxMpxCount < 1) maxMpxCount = 1;
snd_buf_size = Math.min( snd_buf_size, server.maxBufferSize );
capabilities &= server.capabilities;
if ((capabilities & ServerMessageBlock.CAP_UNICODE) == 0) {
// server doesn't want unicode
if (FORCE_UNICODE) {
capabilities |= ServerMessageBlock.CAP_UNICODE;
} else {
useUnicode = false;
flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
}
}
}
protected void doDisconnect( boolean hard ) throws IOException {
ListIterator iter = sessions.listIterator();
while (iter.hasNext()) {
SmbSession ssn = (SmbSession)iter.next();
ssn.logoff( hard );
}
socket.shutdownOutput();
out.close();
in.close();
socket.close();
digest = null;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -