📄 smbtransport.java
字号:
protected void makeKey( Request request ) throws IOException {
/* The request *is* the key */
if (++mid == 32000) mid = 1;
((ServerMessageBlock)request).mid = mid;
}
protected Request peekKey() throws IOException {
int n;
do {
if ((n = readn( in, sbuf, 0, 4 )) < 4)
return null;
} while (sbuf[0] == (byte)0x85); /* Dodge NetBIOS keep-alive */
/* read smb header */
if ((n = readn( in, sbuf, 4, 32 )) < 32)
return null;
if (log.level > 2) {
log.println( "New data read: " + this );
jcifs.util.Hexdump.hexdump( log, sbuf, 4, 32 );
}
for ( ;; ) {
/* 01234567
* 00SSFSMB
* 0 - 0's
* S - size of payload
* FSMB - 0xFF SMB magic #
*/
if (sbuf[0] == (byte)0x00 &&
sbuf[1] == (byte)0x00 &&
sbuf[4] == (byte)0xFF &&
sbuf[5] == (byte)'S' &&
sbuf[6] == (byte)'M' &&
sbuf[7] == (byte)'B') {
break; /* all good */
}
/* out of phase maybe? */
/* inch forward 1 byte and try again */
for (int i = 0; i < 35; i++) {
sbuf[i] = sbuf[i + 1];
}
int b;
if ((b = in.read()) == -1) return null;
sbuf[35] = (byte)b;
}
key.mid = Encdec.dec_uint16le( sbuf, 34 );
/* Unless key returned is null or invalid Transport.loop() always
* calls doRecv() after and no one else but the transport thread
* should call doRecv(). Therefore it is ok to expect that the data
* in sbuf will be preserved for copying into BUF in doRecv().
*/
return key;
}
protected void doSend( Request request ) throws IOException {
synchronized (BUF) {
ServerMessageBlock smb = (ServerMessageBlock)request;
int n = smb.encode( BUF, 4 );
Encdec.enc_uint32be( n & 0xFFFF, BUF, 0 ); /* 4 byte session message header */
if (log.level > 3) {
do {
log.println( smb );
} while (smb instanceof AndXServerMessageBlock &&
(smb = ((AndXServerMessageBlock)smb).andx) != null);
if (log.level > 5) {
Hexdump.hexdump( log, BUF, 4, n );
}
}
out.write( BUF, 0, 4 + n );
}
}
protected void doSend0( Request request ) throws IOException {
try {
doSend( request );
} catch( IOException ioe ) {
if (log.level > 2)
ioe.printStackTrace( log );
try {
disconnect( true );
} catch( IOException ioe2 ) {
ioe2.printStackTrace( log );
}
throw ioe;
}
}
protected void doRecv( Response response ) throws IOException {
ServerMessageBlock resp = (ServerMessageBlock)response;
resp.useUnicode = useUnicode;
synchronized (BUF) {
System.arraycopy( sbuf, 0, BUF, 0, 4 + HEADER_LENGTH );
int size = Encdec.dec_uint16be( BUF, 2 );
if (size < (HEADER_LENGTH + 1) || (4 + size) > rcv_buf_size ) {
throw new IOException( "Invalid payload size: " + size );
}
if (resp.command == ServerMessageBlock.SMB_COM_READ_ANDX) {
SmbComReadAndXResponse r = (SmbComReadAndXResponse)resp;
int off = HEADER_LENGTH;
/* WordCount thru dataOffset always 27 */
readn( in, BUF, 4 + off, 27 ); off += 27;
resp.decode( BUF, 4 );
if (r.dataLength > 0) {
readn( in, BUF, 4 + off, r.dataOffset - off); /* pad */
readn( in, r.b, r.off, r.dataLength ); /* read direct */
}
} else {
readn( in, BUF, 4 + 32, size - 32 );
resp.decode( BUF, 4 );
if (resp instanceof SmbComTransactionResponse) {
((SmbComTransactionResponse)resp).nextElement();
}
}
/* Verification fails (w/ W2K3 server at least) if status is not 0. This
* suggests MS doesn't compute the signature (correctly) for error responses
* (perhaps for DOS reasons).
*/
if (digest != null && resp.errorCode == 0) {
digest.verify( BUF, 4, resp );
}
}
}
protected void doSkip() throws IOException {
int size = Encdec.dec_uint16be( sbuf, 2 );
if (size < 33 || (4 + size) > rcv_buf_size ) {
/* log message? */
in.skip( in.available() );
} else {
in.skip( size - 32 );
}
}
void checkStatus( ServerMessageBlock req, ServerMessageBlock resp ) throws SmbException {
resp.errorCode = SmbException.getStatusByCode( resp.errorCode );
switch( resp.errorCode ) {
case NtStatus.NT_STATUS_OK:
break;
case NtStatus.NT_STATUS_ACCESS_DENIED:
case NtStatus.NT_STATUS_WRONG_PASSWORD:
case NtStatus.NT_STATUS_LOGON_FAILURE:
case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION:
case NtStatus.NT_STATUS_INVALID_LOGON_HOURS:
case NtStatus.NT_STATUS_INVALID_WORKSTATION:
case NtStatus.NT_STATUS_PASSWORD_EXPIRED:
case NtStatus.NT_STATUS_ACCOUNT_DISABLED:
case NtStatus.NT_STATUS_ACCOUNT_LOCKED_OUT:
case NtStatus.NT_STATUS_TRUSTED_DOMAIN_FAILURE:
throw new SmbAuthException( resp.errorCode );
case NtStatus.NT_STATUS_PATH_NOT_COVERED:
if( req.auth == null ) {
throw new SmbException( resp.errorCode, null );
}
DfsReferral dr = getDfsReferral( req.auth, req.path );
referrals.add( dr );
throw dr;
case 0x80000005: /* STATUS_BUFFER_OVERFLOW */
break; /* normal for DCERPC named pipes */
default:
throw new SmbException( resp.errorCode, null );
}
if (resp.verifyFailed) {
throw new SmbException( "Signature verification failed." );
}
}
void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException {
connect(); /* must negotiate before we can test flags2, useUnicode, etc */
request.flags2 |= flags2;
request.useUnicode = useUnicode;
request.response = response; /* needed by sign */
if (request.digest == null)
request.digest = digest; /* for sign called in encode */
try {
if (response == null) {
doSend0( request );
return;
} else if (request instanceof SmbComTransaction) {
response.command = request.command;
SmbComTransaction req = (SmbComTransaction)request;
SmbComTransactionResponse resp = (SmbComTransactionResponse)response;
req.maxBufferSize = snd_buf_size;
resp.reset();
try {
BufferCache.getBuffers( req, resp );
/*
* First request w/ interim response
*/
req.nextElement();
if (req.hasMoreElements()) {
SmbComBlankResponse interim = new SmbComBlankResponse();
super.sendrecv( req, interim, RESPONSE_TIMEOUT );
if (interim.errorCode != 0) {
checkStatus( req, interim );
}
req.nextElement();
} else {
makeKey( req );
}
synchronized (response_map) {
response.received = false;
resp.isReceived = false;
try {
response_map.put( req, resp );
/*
* Send multiple fragments
*/
do {
doSend0( req );
} while( req.hasMoreElements() && req.nextElement() != null );
/*
* Receive multiple fragments
*/
long timeout = RESPONSE_TIMEOUT;
resp.expiration = System.currentTimeMillis() + timeout;
while( resp.hasMoreElements() ) {
response_map.wait( timeout );
timeout = resp.expiration - System.currentTimeMillis();
if (timeout <= 0) {
throw new TransportException( this +
" timedout waiting for response to " +
req );
}
}
if (response.errorCode != 0) {
checkStatus( req, resp );
}
} catch( InterruptedException ie ) {
throw new TransportException( ie );
} finally {
response_map.remove( req );
}
}
} finally {
BufferCache.releaseBuffer( req.txn_buf );
BufferCache.releaseBuffer( resp.txn_buf );
}
} else {
response.command = request.command;
super.sendrecv( request, response, RESPONSE_TIMEOUT );
}
} catch( SmbException se ) {
throw se;
} catch( IOException ioe ) {
throw new SmbException( "", ioe );
}
checkStatus( request, response );
}
public String toString() {
return super.toString() + "[" + address + ":" + port + "]";
}
/* DFS */
DfsReferral getDfsReferral( NtlmPasswordAuthentication auth,
String path ) throws SmbException {
String subpath, node, host;
DfsReferral dr = new DfsReferral();
int p, n, i, s;
UniAddress addr;
SmbTree ipc = getSmbSession( auth ).getSmbTree( "IPC$", null );
Trans2GetDfsReferralResponse resp = new Trans2GetDfsReferralResponse();
ipc.send( new Trans2GetDfsReferral( path ), resp );
subpath = path.substring( 0, resp.pathConsumed );
node = resp.referral.node;
if( subpath.charAt( 0 ) != '\\' ||
(i = subpath.indexOf( '\\', 1 )) < 2 ||
(p = subpath.indexOf( '\\', i + 1 )) < (i + 2) ||
node.charAt( 0 ) != '\\' ||
(s = node.indexOf( '\\', 1 )) < 2) {
throw new SmbException( "Invalid DFS path: " + path );
}
if ((n = node.indexOf( '\\', s + 1 )) == -1) {
n = node.length();
}
dr.path = subpath.substring( p );
dr.node = node.substring( 0, n );
dr.nodepath = node.substring( n );
dr.server = node.substring( 1, s );
dr.share = node.substring( s + 1, n );
dr.resolveHashes = auth.hashesExternal;
/* NTLM HTTP Authentication must be re-negotiated
* with challenge from 'server' to access DFS vol. */
return dr;
}
DfsReferral lookupReferral( String unc ) {
synchronized( referrals ) {
DfsReferral dr;
ListIterator iter = referrals.listIterator();
int i, len;
while( iter.hasNext() ) {
dr = (DfsReferral)iter.next();
len = dr.path.length();
for( i = 0; i < len && i < unc.length(); i++ ) {
if( dr.path.charAt( i ) != unc.charAt( i )) {
break;
}
}
if( i == len && (len == unc.length() || unc.charAt( len ) == '\\')) {
return dr;
}
}
}
return null;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -