/* jcifs smb client library in Java * Copyright (C) 2000 "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 com.knowgate.jcifs.smb; import com.knowgate.jcifs.netbios.NbtSocket; import com.knowgate.jcifs.netbios.NbtException; import com.knowgate.jcifs.netbios.NbtAddress; import com.knowgate.jcifs.UniAddress; import com.knowgate.jcifs.Config; import com.knowgate.debug.*; import java.io.InputStream; import java.io.OutputStream; import java.io.PushbackInputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.LinkedList; import java.util.ListIterator; import java.util.Enumeration; import java.util.HashMap; class SmbTransport implements Runnable { private static final int DEFAULT_MAX_MPX_COUNT = 10; private static final int DEFAULT_RESPONSE_TIMEOUT = 10000; private static final int DEFAULT_SO_TIMEOUT = 15000; private static final int DEFAULT_RCV_BUF_SIZE = 60416; private static final int DEFAULT_SND_BUF_SIZE = 5000; private static final int DEFAULT_SSN_LIMIT = 250; private static final InetAddress LADDR = Config.getInetAddress( "jcifs.smb.client.laddr", null ); private static final int LPORT = Config.getInt( "jcifs.smb.client.lport", 0 ); private static final int SSN_LIMIT = Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT ); private static final int MAX_MPX_COUNT = Config.getInt( "jcifs.smb.client.maxMpxCount", DEFAULT_MAX_MPX_COUNT ); private static final int SND_BUF_SIZE = Config.getInt( "jcifs.smb.client.snd_buf_size", DEFAULT_SND_BUF_SIZE ); private static final int RCV_BUF_SIZE = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE ); private static final boolean USE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", true ); private static final boolean FORCE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", false ); private static final boolean USE_NTSTATUS = Config.getBoolean( "jcifs.smb.client.useNtStatus", true ); private static final boolean SIGNPREF = Config.getBoolean("jcifs.smb.client.signingPreferred", false ); private static final boolean USE_NTSMBS = Config.getBoolean( "jcifs.smb.client.useNTSmbs", true ); private static final int DEFAULT_FLAGS2 = ServerMessageBlock.FLAGS2_LONG_FILENAMES | ServerMessageBlock.FLAGS2_EXTENDED_ATTRIBUTES | ( SIGNPREF ? ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES : 0 ) | ( USE_NTSTATUS ? ServerMessageBlock.FLAGS2_STATUS32 : 0 ) | ( USE_UNICODE ? ServerMessageBlock.FLAGS2_UNICODE : 0 ); private static final int DEFAULT_CAPABILITIES = ( USE_NTSMBS ? ServerMessageBlock.CAP_NT_SMBS : 0 ) | ( USE_NTSTATUS ? ServerMessageBlock.CAP_STATUS32 : 0 ) | ( USE_UNICODE ? ServerMessageBlock.CAP_UNICODE : 0 ) | ServerMessageBlock.CAP_DFS; private static final int FLAGS2 = Config.getInt( "jcifs.smb.client.flags2", DEFAULT_FLAGS2 ); private static final int CAPABILITIES = Config.getInt( "jcifs.smb.client.capabilities", DEFAULT_CAPABILITIES ); private static final int SO_TIMEOUT = Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT ); private static final boolean TCP_NODELAY = Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false ); private static final int RESPONSE_TIMEOUT = Config.getInt( "jcifs.smb.client.responseTimeout", DEFAULT_RESPONSE_TIMEOUT ); private static final int PUSHBACK_BUF_SIZE = 64; private static final int MID_OFFSET = 30; private static final int FLAGS_RESPONSE = 0x80; private static final int ST_GROUND = 0; private static final int ST_NEGOTIATING = 1; private static final LinkedList CONNECTIONS = new LinkedList(); private static final int MAGIC[] = { 0xFF, 'S', 'M', 'B' }; private static byte[] snd_buf = new byte[0xFFFF]; private static byte[] rcv_buf = new byte[0xFFFF]; private NbtSocket socket; private HashMap responseTable; private InputStream in; private OutputStream out; private int localPort; private InetAddress localAddr; private Thread thread; private Object outLock; private UniAddress address; private int port; private LinkedList sessions; private LinkedList referrals = new LinkedList(); private int state; private Mid[] mids = new Mid[MAX_MPX_COUNT]; private short mid_next; static final String NATIVE_OS = Config.getProperty( "jcifs.smb.client.nativeOs", System.getProperty( "os.name" )); static final String NATIVE_LANMAN = Config.getProperty( "jcifs.smb.client.nativeLanMan", "jCIFS" ); static final int VC_NUMBER = 1; static final SmbTransport NULL_TRANSPORT = new SmbTransport(); class Mid { short mid; public int hashCode() { return mid; } public boolean equals( Object obj ) { return ((Mid)obj).mid == mid; } } class ServerData { byte flags; int flags2; int maxMpxCount; int maxBufferSize; int sessionKey; // NT 4 Workstation is 0x43FD 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; } 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; ServerData server; SigningDigest digest = null; 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; } SmbTransport( UniAddress address, int port, InetAddress localAddr, int localPort ) { this.address = address; this.port = port; this.localAddr = localAddr; this.localPort = localPort; sessions = new LinkedList(); responseTable = new HashMap(); outLock = new Object(); state = ST_GROUND; int i; for( i = 0; i < MAX_MPX_COUNT; i++ ) { mids[i] = new Mid(); } } SmbTransport() { } synchronized SmbSession getSmbSession() { return getSmbSession( new NtlmPasswordAuthentication( null, null, null )); } synchronized SmbSession getSmbSession( NtlmPasswordAuthentication auth ) { SmbSession ssn; ListIterator iter = sessions.listIterator(); while( iter.hasNext() ) { ssn = (SmbSession)iter.next(); if( ssn.matches( auth )) { ssn.auth = auth; return ssn; } } 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 ) { InetAddress defaultLocal = null; try { defaultLocal = InetAddress.getLocalHost(); } catch( UnknownHostException uhe ) { } int p1 = ( port == 0 || port == 139 ) ? 0 : port; int p2 = ( this.port == 0 || this.port == 139 ) ? 0 : this.port; InetAddress la1 = localAddr == null ? defaultLocal : localAddr; InetAddress la2 = this.localAddr == null ? defaultLocal : this.localAddr; return address.equals( this.address ) && p1 == p2 && la1.equals( la2 ) && localPort == this.localPort; } boolean hasCapability( int cap ) throws SmbException { if (state == ST_GROUND) { negotiate(); } 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 ensureOpen() throws IOException { if( socket == null ) { Object obj; NbtAddress naddr; String calledName; obj = address.getAddress(); if( obj instanceof NbtAddress ) { naddr = (NbtAddress)obj; } else { try { naddr = NbtAddress.getByName( ((InetAddress)obj).getHostAddress() ); } catch( UnknownHostException uhe ) { naddr = null; // never happen } } calledName = address.firstCalledName(); do { try { socket = new NbtSocket( naddr, calledName, port, localAddr, localPort ); break; } catch( NbtException ne ) { if( ne.errorClass == NbtException.ERR_SSN_SRVC && ( ne.errorCode == NbtException.CALLED_NOT_PRESENT || ne.errorCode == NbtException.NOT_LISTENING_CALLED )) { if( DebugFile.trace ) new ErrorHandler(ne); } else { throw ne; } } } while(( calledName = address.nextCalledName()) != null ); if( calledName == null ) { throw new IOException( "Failed to establish session with " + address ); } /* Save the calledName for using on SMB_COM_TREE_CONNECT */ if( calledName == NbtAddress.SMBSERVER_NAME ) { tconHostName = address.getHostAddress(); } else { tconHostName = calledName; } if( TCP_NODELAY ) { socket.setTcpNoDelay( true ); } in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE ); out = socket.getOutputStream(); thread = new Thread( this, "JCIFS-SmbTransport" ); thread.setDaemon( true ); thread.start(); } } void tryClose( boolean inError ) { SmbSession ssn; if( socket == null ) { inError = true; } ListIterator iter = sessions.listIterator(); while( iter.hasNext() ) { ssn = (SmbSession)iter.next(); ssn.logoff( inError ); } if( socket != null ) { try { socket.close(); } catch( IOException ioe ) { } } digest = null; in = null; out = null; socket = null; thread = null; responseTable.clear(); referrals.clear(); sessions.clear(); synchronized( CONNECTIONS ) { CONNECTIONS.remove( this ); } state = ST_GROUND; } public void run() { Mid mid = new Mid(); int i, m, nbtlen; ServerMessageBlock response; while( thread == Thread.currentThread() ) { try { socket.setSoTimeout( SO_TIMEOUT ); m = 0; while( m < 4 ) { if(( i = in.read() ) < 0 ) { return; } if(( i & 0xFF ) == MAGIC[m] ) { m++; } else if(( i & 0xFF ) == 0xFF ) { m = 1; } else { m = 0; } } nbtlen = 4 + in.available(); synchronized( rcv_buf ) { rcv_buf[0] = (byte)0xFF; rcv_buf[1] = (byte)'S'; rcv_buf[2] = (byte)'M'; rcv_buf[3] = (byte)'B'; if( in.read( rcv_buf, 4, ServerMessageBlock.HEADER_LENGTH - 4 ) != ( ServerMessageBlock.HEADER_LENGTH - 4 )) { /* Read on a netbios SocketInputStream does not * return until len bytes have been read or the stream is * closed. This must be the latter case. */ break; } ((PushbackInputStream)in).unread( rcv_buf, 0, ServerMessageBlock.HEADER_LENGTH ); if( rcv_buf[0] != (byte)0xFF || rcv_buf[1] != (byte)'S' || rcv_buf[2] != (byte)'M' || rcv_buf[3] != (byte)'B' ) { if( DebugFile.trace ) DebugFile.writeln( "bad smb header, purging session message: " + address ); in.skip( in.available() ); continue; } if(( rcv_buf[ServerMessageBlock.FLAGS_OFFSET] & ServerMessageBlock.FLAGS_RESPONSE ) == ServerMessageBlock.FLAGS_RESPONSE ) { mid.mid = (short)(ServerMessageBlock.readInt2( rcv_buf, MID_OFFSET ) & 0xFFFF); response = (ServerMessageBlock)responseTable.get( mid ); if( response == null ) { if( DebugFile.trace) { DebugFile.writeln( "no handler for mid=" + mid.mid + ", purging session message: " + address ); } in.skip( in.available() ); continue; } synchronized( response ) { response.useUnicode = useUnicode; if( DebugFile.trace ) DebugFile.writeln( "new data read from socket: " + address ); if( response instanceof SmbComTransactionResponse ) { Enumeration e = (Enumeration)response; if( e.hasMoreElements() ) { e.nextElement(); } else { if( DebugFile.trace ) DebugFile.writeln( "more responses to transaction than expected" ); continue; } if((m = response.readWireFormat( in, rcv_buf, 0 )) != nbtlen ) { if( DebugFile.trace ) { DebugFile.writeln( "decoded " + m + " but nbtlen=" + nbtlen + ", purging session message" ); } in.skip( in.available() ); } response.received = true; if( response.errorCode != 0 || e.hasMoreElements() == false ) { ((SmbComTransactionResponse)response).hasMore = false; if( digest != null ) { synchronized( outLock ) { digest.verify(rcv_buf, 0, response); } } response.notify(); } else { ensureOpen(); } } else { response.readWireFormat( in, rcv_buf, 0 ); response.received = true; if( digest != null ) { synchronized( outLock ) { digest.verify(rcv_buf, 0, response); } } response.notify(); } } } else { // it's a request(break oplock) } } } catch( InterruptedIOException iioe ) { if( responseTable.size() == 0 ) { tryClose( false ); } else if( DebugFile.trace ) { DebugFile.writeln( "soTimeout has occured but there are " + responseTable.size() + " pending requests" ); } } catch( IOException ioe ) { synchronized( this ) { tryClose( true ); } if( DebugFile.trace && ioe.getMessage().startsWith( "Connection reset" ) == false ) { DebugFile.writeln( ioe.getMessage() + ": " + address ); new ErrorHandler(ioe); } } } } synchronized 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.sendTransaction( 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; } synchronized DfsReferral lookupReferral( String unc ) { 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; } void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { Mid mid = null; if (state == ST_GROUND) { negotiate(); } request.flags2 |= flags2; request.useUnicode = useUnicode; if( response == null ) { try { synchronized( outLock ) { mid = aquireMid(); request.mid = mid.mid; ensureOpen(); synchronized( snd_buf ) { request.digest = digest; request.response = null; int length = request.writeWireFormat(snd_buf, 4); out.write(snd_buf, 4, length); out.flush(); } } } catch( IOException ioe ) { tryClose( true ); throw new SmbException( "An error occured sending the request.", ioe ); } finally { synchronized( outLock ) { releaseMid( mid ); } } return; } // now for the normal case where response is not null try { synchronized( response ) { synchronized( outLock ) { response.received = false; mid = aquireMid(); request.mid = mid.mid; responseTable.put( mid, response ); ensureOpen(); synchronized( snd_buf ) { if( digest != null ) { request.digest = digest; request.response = response; } int length = request.writeWireFormat(snd_buf, 4); out.write(snd_buf, 4, length); out.flush(); } } // default it 1 so that 0 can be used as forever response.wait( response.responseTimeout == 1 ? RESPONSE_TIMEOUT : response.responseTimeout ); } } catch( InterruptedException ie ) { tryClose( true ); } catch( IOException ioe ) { tryClose( true ); throw new SmbException( "An error occured sending the request.", ioe ); } finally { synchronized( outLock ) { responseTable.remove( mid ); releaseMid( mid ); } } if( response.received == false ) { tryClose( true ); throw new SmbException( "Timeout waiting for response from server: " + address ); } else if( response.verifyFailed ) { tryClose( true ); throw new SmbException( "Unverifiable signature: " + address ); } response.errorCode = SmbException.getStatusByCode( response.errorCode ); switch( response.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: throw new SmbAuthException( response.errorCode ); case NtStatus.NT_STATUS_PATH_NOT_COVERED: if( request.auth == null ) { throw new SmbException( response.errorCode, null ); } DfsReferral dr = getDfsReferral( request.auth, request.path ); referrals.add( dr ); throw dr; default: throw new SmbException( response.errorCode, null ); } } void sendTransaction( SmbComTransaction request, SmbComTransactionResponse response ) throws SmbException { Mid mid = null; negotiate(); request.flags2 |= flags2; request.useUnicode = useUnicode; request.maxBufferSize = snd_buf_size; response.received = false; response.hasMore = true; response.isPrimary = true; try { request.txn_buf = BufferCache.getBuffer(); response.txn_buf = BufferCache.getBuffer(); request.nextElement(); if( request.hasMoreElements() ) { // multi-part request SmbComBlankResponse interimResponse = new SmbComBlankResponse(); synchronized( interimResponse ) { synchronized( outLock ) { mid = aquireMid(); request.mid = mid.mid; responseTable.put( mid, interimResponse ); ensureOpen(); synchronized(snd_buf) { request.digest = digest; request.response = response; int length = request.writeWireFormat(snd_buf, 4); out.write(snd_buf, 4, length); out.flush(); } } interimResponse.wait( RESPONSE_TIMEOUT ); if( interimResponse.received == false ) { throw new SmbException( "Timeout waiting for response from server: " + address ); } interimResponse.errorCode = SmbException.getStatusByCode( interimResponse.errorCode ); switch( interimResponse.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: throw new SmbAuthException( interimResponse.errorCode ); case NtStatus.NT_STATUS_PATH_NOT_COVERED: if( request.auth == null ) { throw new SmbException( interimResponse.errorCode, null ); } DfsReferral dr = getDfsReferral( request.auth, request.path ); referrals.add( dr ); throw dr; default: throw new SmbException( interimResponse.errorCode, null ); } } request.nextElement(); } synchronized( response ) { synchronized( outLock ) { mid = aquireMid(); request.mid = mid.mid; responseTable.put( mid, response ); } do { synchronized( outLock ) { ensureOpen(); synchronized( snd_buf ) { request.digest = digest; request.response = response; int length = request.writeWireFormat(snd_buf, 4); out.write(snd_buf, 4, length); out.flush(); } } } while( request.hasMoreElements() && request.nextElement() != null ); do { // default it 1 so that 0 can be used as forever response.received = false; response.wait( response.responseTimeout == 1 ? RESPONSE_TIMEOUT : response.responseTimeout ); } while( response.received && response.hasMoreElements() ); } } catch( InterruptedException ie ) { tryClose( true ); } catch( IOException ioe ) { tryClose( true ); throw new SmbException( "An error occured sending the request.", ioe ); } finally { synchronized( outLock ) { responseTable.remove( mid ); releaseMid( mid ); } BufferCache.releaseBuffer( request.txn_buf ); BufferCache.releaseBuffer( response.txn_buf ); } if( response.received == false ) { tryClose( true ); throw new SmbException( "Timeout waiting for response from server: " + address ); } else if( response.verifyFailed ) { tryClose( true ); throw new SmbException( "Unverifiable signature: " + address ); } response.errorCode = SmbException.getStatusByCode( response.errorCode ); switch( response.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: throw new SmbAuthException( response.errorCode ); case NtStatus.NT_STATUS_PATH_NOT_COVERED: if( request.auth == null ) { throw new SmbException( response.errorCode, null ); } DfsReferral dr = getDfsReferral( request.auth, request.path ); referrals.add( dr ); throw dr; default: throw new SmbException( response.errorCode, null ); } } synchronized void negotiate() throws SmbException { if( this == NULL_TRANSPORT ) { throw new RuntimeException( "Null transport cannot be used" ); } if( state >= ST_NEGOTIATING ) { return; } state = ST_NEGOTIATING; if( DebugFile.trace ) DebugFile.writeln( "requesting negotiation with " + address ); /* * Negotiate Protocol Request / Response */ SmbComNegotiateResponse response = new SmbComNegotiateResponse(); send( new SmbComNegotiate(), response ); if( response.dialectIndex > 10 ) { tryClose( true ); throw new SmbException( "This client does not support the negotiated dialect." ); } server = new ServerData(); server.securityMode = response.securityMode; server.security = response.security; server.encryptedPasswords = response.encryptedPasswords; server.signaturesEnabled = response.signaturesEnabled; server.signaturesRequired = response.signaturesRequired; server.maxMpxCount = response.maxMpxCount; server.maxNumberVcs = response.maxNumberVcs; server.maxBufferSize = response.maxBufferSize; server.maxRawSize = response.maxRawSize; server.sessionKey = response.sessionKey; server.capabilities = response.capabilities; server.serverTime = response.serverTime; server.serverTimeZone = response.serverTimeZone; server.encryptionKeyLength = response.encryptionKeyLength; server.encryptionKey = response.encryptionKey; server.oemDomainName = response.oemDomainName; if (server.signaturesRequired || (server.signaturesEnabled && SIGNPREF)) { flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES; } else { flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES; } maxMpxCount = maxMpxCount < server.maxMpxCount ? maxMpxCount : server.maxMpxCount; maxMpxCount = maxMpxCount < 1 ? 1 : maxMpxCount; snd_buf_size = snd_buf_size < server.maxBufferSize ? 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; } } } public String toString() { String ret = "SmbTransport[address=" + address; if( socket == null ) { ret += ",port=,localAddr=,localPort=]"; } else { ret += ",port=" + socket.getPort() + ",localAddr=" + socket.getLocalAddress() + ",localPort=" + socket.getLocalPort() + "]"; } return ret; } /* Manage MIDs */ Mid aquireMid() throws SmbException { int i; if( mid_next == 0 ) { mid_next++; } for( ;; ) { for( i = 0; i < maxMpxCount; i++ ) { if( mids[i].mid == 0 ) { break; } } if( i == maxMpxCount ) { try { outLock.wait(); } catch( InterruptedException ie ) { throw new SmbException( "Interrupted aquiring mid", ie ); } } else { break; } } mids[i].mid = mid_next++; return mids[i]; } void releaseMid( Mid mid ) { int i; for( i = 0; i < maxMpxCount; i++ ) { if( mids[i].mid == mid.mid ) { mid.mid = 0; outLock.notify(); return; } } if( DebugFile.trace ) DebugFile.writeln( "mid not found" ); } }