From e2d55eb69955c79cdb440a5be54feb4b59ad81dd Mon Sep 17 00:00:00 2001 From: Felix Schumacher Date: Wed, 6 Aug 2008 16:34:10 +0200 Subject: [PATCH] jcifs-1.2.5 from tgz Fri Sep 30 23:28:51 EDT 2005 jcifs-1.2.5 released / Filter Exceptions, Stressing the Transport Layer, and DFS Deadlock Fixed This release of the JCIFS client consists of the following changes. o It was discovered that a flaw in session expiration could cause sessions to expire prematurely. This has been repaired. o If the jcifs.netbios.hostname property is set, the client will communicate using only NetBIOS over port 139. This is required for environments that implement a policy restricting users to logging in from certain computers. o Under stress the client could incorrectly attempt to use the invalid "NULL" transport. This has been fixed. o Filter users could experience exceptions due to using the port 0 rather than the default CIFS port. o The client should now handle partial reads and socket exceptions more gracefully. o Under stress, the DFS referral query could cause the client to deadlock. This has been fixed. --- README.txt | 21 +++++++++++ build.xml | 4 +-- examples/CrawlTest.java | 64 +++++++++++++++++++++++++++++++++ examples/ListDC.java | 18 ---------- src/jcifs/smb/SmbConstants.java | 2 ++ src/jcifs/smb/SmbSession.java | 53 +++++++++++++-------------- src/jcifs/smb/SmbTransport.java | 56 +++++++++++++++++------------ src/jcifs/util/transport/Transport.java | 3 +- 8 files changed, 148 insertions(+), 73 deletions(-) create mode 100644 examples/CrawlTest.java delete mode 100644 examples/ListDC.java diff --git a/README.txt b/README.txt index afe8479..4e90ab2 100644 --- a/README.txt +++ b/README.txt @@ -1,3 +1,24 @@ +Fri Sep 30 23:28:51 EDT 2005 +jcifs-1.2.5 released / Filter Exceptions, Stressing the Transport Layer, + and DFS Deadlock Fixed + +This release of the JCIFS client consists of the following changes. + +o It was discovered that a flaw in session expiration could cause sessions + to expire prematurely. This has been repaired. +o If the jcifs.netbios.hostname property is set, the client will + communicate using only NetBIOS over port 139. This is required for + environments that implement a policy restricting users to logging in from + certain computers. +o Under stress the client could incorrectly attempt to use the invalid + "NULL" transport. This has been fixed. +o Filter users could experience exceptions due to using the port 0 rather + than the default CIFS port. +o The client should now handle partial reads and socket exceptions more + gracefully. +o Under stress, the DFS referral query could cause the client to deadlock. + This has been fixed. + Wed Sep 21 01:53:28 EDT 2005 jcifs-1.2.4 released / Timeout Transport Exception, Bogus Signature Error, and More diff --git a/build.xml b/build.xml index a883a90..4817199 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - - + + diff --git a/examples/CrawlTest.java b/examples/CrawlTest.java new file mode 100644 index 0000000..fdebe95 --- /dev/null +++ b/examples/CrawlTest.java @@ -0,0 +1,64 @@ +import jcifs.smb.SmbFile; +import java.util.LinkedList; +import java.util.ListIterator; +import java.net.MalformedURLException; +import java.io.IOException; + +public class CrawlTest extends Thread { + + SmbFile f; + int maxDepth; + + CrawlTest( SmbFile f, int maxDepth ) { + this.f = f; + this.maxDepth = maxDepth; + } + + void traverse( SmbFile f, int depth ) throws MalformedURLException, IOException { + + if( depth == 0 ) { + return; + } + + SmbFile[] l = f.listFiles(); + + for(int i = 0; l != null && i < l.length; i++ ) { + try { + for( int j = maxDepth - depth; j > 0; j-- ) { + System.out.print( " " ); + } + System.out.println( l[i] + " " + l[i].exists() ); + if( l[i].isDirectory() ) { + traverse( l[i], depth - 1 ); + } + } catch( IOException ioe ) { + System.out.println( l[i] + ":" ); + ioe.printStackTrace( System.out ); + } + } + } + + public void run() { + try { + traverse( f, maxDepth ); + } catch( Exception ex ) { + ex.printStackTrace(); + } + } + + public static void main(String[] argv) throws Exception { + if (argv.length < 3) { + System.err.println( "CrawlTest " ); + return; + } + + SmbFile f = new SmbFile( argv[0] ); + int numThreads = Integer.parseInt( argv[1] ); + int maxDepth = Integer.parseInt( argv[2] ); + + while (numThreads-- > 0 && System.in.read() == '\n') { + CrawlTest sc = new CrawlTest( f, maxDepth ); + sc.start(); + } + } +} diff --git a/examples/ListDC.java b/examples/ListDC.java deleted file mode 100644 index 4a1cda4..0000000 --- a/examples/ListDC.java +++ /dev/null @@ -1,18 +0,0 @@ -import jcifs.netbios.NbtAddress; -import jcifs.*; -import jcifs.smb.*; - -public class CheckAllDC { - - public static void main( String argv[] ) throws Exception { - - NbtAddress[] addrs = NbtAddress.getAllByName( argv[0], 0x1C, null, null ); - - for( int i = 0; i < addrs.length; i++ ) { - System.out.println( addrs[i] ); - UniAddress dc = new UniAddress( addrs[i] ); - NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication( argv[1] ); - SmbSession.logon( dc, auth ); - } - } -} diff --git a/src/jcifs/smb/SmbConstants.java b/src/jcifs/smb/SmbConstants.java index b545a5b..9429cea 100644 --- a/src/jcifs/smb/SmbConstants.java +++ b/src/jcifs/smb/SmbConstants.java @@ -28,6 +28,8 @@ interface SmbConstants { static final boolean USE_NTSMBS = Config.getBoolean( "jcifs.smb.client.useNTSmbs", true ); static final boolean USE_EXTSEC = Config.getBoolean( "jcifs.smb.client.useExtendedSecurity", false ); + static final String NETBIOS_HOSTNAME = Config.getProperty( "jcifs.netbios.hostname", null ); + static final int FLAGS_NONE = 0x00; static final int FLAGS_LOCK_AND_READ_WRITE_AND_UNLOCK = 0x01; static final int FLAGS_RECEIVE_BUFFER_POSTED = 0x02; diff --git a/src/jcifs/smb/SmbSession.java b/src/jcifs/smb/SmbSession.java index 37e6b0b..b565b19 100644 --- a/src/jcifs/smb/SmbSession.java +++ b/src/jcifs/smb/SmbSession.java @@ -174,7 +174,7 @@ public final class SmbSession { private int port, localPort; private InetAddress localAddr; - SmbTransport transport = SmbTransport.NULL_TRANSPORT; + SmbTransport transport = null; NtlmPasswordAuthentication auth; long expiration; @@ -208,8 +208,8 @@ public final class SmbSession { boolean matches( NtlmPasswordAuthentication auth ) { return this.auth == auth || this.auth.equals( auth ); } - synchronized SmbTransport transport() throws SmbException { - if( transport == SmbTransport.NULL_TRANSPORT ) { + synchronized SmbTransport transport() { + if( transport == null ) { transport = SmbTransport.getSmbTransport( address, port, localAddr, localPort ); } return transport; @@ -219,13 +219,14 @@ public final class SmbSession { if( response != null ) { response.received = false; } + expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT; sessionSetup( request, response ); if( response != null && response.received ) { return; } request.uid = uid; request.auth = auth; - transport().send( request, response ); + transport.send( request, response ); } void sessionSetup( ServerMessageBlock andx, ServerMessageBlock andxResponse ) throws SmbException { @@ -234,8 +235,6 @@ synchronized( transport() ) { return; } - expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT; - transport.connect(); /* @@ -279,35 +278,31 @@ synchronized( transport() ) { } } void logoff( boolean inError ) { -synchronized( transport ) { - try { - if( sessionSetup == false ) { - return; - } +synchronized( transport() ) { + if( sessionSetup == false ) { + return; + } - for( Enumeration e = trees.elements(); e.hasMoreElements(); ) { - SmbTree t = (SmbTree)e.nextElement(); - t.treeDisconnect( inError ); - } + for( Enumeration e = trees.elements(); e.hasMoreElements(); ) { + SmbTree t = (SmbTree)e.nextElement(); + t.treeDisconnect( inError ); + } - if( !inError && transport.server.security != ServerMessageBlock.SECURITY_SHARE ) { + if( !inError && transport.server.security != ServerMessageBlock.SECURITY_SHARE ) { - /* - * Logoff And X Request / Response - */ + /* + * Logoff And X Request / Response + */ - SmbComLogoffAndX request = new SmbComLogoffAndX( null ); - request.uid = uid; - try { - transport.send( request, null ); - } catch( SmbException se ) { - } + SmbComLogoffAndX request = new SmbComLogoffAndX( null ); + request.uid = uid; + try { + transport.send( request, null ); + } catch( SmbException se ) { } - - sessionSetup = false; - } finally { - transport = SmbTransport.NULL_TRANSPORT; } + + sessionSetup = false; } } public String toString() { diff --git a/src/jcifs/smb/SmbTransport.java b/src/jcifs/smb/SmbTransport.java index adc4231..28fe58e 100644 --- a/src/jcifs/smb/SmbTransport.java +++ b/src/jcifs/smb/SmbTransport.java @@ -148,10 +148,8 @@ public class SmbTransport extends Transport implements SmbConstants { return ssn; } boolean matches( UniAddress address, int port, InetAddress localAddr, int localPort ) { - int p1 = ( port == 0 || port == DEFAULT_PORT ) ? 0 : port; - int p2 = ( this.port == 0 || this.port == DEFAULT_PORT ) ? 0 : this.port; return address.equals( this.address ) && - p1 == p2 && + (port == 0 || port == this.port) && (localAddr == this.localAddr || (localAddr != null && localAddr.equals( this.localAddr ))) && @@ -226,9 +224,18 @@ public class SmbTransport extends Transport implements SmbConstants { * 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 { @@ -248,7 +255,8 @@ public class SmbTransport extends Transport implements SmbConstants { /* Note the Transport thread isn't running yet so we can * read from the socket here. */ - peekKey(); /* try to read header */ + 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 ); @@ -273,7 +281,7 @@ public class SmbTransport extends Transport implements SmbConstants { try { negotiate( port, resp ); } catch( ConnectException ce ) { - port = port == 445 ? 139 : 445; + port = (port == 0 || port == DEFAULT_PORT) ? 139 : DEFAULT_PORT; negotiate( port, resp ); } @@ -325,12 +333,12 @@ public class SmbTransport extends Transport implements SmbConstants { protected Request peekKey() throws IOException { int n; do { - n = readn( in, sbuf, 0, 4 ); + 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; /* stream closed */ - } + 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 ); @@ -585,7 +593,7 @@ public class SmbTransport extends Transport implements SmbConstants { /* DFS */ - synchronized DfsReferral getDfsReferral( NtlmPasswordAuthentication auth, + DfsReferral getDfsReferral( NtlmPasswordAuthentication auth, String path ) throws SmbException { String subpath, node, host; DfsReferral dr = new DfsReferral(); @@ -619,21 +627,23 @@ public class SmbTransport extends Transport implements SmbConstants { * with challenge from 'server' to access DFS vol. */ return dr; } - synchronized DfsReferral lookupReferral( String unc ) { - DfsReferral dr; - ListIterator iter = referrals.listIterator(); - int i, len; + 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; + 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; } - } - if( i == len && (len == unc.length() || unc.charAt( len ) == '\\')) { - return dr; } } diff --git a/src/jcifs/util/transport/Transport.java b/src/jcifs/util/transport/Transport.java index 8f262d1..31408d4 100644 --- a/src/jcifs/util/transport/Transport.java +++ b/src/jcifs/util/transport/Transport.java @@ -96,7 +96,8 @@ public abstract class Transport implements Runnable { while( thread == Thread.currentThread() ) { try { Request key = peekKey(); - if (key == null) return; + if (key == null) + throw new IOException( "end of stream" ); synchronized (response_map) { Response response = (Response)response_map.get( key ); if (response == null) { -- 2.11.0