From 21c48fe7dde5c68b2c06cc0b159e0160f503d2d3 Mon Sep 17 00:00:00 2001 From: Felix Schumacher Date: Wed, 6 Aug 2008 16:32:10 +0200 Subject: [PATCH] jcifs-1.2.0 from tgz Sun May 22 18:22:32 EDT 2005 jcifs-1.2.0 released This release is jcifs-1.1.11trans2 with the following modifications. Named pipes were broken when DCE transactions where added with 1.x. Call, Transact, CreateFile, and DCE named pipe calls should now all work as expected. The NetBIOS name resolution code will now use the last resource record of a name query response if there are more than one. This appears to be more correct in at least one instance (VMWare adapters on my workstation at work are appearing first). Also note the trans releases below. Mon May 9 18:49:24 EDT 2005 jcifs-1.1.11trans2 released Socket exception handling was non-existant and reads would actually not read anything but 0's. These issues and other small issues have been fixed. Wed May 4 22:31:28 EDT 2005 jcifs-1.1.11trans released This "transitional" release has all the 1.1.10 and 1.1.11 fixes as well as more work on the transport layer. The last trans release had a silly mid rollover bug. I have also emiminated a deadlock condition. These issues have been fixed. Also the client will not properly try port 445 and fallback to 139 as necessary. This *could* be stable enough that I might try to promote this to 1.2.0. Thu Apr 7 23:02:48 EDT 2005 jcifs-1.1.9trans released This is a 'transitional' or 'transport rewrite' release. It's stock 1.1.9 but the transport layer has been refactored and reduced (actually totally rewritten - SmbTransport.java is less than half the size of it's previous version). It may still not be "correct" because I believe the high-load concurrency issue may have to do with how sessions and trees are created. That is another step that delves into how Principles will be handled so I thought I would release this as is because it seems pretty stable so I thought I would put it out there as a reference point. To give people an insentive to actually use it I have changed the port to 445, applied the share reconnect fix from Darren and the getDiskFreeSpace patch from Thomas. Also if you really need the dial to go to 11, preliminary testing indicates this transport is a few percent faster. --- README.txt | 75 +- build.xml | 4 +- examples/SmbCrawler.java | 3 +- examples/T2Crawler.java | 40 +- src/jcifs/Config.java | 16 + src/jcifs/http/NetworkExplorer.java | 25 +- src/jcifs/http/NtlmHttpFilter.java | 66 +- src/jcifs/netbios/.NbtSocket.java.swp | Bin 16384 -> 0 bytes src/jcifs/netbios/.SessionServicePacket.java.swp | Bin 20480 -> 0 bytes src/jcifs/netbios/Name.java | 8 +- src/jcifs/netbios/NameServiceClient.java | 5 +- src/jcifs/netbios/NbtAddress.java | 12 +- src/jcifs/netbios/SessionRequestPacket.java | 4 +- src/jcifs/netbios/SessionServicePacket.java | 8 +- src/jcifs/smb/AndXServerMessageBlock.java | 147 +-- src/jcifs/smb/BufferCache.java | 50 +- src/jcifs/smb/Handler.java | 2 +- src/jcifs/smb/NtStatus.java | 9 + src/jcifs/smb/NtlmChallenge.java | 2 +- src/jcifs/smb/ServerMessageBlock.java | 191 +--- src/jcifs/smb/SmbComLogoffAndX.java | 7 - src/jcifs/smb/SmbComNTCreateAndX.java | 6 - src/jcifs/smb/SmbComNTCreateAndXResponse.java | 6 - src/jcifs/smb/SmbComNegotiate.java | 1 + src/jcifs/smb/SmbComNegotiateResponse.java | 149 ++- src/jcifs/smb/SmbComOpenAndX.java | 6 - src/jcifs/smb/SmbComOpenAndXResponse.java | 4 - src/jcifs/smb/SmbComReadAndX.java | 6 - src/jcifs/smb/SmbComReadAndXResponse.java | 15 +- src/jcifs/smb/SmbComSessionSetupAndX.java | 6 - src/jcifs/smb/SmbComSessionSetupAndXResponse.java | 9 - src/jcifs/smb/SmbComTransactionResponse.java | 8 +- src/jcifs/smb/SmbComTreeConnectAndX.java | 6 - src/jcifs/smb/SmbComTreeConnectAndXResponse.java | 6 - src/jcifs/smb/SmbComWrite.java | 5 - src/jcifs/smb/SmbComWriteAndX.java | 6 - src/jcifs/smb/SmbComWriteAndXResponse.java | 7 - src/jcifs/smb/SmbComWriteResponse.java | 6 - src/jcifs/smb/SmbConstants.java | 137 +++ src/jcifs/smb/SmbFile.java | 95 +- src/jcifs/smb/SmbFileInputStream.java | 8 +- src/jcifs/smb/SmbFileOutputStream.java | 5 +- src/jcifs/smb/SmbSession.java | 27 +- src/jcifs/smb/SmbTransport.java | 1192 +++++++------------- src/jcifs/smb/SmbTree.java | 74 +- .../smb/Trans2QueryFSInformationResponse.java | 41 +- src/jcifs/smb/TransactNamedPipeInputStream.java | 5 +- src/jcifs/smb/TransactNamedPipeOutputStream.java | 6 +- src/jcifs/util/transport/Request.java | 4 + src/jcifs/util/transport/Response.java | 6 + src/jcifs/util/transport/Transport.java | 235 ++++ src/jcifs/util/transport/TransportException.java | 38 + 52 files changed, 1274 insertions(+), 1525 deletions(-) delete mode 100644 src/jcifs/netbios/.NbtSocket.java.swp delete mode 100644 src/jcifs/netbios/.SessionServicePacket.java.swp create mode 100644 src/jcifs/smb/SmbConstants.java create mode 100644 src/jcifs/util/transport/Request.java create mode 100644 src/jcifs/util/transport/Response.java create mode 100644 src/jcifs/util/transport/Transport.java create mode 100644 src/jcifs/util/transport/TransportException.java diff --git a/README.txt b/README.txt index e4435f7..9f49463 100644 --- a/README.txt +++ b/README.txt @@ -1,24 +1,57 @@ -Wed May 4 22:59:32 EDT 2005 -jcifs-1.1.11 released - -If a file is opened with SmbFileOutputStream, written to, and then the -client waits for soTimeout without any communication to the target, a -subsequent write would zero the contents of the file before the file -pointer. This file corruption bug has been fixed. - -Sun Apr 17 22:37:04 EDT 2005 -jcifs-1.1.10 released - -The getChallengeForDomain code has been rewritten. It has been considerably -simplified. It will now rotate through the first -jcifs.netbios.lookupRespLimit domain controllers rather than try to grow -and shrink the list depending on load. The lookupRespLimit property default -has been reduced to 3. The timeout value for rebuilting the DC list has -been increased from 20 minutes to 10 hours. This is calculated by -multiplying jcifs.netvios.cachePolicy by 60 but the default in the -SmbSession class is 60 * 10 meaning 10 minutes so 10 * 60 is 10 hours. -Finally the NtlmChallenge class is now Serializeable for servers that are -pedantic about what can be stored in a session. +Sun May 22 18:22:32 EDT 2005 +jcifs-1.2.0 released + +This release is jcifs-1.1.11trans2 with the following modifications. + +Named pipes were broken when DCE transactions where added with 1.x. Call, +Transact, CreateFile, and DCE named pipe calls should now all work as +expected. The NetBIOS name resolution code will now use the last resource +record of a name query response if there are more than one. This appears to +be more correct in at least one instance (VMWare adapters on my workstation +at work are appearing first). + +Also note the trans releases below. + +Mon May 9 18:49:24 EDT 2005 +jcifs-1.1.11trans2 released + +Socket exception handling was non-existant and reads would actually not +read anything but 0's. These issues and other small issues have been fixed. + +Wed May 4 22:31:28 EDT 2005 +jcifs-1.1.11trans released + +This "transitional" release has all the 1.1.10 and 1.1.11 fixes as well as +more work on the transport layer. The last trans release had a silly mid +rollover bug. I have also emiminated a deadlock condition. These issues +have been fixed. Also the client will not properly try port 445 and +fallback to 139 as necessary. This *could* be stable enough that I might +try to promote this to 1.2.0. + +Thu Apr 7 23:02:48 EDT 2005 +jcifs-1.1.9trans released + +This is a 'transitional' or 'transport rewrite' release. It's stock 1.1.9 +but the transport layer has been refactored and reduced (actually totally +rewritten - SmbTransport.java is less than half the size of it's previous +version). It may still not be "correct" because I believe the high-load +concurrency issue may have to do with how sessions and trees are created. +That is another step that delves into how Principles will be handled so I +thought I would release this as is because it seems pretty stable so I +thought I would put it out there as a reference point. To give people an +insentive to actually use it I have changed the port to 445, applied the +share reconnect fix from Darren and the getDiskFreeSpace patch from Thomas. +Also if you really need the dial to go to 11, preliminary testing indicates +this transport is a few percent faster. + +Feb 28 03:09:31 EST 2005 +jcifs-1.1.9 released + +When multiplexing I/O, if socket buffers fill up such that packets can be +read in fragments (i.e. high load), it was possible for the 4 byte NetBIOS +header to be read incorrectly resulting in a bogus "unexpected EOF reading +netbios session header" exception. This problem has been fixed. Also, some +small javadoc updates have been applied. Thu Feb 10 22:29:12 EST 2005 jcifs-1.1.8 released diff --git a/build.xml b/build.xml index f238d3e..45f4d6a 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - - + + diff --git a/examples/SmbCrawler.java b/examples/SmbCrawler.java index 2beccbe..1ce2d0a 100644 --- a/examples/SmbCrawler.java +++ b/examples/SmbCrawler.java @@ -30,7 +30,8 @@ public class SmbCrawler { traverse( l[i], depth - 1 ); } } catch( IOException ioe ) { - System.out.println( l[i] + ": " + ioe.getMessage() ); + System.out.println( l[i] + ":" ); + ioe.printStackTrace( System.out ); } } } diff --git a/examples/T2Crawler.java b/examples/T2Crawler.java index 14a6ad5..c325e36 100644 --- a/examples/T2Crawler.java +++ b/examples/T2Crawler.java @@ -97,24 +97,32 @@ public class T2Crawler { T2Crawler( String dir, int numThreads, int depth ) throws Exception { SmbFile top = new SmbFile( dir ); Semaphore sem = new Semaphore( numThreads ); - SmbFile[] l = top.listFiles(); - depth--; - for( int i = 0; i < l.length; i++ ) { - try { - System.out.println( l[i] ); - if( !l[i].isDirectory() || l[i].isHidden() ) { - continue; - } - if( depth > 0 ) { - sem.P(); - (new CrawlerThread( l[i], sem, depth )).start(); + SmbFile[] l = null; + int i = 0; + + try { + l = top.listFiles(); + depth--; + for( i = 0; i < l.length; i++ ) { + try { + System.out.println( l[i] ); + if( !l[i].isDirectory() || l[i].isHidden() ) { + continue; + } + if( depth > 0 ) { + sem.P(); + (new CrawlerThread( l[i], sem, depth )).start(); + } + } catch( Exception e ) { + e.printStackTrace(); } - } catch( Exception e ) { - e.printStackTrace(); } - } - for( int i = 0; i < l.length; i++ ) { - l[i].canRead(); + for( i = 0; i < l.length; i++ ) { + l[i].canRead(); + } + } catch( Exception ex ) { + System.err.println( l[i] ); + ex.printStackTrace(); } } public static void main(String[] argv) throws Exception { diff --git a/src/jcifs/Config.java b/src/jcifs/Config.java index 35a5959..512be81 100644 --- a/src/jcifs/Config.java +++ b/src/jcifs/Config.java @@ -273,6 +273,22 @@ public class Config { } return def; } + public static InetAddress getLocalHost() { + String addr = prp.getProperty( "jcifs.smb.client.laddr" ); + try { + if( addr == null ) { + return InetAddress.getLocalHost(); + } + return InetAddress.getByName( addr ); + } catch( UnknownHostException uhe ) { + if( log.level > 0 ) { + log.println( addr ); + uhe.printStackTrace( log ); + } + } + + return null; + } /** * Retrieve a boolean value. If the property is not found, the value of def is returned. diff --git a/src/jcifs/http/NetworkExplorer.java b/src/jcifs/http/NetworkExplorer.java index 279a66a..7bfa14a 100644 --- a/src/jcifs/http/NetworkExplorer.java +++ b/src/jcifs/http/NetworkExplorer.java @@ -30,18 +30,19 @@ import jcifs.smb.*; import jcifs.netbios.NbtAddress; import jcifs.util.MimeMap; import jcifs.util.Base64; +import jcifs.util.LogStream; /** * This servlet may be used to "browse" the entire hierarchy of resources * on an SMB network like one might with Network Neighborhood or Windows * Explorer. The users credentials with be negotiated using NTLM SSP if * the client is Microsoft Internet Explorer. - * - * Please read jCIFS NTLM HTTP Authentication and the Network Explorer Servlet. */ public class NetworkExplorer extends HttpServlet { + private static LogStream log = LogStream.getInstance(); + private MimeMap mimeMap; private String style; private NtlmSsp ntlmSsp; @@ -54,7 +55,7 @@ public class NetworkExplorer extends HttpServlet { InputStream is; StringBuffer sb = new StringBuffer(); byte[] buf = new byte[1024]; - int n; + int n, level; String name; Config.setProperty( "jcifs.smb.client.soTimeout", "600000" ); @@ -90,6 +91,16 @@ public class NetworkExplorer extends HttpServlet { realm = Config.getProperty("jcifs.http.basicRealm"); if (realm == null) realm = "jCIFS"; defaultDomain = Config.getProperty("jcifs.smb.client.domain"); + + if(( level = Config.getInt( "jcifs.util.loglevel", -1 )) != -1 ) { + LogStream.setLevel( level ); + } + if( log.level > 2 ) { + try { + Config.store( log, "JCIFS PROPERTIES" ); + } catch( IOException ioe ) { + } + } } protected void doFile( HttpServletRequest req, @@ -184,6 +195,8 @@ public class NetworkExplorer extends HttpServlet { sdf.setCalendar( cal ); dirents = dir.listFiles(); + if( log.level > 2 ) + log.println( dirents.length + " items listed" ); sorted = new LinkedList(); if(( fmt = req.getParameter( "fmt" )) == null ) { fmt = "col"; @@ -206,7 +219,11 @@ public class NetworkExplorer extends HttpServlet { continue; } } catch( SmbAuthException sae ) { + if( log.level > 2 ) + sae.printStackTrace( log ); } catch( SmbException se ) { + if( log.level > 2 ) + se.printStackTrace( log ); if( se.getNtStatus() != se.NT_STATUS_UNSUCCESSFUL ) { throw se; } @@ -218,6 +235,8 @@ public class NetworkExplorer extends HttpServlet { } name = dirents[i].getName(); + if( log.level > 3 ) + log.println( i + ": " + name ); len = name.length(); if( len > maxLen ) { maxLen = len; diff --git a/src/jcifs/http/NtlmHttpFilter.java b/src/jcifs/http/NtlmHttpFilter.java index 45c7009..91e4a65 100644 --- a/src/jcifs/http/NtlmHttpFilter.java +++ b/src/jcifs/http/NtlmHttpFilter.java @@ -3,6 +3,7 @@ * "Jason Pugsley" * "skeetz" * "Eric Glass" + * and Marcel, Thomas, ... * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -97,17 +98,43 @@ public class NtlmHttpFilter implements Filter { public void destroy() { } + + /** + * This method simply calls negotiate( req, resp, false ) + * and then chain.doFilter. You can override and call + * negotiate manually to achive a variety of different behavior. + */ public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException { - HttpServletRequest req; - HttpServletResponse resp; + HttpServletRequest req = (HttpServletRequest)request; + HttpServletResponse resp = (HttpServletResponse)response; + NtlmPasswordAuthentication ntlm; + + if ((ntlm = negotiate( req, resp, false )) == null) { + return; + } + + chain.doFilter( new NtlmHttpServletRequest( req, ntlm ), response ); + } + + /** + * Negotiate password hashes with MSIE clients using NTLM SSP + * @param req The servlet request + * @param resp The servlet response + * @param skipAuthentication If true the negotiation is only done if it is + * initiated by the client (MSIE post requests after successful NTLM SSP + * authentication). If false and the user has not been authenticated yet + * the client will be forced to send an authentication (server sends + * HttpServletResponse.SC_UNAUTHORIZED). + * @return True if the negotiation is complete, otherwise false + */ + protected NtlmPasswordAuthentication negotiate( HttpServletRequest req, + HttpServletResponse resp, + boolean skipAuthentication ) throws IOException, ServletException { UniAddress dc; String msg; - NtlmPasswordAuthentication ntlm = null; - req = (HttpServletRequest)request; - resp = (HttpServletResponse)response; msg = req.getHeader( "Authorization" ); boolean offerBasic = enableBasic && (insecureBasic || req.isSecure()); @@ -131,7 +158,7 @@ public class NtlmHttpFilter implements Filter { } if(( ntlm = NtlmSsp.authenticate( req, resp, challenge )) == null ) { - return; + return null; } /* negotiation complete, remove the challenge object */ ssn.removeAttribute( "NtlmHttpChal" ); @@ -178,27 +205,30 @@ public class NtlmHttpFilter implements Filter { resp.addHeader( "WWW-Authenticate", "Basic realm=\"" + realm + "\""); } + resp.setContentLength(0); /* Marcel Feb-15-2005 */ resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); resp.flushBuffer(); - return; + return null; } req.getSession().setAttribute( "NtlmHttpAuth", ntlm ); } else { - HttpSession ssn = req.getSession(false); - if (ssn == null || (ntlm = (NtlmPasswordAuthentication) - ssn.getAttribute("NtlmHttpAuth")) == null) { - resp.setHeader( "WWW-Authenticate", "NTLM" ); - if (offerBasic) { - resp.addHeader( "WWW-Authenticate", "Basic realm=\"" + - realm + "\""); + if (!skipAuthentication) { + HttpSession ssn = req.getSession(false); + if (ssn == null || (ntlm = (NtlmPasswordAuthentication) + ssn.getAttribute("NtlmHttpAuth")) == null) { + resp.setHeader( "WWW-Authenticate", "NTLM" ); + if (offerBasic) { + resp.addHeader( "WWW-Authenticate", "Basic realm=\"" + + realm + "\""); + } + resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); + resp.flushBuffer(); + return null; } - resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); - resp.flushBuffer(); - return; } } - chain.doFilter( new NtlmHttpServletRequest( req, ntlm ), response ); + return ntlm; } // Added by cgross to work with weblogic 6.1. diff --git a/src/jcifs/netbios/.NbtSocket.java.swp b/src/jcifs/netbios/.NbtSocket.java.swp deleted file mode 100644 index c307aee14a5324690778462c95777ebed477ac22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16384 zcmeHO-)|#V6~2@oEwrT-NPR;(%}UhSb;owHyR;k9)|<7rZnJh|JG(5^DjJWk5l6%`2;X_2aesCYs=@r0mIctG%-d&e`^Np=$u zLV#wZFP@ou@44rG=iFcCPI~2wjSFvI>2C4ci4Y^#_B`ox$}O*> z=6g2DSQ?kMN?VRQh&C!##X4DvLPtNBd>QxLASyL`aVK!D%Glbnx9wZjo+suE~JukAPQ! z9|A7|yFdh-2LAj3A$||M0tA2yGyw}J0DnUefIEPn!!~T6SJ_5~Tx49WNj#p!oj8>Ch=NH>%M?wZ7n_z4(@dd^C!tSs=?5!M+5LW~>f#$2 zMRY=C9#49n>kzEr`kNF7`UbV{RXvfITFTHgVMR+~W?@Jp`Dmi5TCJ%q6TKSv@+L`1 zrKUL#6|8AFNWFxxn>3PbufOw|@yEp&R|0?FZgR(O_;G>e z)Yn&5^0k$f=A0|ixmvxtzS`aBv^Khp3$@mIcgi};%qrxkc<4qJ`jIF5O?xDh&dj$3 z%3c?#d~KmzB!A+0GqOl}kxYDx#qqUYWWtO!45FAtXAN`*W;L{ou|!p2h*aVd2~cl_ zWnJOHf7PhLTz^=%Kcetgj2 zu}r7R7^)?9ay%QeZb~M}Yq9kEQ8LjeW{;P| zPUyxMrmzet(n<7k>C?PLD;Ugpel}Avbg5L@aWQ~xN?(S&D6xH#VHkv#2<7J{E~a{9 zv$wglO()fo2Ii9k_Zkg?5Peiq^K6%f((YpkhSkd@+6^W&nnbZ0EXBEi{2-Mj$=XPh!`zQll=-ChEx{dxl#oh9?<{5x&Uv9qR9>i5Di2l`%by}z?^IdXs_RG} zq}yJ=mUrW!Ce?F$p&jlnkvm|+6tz=e>89*Z52b`l4dNX;lq}{lj2R7siPxv0y)7w} zj&!$WAKu^u<6UhlN#~pEw2EaR*1qSJD|xi07IZ8_sdG?bswBJ8CWo)}%WO0!T zwf4&6)n>PPwz1miUMA$JH@eMQr$hBto2s-{ZFd_h>#Nl^t*y7$TAi9j)IkH-E1?k! z>0zO8snLC$XZ&jOGF_^++mLyANm0Vf2)T_;!X@BZo{N^D>7nh%+%}fbWv@+GBi#1g z2&-MlMON%7xa2T^qsBu!CO6josVCXv2NMrdjV54Qh7qsn7p%&Zw8TV3Zdn0^(Q!fw z)Y5+*9dVaD^vIBsl8Temsu8JiAsRx9-mcPO#&(7?Es=!vWyqS0g1$T0Wi{bykj>ho zj!`t#>6V7vOT~b_B}%+yNp*Y&14t+{j<_n@@0S8qJ*%(+w+Y?NVN8XUd0N0QN;G%D zb%wU|=&VIm{yKk-KCLo{xyD%5sMI5JK(ljWZXHV{&E>8!V3=p+%Y( zEG3C&=+h5f1IiwH_K_(!RYet22Q7$-q=zOd7??g;wKmRPk~pOi{F=((-vgW3mjip^ z#b<<>lkfk9T21w=l~%J^Tj@4h&5d@gzTT;wn+D{jH90o6?GIM|Emf;n&Pvdidn@6} z4s19laL_9&xl9GTm@nY9g+sSK0`;Fn@Vj2$D^n@n!A2kZ+>Q*l5rJ4k!~@}xX6<~n z+qhWU=wSD*o8DP#H9NKajns!1I#R~EnAfcDMY<-E2)yAGN^OOMt2)%d4w-}o_iD)k z_xk2S;+xaTZr&0^85)PQBto#o85Yz5A;P9lWBZw0vp%dn$qkIyKj+(Lm1hu0Qv!|9 z6``1tJr&KrDqe=u&}dv%hSKDB5k+I$6_dls1A0Lu@qg*bu?h}|rnk(TFe^Z~#L8lb zIOv3|qOMQ9zJz#TJqSlO4rBC5sH)5u6j<6p9-@RKCoM^O8}Ub&RyV>t5-A$teoGw~ M@F7ZilEPa51Aa#^lmGw# diff --git a/src/jcifs/netbios/.SessionServicePacket.java.swp b/src/jcifs/netbios/.SessionServicePacket.java.swp deleted file mode 100644 index 12f416274e287dfd7008adef867316e18733a50c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeHPU5F%C6~4OBwKXw8Nl+wmb_}K`)7w2gGrL*onT6ijo|)dvpWQvX8P~O`?!G-; zo1Utss(NN8lgX10fg0(S$izEg-_0WSbg0|&q? za2N1OOo*QY&j6Q!2Z7(eLx}GH-vsu7Jn#YFe&E(gA-)E9z#MQd5CdL*yAa<8J_Qtk zhk;YTzrn#@fZqW>0KNg-1fB;xpb9(=6oDn+A}|j;3NU}aK+xo?zya_S@FcJaEb`yr zxQ!soL%;`t+X%FL4|t9PE<-K~F0&pdB%K&)TDF8bmW5VY#UyjSn}#Mf_{QnEUc*0!a=7U zM|y3?qNQB+Vy;kL&aEz%mS}<;)LC*2v)Nm*X(g!AuGgg#{wf1$+&77hXU##2j! z#2jteUIr@!;zPCiWH8^3tVhksOOKVam)6tM<@vP%g@FRQx0Tp|h{b&KyZ)qB&kc7A zV*V8=kg1BfAZBv^tPKCD?qe0q$0yXiS*N%~vvV}b>lOkQ7O80^c^+d4CdjVWv69RL zuXQ?2Ca;oMY`1|$MRAj6xtvu|$dlQG`eY(#OqHgvpq_Y9e(S5y;@f9&(5n3(*CP1R6||+%7E^L<{Q*&I)-Ta8Xdc*5TA;~2m2cK zxv#TOOZTevb$2*Ny(&{P9ftbY$Xnjb8^cAHmC>jl$GB+72W^{rO}60;+xhfGAHF#4 z7|kK$)Ggipp~L{N!uj)RG7gUK(RylxUXP+0r(VT?lO5Zv`5$e6#CQqA%Ff3PMjiRZ z?l%0+&@;?f4B_#NRf{gDp>A3j0@mx@U(C@=&!UdxRcOq|) z(!4>!YnhkVK;=a!zGz3EYU>ubgQA$n7z^rB`yx{)iE6dC8zM@a|#1=I!7sT8?>{w;o0 z0xq>w1}^cA(j_5`it9N>)uU?Da9tXftxNlmGq+o|;}IwBCQUop^=-)vJd3ts7&~sy z*pj5Ogp)y5FpudYDS#I2wpGKI%f?6|{us@w zMM9v(HMT1T)okqboUQXB^@zWI$lb1BrJ52i*I-ifcwFLidiMW!;fvn_*#GA<{$Il1 z{~7RI;B!C=xDLz$_W-ZL_kRJ{1Ktn(6Mp~SfxiJafn8t;cmTK^)cqT-UtgL5&46Y= zGoTsJ3}^;41DXNNfM(#%F>nBn@`!8jC@2bMj#A|?RnLLak*$O=cmF_4iFbl1TpLH< zha94HMNHtb!9~W^qo-mLLlj3J>jjaqDApZBY#uh8+z&eU zhUHaX@|MSu+#%-QY3i zu%SCH>1tGc3Vr?){sArGxdVr&VcEn)#8cD`cXoIb7_riHM*07L#@YHV&feMo=bZnS z;p2Y=XaFgIfS2Ise;s%h_#}`79s>RWAO8=)Z-HCDOTdqTX911@ybt&*eE&ZIp9M<5 z3E*F7?}xzifNJ~By#sX3ngPv#WL zD90Smm~!U)PEYh@y9DWTOoFPQn}yLXJtqe8jAAwRr&Ssuy!KJ9K2k7QoG+y^)c+pz zzI(k&<#UrIce}G_<22T`m2bm~6QhwuIY*~CCvabMm8%D;VdOK8$R}xTjf=yY37-v#ECoqSTp!1k{C}TU!o(O%@BA+!=(0rs diff --git a/src/jcifs/netbios/Name.java b/src/jcifs/netbios/Name.java index b06b783..fddbd85 100644 --- a/src/jcifs/netbios/Name.java +++ b/src/jcifs/netbios/Name.java @@ -23,7 +23,7 @@ import java.io.UnsupportedEncodingException; import jcifs.Config; import jcifs.util.Hexdump; -class Name { +public class Name { private static final int TYPE_OFFSET = 31; private static final int SCOPE_OFFSET = 33; @@ -33,15 +33,15 @@ class Name { Config.getProperty( "jcifs.encoding", System.getProperty( "file.encoding" )); - String name, scope; - int hexCode; + public String name, scope; + public int hexCode; int srcHashCode; /* srcHashCode must be set by name resolution * routines before entry into addressCache */ Name() { } - Name( String name, int hexCode, String scope ) { + public Name( String name, int hexCode, String scope ) { if( name.length() > 15 ) { name = name.substring( 0, 15 ); } diff --git a/src/jcifs/netbios/NameServiceClient.java b/src/jcifs/netbios/NameServiceClient.java index dbd2011..9bd690d 100644 --- a/src/jcifs/netbios/NameServiceClient.java +++ b/src/jcifs/netbios/NameServiceClient.java @@ -314,8 +314,9 @@ class NameServiceClient implements Runnable { } if( response.received && response.resultCode == 0 ) { - response.addrEntry[0].hostName.srcHashCode = addr.hashCode(); - return response.addrEntry[0]; + int last = response.addrEntry.length - 1; + response.addrEntry[last].hostName.srcHashCode = addr.hashCode(); + return response.addrEntry[last]; } } while( --n > 0 && request.isBroadcast ); diff --git a/src/jcifs/netbios/NbtAddress.java b/src/jcifs/netbios/NbtAddress.java index affceb2..ae4e82f 100644 --- a/src/jcifs/netbios/NbtAddress.java +++ b/src/jcifs/netbios/NbtAddress.java @@ -351,6 +351,9 @@ public final class NbtAddress { public static NbtAddress getLocalHost() throws UnknownHostException { return localhost; } + public static Name getLocalName() { + return localhost.hostName; + } /** * Determines the address of a host given it's host name. The name can be a NetBIOS name like @@ -603,8 +606,13 @@ public final class NbtAddress { i++; } } - } else if( hostName.hexCode == 0x1D || hostName.hexCode == 0x1C ) { - calledName = SMBSERVER_NAME; + } else { + switch (hostName.hexCode) { + case 0x1B: + case 0x1C: + case 0x1D: + calledName = SMBSERVER_NAME; + } } return calledName; diff --git a/src/jcifs/netbios/SessionRequestPacket.java b/src/jcifs/netbios/SessionRequestPacket.java index b5a7ee9..28325df 100644 --- a/src/jcifs/netbios/SessionRequestPacket.java +++ b/src/jcifs/netbios/SessionRequestPacket.java @@ -21,7 +21,7 @@ package jcifs.netbios; import java.io.IOException; import java.io.InputStream; -class SessionRequestPacket extends SessionServicePacket { +public class SessionRequestPacket extends SessionServicePacket { private Name calledName, callingName; @@ -29,7 +29,7 @@ class SessionRequestPacket extends SessionServicePacket { calledName = new Name(); callingName = new Name(); } - SessionRequestPacket( Name calledName, Name callingName ) { + public SessionRequestPacket( Name calledName, Name callingName ) { type = SESSION_REQUEST; this.calledName = calledName; this.callingName = callingName; diff --git a/src/jcifs/netbios/SessionServicePacket.java b/src/jcifs/netbios/SessionServicePacket.java index a1a8d6c..66174ef 100644 --- a/src/jcifs/netbios/SessionServicePacket.java +++ b/src/jcifs/netbios/SessionServicePacket.java @@ -21,13 +21,13 @@ package jcifs.netbios; import java.io.IOException; import java.io.InputStream; -abstract class SessionServicePacket { +public abstract class SessionServicePacket { // session service packet types static final int SESSION_MESSAGE = 0x00; static final int SESSION_REQUEST = 0x81; - static final int POSITIVE_SESSION_RESPONSE = 0x82; - static final int NEGATIVE_SESSION_RESPONSE = 0x83; + public static final int POSITIVE_SESSION_RESPONSE = 0x82; + public static final int NEGATIVE_SESSION_RESPONSE = 0x83; static final int SESSION_RETARGET_RESPONSE = 0x84; static final int SESSION_KEEP_ALIVE = 0x85; @@ -93,7 +93,7 @@ abstract class SessionServicePacket { int type, length; - int writeWireFormat( byte[] dst, int dstIndex ) { + public int writeWireFormat( byte[] dst, int dstIndex ) { length = writeTrailerWireFormat( dst, dstIndex + HEADER_LENGTH ); writeHeaderWireFormat( dst, dstIndex ); return HEADER_LENGTH + length; diff --git a/src/jcifs/smb/AndXServerMessageBlock.java b/src/jcifs/smb/AndXServerMessageBlock.java index b21eb95..07287f1 100644 --- a/src/jcifs/smb/AndXServerMessageBlock.java +++ b/src/jcifs/smb/AndXServerMessageBlock.java @@ -36,23 +36,12 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock { AndXServerMessageBlock() { } AndXServerMessageBlock( ServerMessageBlock andx ) { - this.andx = andx; - if( andx != null ) { + if (andx != null) { + this.andx = andx; andxCommand = andx.command; } } - /* The SmbComReadAndXResponse can read from the InputStream - * directly by implementing this method. The default - * behavior is to arraycopy all bytes into the buffer and call - * readBytesWireFormat. The alternative would have been to overload - * the readAndXWireFormat method but that would have resulted in - * copying a fairly large chunck of code into the subclass. - */ - - abstract int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException; - int getBatchLimit( byte command ) { /* the default limit is 0 batched messages before this * one, meaning this message cannot be batched. @@ -69,7 +58,7 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock { * just recursivly call writeAndXWireFormat. */ - int writeWireFormat( byte[] dst, int dstIndex ) { + int encode( byte[] dst, int dstIndex ) { int start = headerStart = dstIndex; dstIndex += writeHeaderWireFormat( dst, dstIndex ); @@ -90,17 +79,11 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock { * readAndXWireFormat without reading the non-existent header. */ - int readWireFormat( InputStream in, - byte[] buffer, - int bufferIndex ) - throws IOException { - int start = bufferIndex; + int decode( byte[] buffer, int bufferIndex ) { + int start = headerStart = bufferIndex; - if( in.read( buffer, bufferIndex, HEADER_LENGTH ) != HEADER_LENGTH ) { - throw new IOException( "unexpected EOF reading smb header" ); - } bufferIndex += readHeaderWireFormat( buffer, bufferIndex ); - bufferIndex += readAndXWireFormat( in, buffer, bufferIndex ); + bufferIndex += readAndXWireFormat( buffer, bufferIndex ); length = bufferIndex - start; return length; @@ -109,7 +92,7 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock { int start = dstIndex; wordCount = writeParameterWordsWireFormat( dst, - start + ANDX_OFFSET_OFFSET + 2 ); + start + ANDX_OFFSET_OFFSET + 2 ); wordCount += 4; // for command, reserved, and offset dstIndex += wordCount + 1; wordCount /= 2; @@ -130,7 +113,6 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock { * very indirect and simple batching control mechanism. */ - if( andx == null || USE_BATCHING == false || batchLevel >= getBatchLimit( andx.command )) { andxCommand = (byte)0xFF; @@ -197,77 +179,39 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock { return dstIndex - start; } - int readAndXWireFormat( InputStream in, - byte[] buffer, - int bufferIndex ) - throws IOException { + int readAndXWireFormat( byte[] buffer, int bufferIndex ) { int start = bufferIndex; - /* - * read wordCount - */ - - if(( wordCount = in.read() ) == -1 ) { - throw new IOException( "unexpected EOF reading smb wordCount" ); - } - buffer[bufferIndex++] = (byte)( wordCount & 0xFF ); - - /* - * read parameterWords - */ + wordCount = buffer[bufferIndex++]; if( wordCount != 0 ) { - if( in.read( buffer, bufferIndex, wordCount * 2 ) != ( wordCount * 2 )) { - throw new IOException( "unexpected EOF reading andx parameter words" ); - } - /* * these fields are common to all andx commands * so let's populate them here */ - - andxCommand = buffer[bufferIndex]; - bufferIndex += 2; - andxOffset = readInt2( buffer, bufferIndex ); - bufferIndex += 2; + + andxCommand = buffer[bufferIndex]; bufferIndex += 2; + andxOffset = readInt2( buffer, bufferIndex ); bufferIndex += 2; if( andxOffset == 0 ) { /* Snap server workaround */ andxCommand = (byte)0xFF; } - + /* * no point in calling readParameterWordsWireFormat if there are no more * parameter words. besides, win98 doesn't return "OptionalSupport" field */ - + if( wordCount > 2 ) { bufferIndex += readParameterWordsWireFormat( buffer, bufferIndex ); } } - /* - * read byteCount - */ + byteCount = readInt2( buffer, bufferIndex ); bufferIndex += 2; - if( in.read( buffer, bufferIndex, 2 ) != 2 ) { - throw new IOException( "unexpected EOF reading smb byteCount" ); - } - byteCount = readInt2( buffer, bufferIndex ); - bufferIndex += 2; - - /* - * read bytes - */ - - if( byteCount != 0 ) { + if (byteCount != 0) { int n; - n = readBytesDirectWireFormat( in, byteCount, buffer, bufferIndex ); - if( n == 0 ) { - if( in.read( buffer, bufferIndex, byteCount ) != byteCount ) { - throw new IOException( "unexpected EOF reading andx bytes" ); - } - n = readBytesWireFormat( buffer, bufferIndex ); - } + n = readBytesWireFormat( buffer, bufferIndex ); bufferIndex += byteCount; } @@ -283,30 +227,14 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock { andx = null; } else if( andx == null ) { andxCommand = (byte)0xFF; - throw new IOException( "no andx command supplied with response" ); + throw new RuntimeException( "no andx command supplied with response" ); } else { /* - * This is where we take into account andxOffset - * - * Before we call readAndXWireFormat on the next andx - * part we must take into account the andxOffset. The - * input stream must be positioned at this location. The - * new location is the just read andxOffset(say 68) - * minus the current bufferIndex(say 65). But this packet - * construction/deconstruction technique does not require that - * the bufferIndex begin at 0. The header might be at another - * location(say 4). So we must subtract the current buffer - * index from the real start of the header and substract that - * from the andxOffset(like 68 - ( 65 - 0 ) if headerStart - * were 0 or 68 - ( 69 - 4 ) if the headerStart were 4. We - * also need to communicate to our newly instantiated andx - * smb the headerStart value so that it may perform the same - * calculation as this is a recursive process. + * Set bufferIndex according to andxOffset */ - bufferIndex += in.read( buffer, bufferIndex, - andxOffset - ( bufferIndex - headerStart )); + bufferIndex = headerStart + andxOffset; andx.headerStart = headerStart; andx.command = andxCommand; @@ -321,61 +249,30 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock { if( andx instanceof AndXServerMessageBlock ) { bufferIndex += ((AndXServerMessageBlock)andx).readAndXWireFormat( - in, buffer, andxOffset - headerStart ); + buffer, bufferIndex ); } else { /* * Just a plain smb. Read it as normal. */ - /* - * read wordCount - */ - - if(( andx.wordCount = in.read() ) == -1 ) { - throw new IOException( "unexpected EOF reading smb wordCount" ); - } buffer[bufferIndex++] = (byte)( andx.wordCount & 0xFF ); - /* - * read parameterWords - */ - if( andx.wordCount != 0 ) { - if( in.read( buffer, bufferIndex, andx.wordCount * 2 ) != - ( andx.wordCount * 2 )) { - throw new IOException( "unexpected EOF reading andx parameter words" ); - } - /* * no point in calling readParameterWordsWireFormat if there are no more * parameter words. besides, win98 doesn't return "OptionalSupport" field */ if( andx.wordCount > 2 ) { - bufferIndex += - andx.readParameterWordsWireFormat( buffer, bufferIndex ); + bufferIndex += andx.readParameterWordsWireFormat( buffer, bufferIndex ); } } - /* - * read byteCount - */ - - if( in.read( buffer, bufferIndex, 2 ) != 2 ) { - throw new IOException( "unexpected EOF reading smb byteCount" ); - } andx.byteCount = readInt2( buffer, bufferIndex ); bufferIndex += 2; - /* - * read bytes - */ - if( andx.byteCount != 0 ) { - if( in.read( buffer, bufferIndex, andx.byteCount ) != andx.byteCount ) { - throw new IOException( "unexpected EOF reading andx bytes" ); - } andx.readBytesWireFormat( buffer, bufferIndex ); bufferIndex += andx.byteCount; } diff --git a/src/jcifs/smb/BufferCache.java b/src/jcifs/smb/BufferCache.java index 120886e..9dcc74a 100644 --- a/src/jcifs/smb/BufferCache.java +++ b/src/jcifs/smb/BufferCache.java @@ -24,43 +24,47 @@ class BufferCache { private static final int MAX_BUFFERS = Config.getInt( "jcifs.smb.maxBuffers", 16 ); - private static Object[] cache = new Object[MAX_BUFFERS]; + static Object[] cache = new Object[MAX_BUFFERS]; private static int numBuffers = 0; private static int freeBuffers = 0; - static byte[] getBuffer() { + private static byte[] getBuffer() { byte[] buf; - synchronized( cache ) { - while( freeBuffers == 0 && numBuffers == MAX_BUFFERS ) { - try { - cache.wait(); - } catch( InterruptedException ie ) { - return null; + if (freeBuffers > 0) { + for (int i = 0; i < MAX_BUFFERS; i++) { + if( cache[i] != null ) { + buf = (byte[])cache[i]; + cache[i] = null; + freeBuffers--; + return buf; } } + } + + buf = new byte[SmbComTransaction.TRANSACTION_BUF_SIZE]; + numBuffers++; + + return buf; + } - if( freeBuffers > 0 ) { - for( int i = 0; i < MAX_BUFFERS; i++ ) { - if( cache[i] != null ) { - buf = (byte[])cache[i]; - cache[i] = null; - freeBuffers--; - return buf; - } + static void getBuffers( SmbComTransaction req, SmbComTransactionResponse rsp ) { + synchronized( cache ) { + try { + while ((freeBuffers + (MAX_BUFFERS - numBuffers)) < 2) { + cache.wait(); } + req.txn_buf = getBuffer(); + rsp.txn_buf = getBuffer(); + } catch( InterruptedException ie ) { + ie.printStackTrace(); } - - buf = new byte[SmbComTransaction.TRANSACTION_BUF_SIZE]; - numBuffers++; } - - return buf; } static void releaseBuffer( byte[] buf ) { synchronized( cache ) { - for( int i = 0; i < MAX_BUFFERS; i++ ) { - if( cache[i] == null ) { + for (int i = 0; i < MAX_BUFFERS; i++) { + if (cache[i] == null) { cache[i] = buf; freeBuffers++; cache.notify(); diff --git a/src/jcifs/smb/Handler.java b/src/jcifs/smb/Handler.java index a02f753..1f89e4b 100644 --- a/src/jcifs/smb/Handler.java +++ b/src/jcifs/smb/Handler.java @@ -68,7 +68,7 @@ public class Handler extends URLStreamHandler { } protected int getDefaultPort() { - return 139; + return SmbConstants.DEFAULT_PORT; } public URLConnection openConnection( URL u ) throws IOException { return new SmbFile( u ); diff --git a/src/jcifs/smb/NtStatus.java b/src/jcifs/smb/NtStatus.java index 58f9782..4bf5717 100644 --- a/src/jcifs/smb/NtStatus.java +++ b/src/jcifs/smb/NtStatus.java @@ -30,6 +30,7 @@ public interface NtStatus { public static final int NT_STATUS_INVALID_INFO_CLASS = 0xC0000003; public static final int NT_STATUS_ACCESS_VIOLATION = 0xC0000005; public static final int NT_STATUS_INVALID_HANDLE = 0xC0000008; + public static final int NT_STATUS_NO_SUCH_DEVICE = 0xC000000e; public static final int NT_STATUS_NO_SUCH_FILE = 0xC000000f; public static final int NT_STATUS_ACCESS_DENIED = 0xC0000022; public static final int NT_STATUS_OBJECT_NAME_INVALID = 0xC0000033; @@ -56,11 +57,13 @@ public interface NtStatus { public static final int NT_STATUS_PIPE_CLOSING = 0xC00000b1; public static final int NT_STATUS_PIPE_LISTENING = 0xC00000b3; public static final int NT_STATUS_FILE_IS_A_DIRECTORY = 0xC00000ba; + public static final int NT_STATUS_NETWORK_NAME_DELETED = 0xC00000c9; public static final int NT_STATUS_BAD_NETWORK_NAME = 0xC00000cc; public static final int NT_STATUS_NOT_A_DIRECTORY = 0xC0000103; public static final int NT_STATUS_CANNOT_DELETE = 0xC0000121; public static final int NT_STATUS_PIPE_BROKEN = 0xC000014b; public static final int NT_STATUS_LOGON_TYPE_NOT_GRANTED = 0xC000015b; + public static final int NT_STATUS_TRUSTED_DOMAIN_FAILURE = 0xC000018c; public static final int NT_STATUS_ACCOUNT_LOCKED_OUT = 0xC0000234; public static final int NT_STATUS_PATH_NOT_COVERED = 0xC0000257; @@ -71,6 +74,7 @@ public interface NtStatus { NT_STATUS_INVALID_INFO_CLASS, NT_STATUS_ACCESS_VIOLATION, NT_STATUS_INVALID_HANDLE, + NT_STATUS_NO_SUCH_DEVICE, NT_STATUS_NO_SUCH_FILE, NT_STATUS_ACCESS_DENIED, NT_STATUS_OBJECT_NAME_INVALID, @@ -97,11 +101,13 @@ public interface NtStatus { NT_STATUS_PIPE_CLOSING, NT_STATUS_PIPE_LISTENING, NT_STATUS_FILE_IS_A_DIRECTORY, + NT_STATUS_NETWORK_NAME_DELETED, NT_STATUS_BAD_NETWORK_NAME, NT_STATUS_NOT_A_DIRECTORY, NT_STATUS_CANNOT_DELETE, NT_STATUS_PIPE_BROKEN, NT_STATUS_LOGON_TYPE_NOT_GRANTED, + NT_STATUS_TRUSTED_DOMAIN_FAILURE, NT_STATUS_ACCOUNT_LOCKED_OUT, NT_STATUS_PATH_NOT_COVERED, }; @@ -114,6 +120,7 @@ public interface NtStatus { "Invalid access to memory location.", "The handle is invalid.", "The system cannot find the file specified.", + "The system cannot find the file specified.", "Access is denied.", "The filename, directory name, or volume label syntax is incorrect.", "The system cannot find the file specified.", @@ -139,11 +146,13 @@ public interface NtStatus { "The pipe is being closed.", "Waiting for a process to open the other end of the pipe.", "Access is denied.", + "The specified network name is no longer available.", "The network name cannot be found.", "The directory name is invalid.", "Access is denied.", "The pipe has been ended.", "Logon failure: the user has not been granted the requested logon type at this computer.", + "The trust relationship between the primary domain and the trusted domain failed.", "The referenced account is currently locked out and may not be logged on to.", "The remote system is not reachable by the transport.", }; diff --git a/src/jcifs/smb/NtlmChallenge.java b/src/jcifs/smb/NtlmChallenge.java index 0d9ce62..0eed075 100644 --- a/src/jcifs/smb/NtlmChallenge.java +++ b/src/jcifs/smb/NtlmChallenge.java @@ -19,8 +19,8 @@ package jcifs.smb; import java.io.Serializable; -import jcifs.util.Hexdump; import jcifs.UniAddress; +import jcifs.util.Hexdump; public final class NtlmChallenge implements Serializable { diff --git a/src/jcifs/smb/ServerMessageBlock.java b/src/jcifs/smb/ServerMessageBlock.java index 6a4fa0a..7580f49 100644 --- a/src/jcifs/smb/ServerMessageBlock.java +++ b/src/jcifs/smb/ServerMessageBlock.java @@ -23,90 +23,13 @@ import java.io.InputStream; import java.io.PushbackInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.util.TimeZone; import java.util.Calendar; import java.util.Date; import jcifs.util.Hexdump; import jcifs.util.LogStream; +import jcifs.util.transport.*; -abstract class ServerMessageBlock { - - 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; - static final int FLAGS_PATH_NAMES_CASELESS = 0x08; - static final int FLAGS_PATH_NAMES_CANONICALIZED = 0x10; - static final int FLAGS_OPLOCK_REQUESTED_OR_GRANTED = 0x20; - static final int FLAGS_NOTIFY_OF_MODIFY_ACTION = 0x40; - static final int FLAGS_RESPONSE = 0x80; - - static final int FLAGS2_NONE = 0x0000; - static final int FLAGS2_LONG_FILENAMES = 0x0001; - static final int FLAGS2_EXTENDED_ATTRIBUTES = 0x0002; - static final int FLAGS2_SECURITY_SIGNATURES = 0x0004; - static final int FLAGS2_EXTENDED_SECURITY_NEGOTIATION = 0x0800; - static final int FLAGS2_RESOLVE_PATHS_IN_DFS = 0x1000; - static final int FLAGS2_PERMIT_READ_IF_EXECUTE_PERM = 0x2000; - static final int FLAGS2_STATUS32 = 0x4000; - static final int FLAGS2_UNICODE = 0x8000; - - static final int CAP_NONE = 0x0000; - static final int CAP_RAW_MODE = 0x0001; - static final int CAP_MPX_MODE = 0x0002; - static final int CAP_UNICODE = 0x0004; - static final int CAP_LARGE_FILES = 0x0008; - static final int CAP_NT_SMBS = 0x0010; - static final int CAP_RPC_REMOTE_APIS = 0x0020; - static final int CAP_STATUS32 = 0x0040; - static final int CAP_LEVEL_II_OPLOCKS = 0x0080; - static final int CAP_LOCK_AND_READ = 0x0100; - static final int CAP_NT_FIND = 0x0200; - static final int CAP_DFS = 0x1000; - - // file attribute encoding - static final int ATTR_READONLY = 0x01; - static final int ATTR_HIDDEN = 0x02; - static final int ATTR_SYSTEM = 0x04; - static final int ATTR_VOLUME = 0x08; - static final int ATTR_DIRECTORY = 0x10; - static final int ATTR_ARCHIVE = 0x20; - - // extended file attribute encoding(others same as above) - static final int ATTR_COMPRESSED = 0x800; - static final int ATTR_NORMAL = 0x080; - static final int ATTR_TEMPORARY = 0x100; - - // flags for move and copy - static final int FLAGS_TARGET_MUST_BE_FILE = 0x0001; - static final int FLAGS_TARGET_MUST_BE_DIRECTORY = 0x0002; - static final int FLAGS_COPY_TARGET_MODE_ASCII = 0x0004; - static final int FLAGS_COPY_SOURCE_MODE_ASCII = 0x0008; - static final int FLAGS_VERIFY_ALL_WRITES = 0x0010; - static final int FLAGS_TREE_COPY = 0x0020; - - // open function - static final int OPEN_FUNCTION_FAIL_IF_EXISTS = 0x0000; - static final int OPEN_FUNCTION_OVERWRITE_IF_EXISTS = 0x0020; - - static final int PID = (int)( Math.random() * 65536d ); - - static final int SECURITY_SHARE = 0x00; - static final int SECURITY_USER = 0x01; - - static final int CMD_OFFSET = 4; - static final int ERROR_CODE_OFFSET = 5; - static final int FLAGS_OFFSET = 9; - static final int SIGNATURE_OFFSET = 14; - static final int TID_OFFSET = 24; - static final int HEADER_LENGTH = 32; - - static final long MILLISECONDS_BETWEEN_1970_AND_1601 = 11644473600000L; - static final TimeZone TZ = TimeZone.getDefault(); - - static final boolean USE_BATCHING = Config.getBoolean( "jcifs.smb.client.useBatching", true ); - static final String OEM_ENCODING = - Config.getProperty( "jcifs.encoding", - System.getProperty( "file.encoding" )); +abstract class ServerMessageBlock extends Response implements Request, SmbConstants { static LogStream log = LogStream.getInstance(); @@ -158,57 +81,12 @@ abstract class ServerMessageBlock { int hi = readInt4( src, srcIndex + 4 ); long t = ((long)hi << 32L ) | (low & 0xFFFFFFFFL); t = ( t / 10000L - MILLISECONDS_BETWEEN_1970_AND_1601 ); - -/* - synchronized( TZ ) { - if( TZ.inDaylightTime( new Date() )) { - // in DST - if( TZ.inDaylightTime( new Date( t ))) { - // t also in DST so no correction - return t; - } - // t not in DST so add 1 hour - return t + 3600000; - } else { - // not in DST - if( TZ.inDaylightTime( new Date( t ))) { - // t is in DST so subtract 1 hour - return t - 3600000; - } - // t isn't in DST either - return t; - } - } -*/ return t; } static void writeTime( long t, byte[] dst, int dstIndex ) { - if( t != 0L ) { -/* - synchronized( TZ ) { - if( TZ.inDaylightTime( new Date() )) { - // in DST - if( TZ.inDaylightTime( new Date( t ))) { - // t also in DST so no correction - } else { - // t not in DST so subtract 1 hour - t -= 3600000; - } - } else { - // not in DST - if( TZ.inDaylightTime( new Date( t ))) { - // t is in DST so add 1 hour - t += 3600000; - } else { - // t isn't in DST either - } - } - } -*/ t = (t + MILLISECONDS_BETWEEN_1970_AND_1601) * 10000L; } - writeInt8( t, dst, dstIndex ); } static long readUTime( byte[] buffer, int bufferIndex ) { @@ -241,7 +119,6 @@ abstract class ServerMessageBlock { writeInt4( (int)(t / 1000L), dst, dstIndex ); } - /* * These are all the smbs supported by this library. This includes requests * and well as their responses for each type however the actuall implementations @@ -312,6 +189,8 @@ abstract class ServerMessageBlock { batchLevel = 0; } + void reset() { + } int writeString( String str, byte[] dst, int dstIndex ) { return writeString( str, dst, dstIndex, useUnicode ); } @@ -398,7 +277,7 @@ Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 ); } return len; } - int writeWireFormat( byte[] dst, int dstIndex ) { + int encode( byte[] dst, int dstIndex ) { int start = headerStart = dstIndex; dstIndex += writeHeaderWireFormat( dst, dstIndex ); @@ -419,39 +298,13 @@ Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 ); return length; } - int readWireFormat( InputStream in, - byte[] buffer, - int bufferIndex ) - throws IOException { - + int decode( byte[] buffer, int bufferIndex ) { int start = headerStart = bufferIndex; - /* - * read header - */ - - if( in.read( buffer, bufferIndex, HEADER_LENGTH ) != HEADER_LENGTH ) { - throw new IOException( "unexpected EOF reading smb header" ); - } bufferIndex += readHeaderWireFormat( buffer, bufferIndex ); - /* - * read wordCount - */ - - if(( wordCount = in.read() ) == -1 ) { - throw new IOException( "unexpected EOF reading smb wordCount" ); - } - buffer[bufferIndex++] = (byte)( wordCount & 0xFF ); - - /* - * read parameter words - */ - + wordCount = buffer[bufferIndex++]; if( wordCount != 0 ) { - if( in.read( buffer, bufferIndex, wordCount * 2 ) != wordCount * 2 ) { - throw new IOException( "unexpected EOF reading smb parameter words" ); - } int n; if(( n = readParameterWordsWireFormat( buffer, bufferIndex )) != wordCount * 2 ) { if( log.level > 2 ) { @@ -462,24 +315,10 @@ Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 ); bufferIndex += wordCount * 2; } - /* - * read byteCount - */ - - if( in.read( buffer, bufferIndex, 2 ) != 2 ) { - throw new IOException( "unexpected EOF reading smb byteCount" ); - } byteCount = readInt2( buffer, bufferIndex ); bufferIndex += 2; - /* - * read bytes - */ - if( byteCount != 0 ) { - if( in.read( buffer, bufferIndex, byteCount ) != byteCount ) { - throw new IOException( "unexpected EOF reading smb" ); - } int n; if(( n = readBytesWireFormat( buffer, bufferIndex )) != byteCount ) { if( log.level > 2 ) { @@ -508,7 +347,7 @@ Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 ); writeInt2( mid, dst, dstIndex + 6 ); return HEADER_LENGTH; } - int readHeaderWireFormat( byte[] buffer, int bufferIndex ) throws IOException { + int readHeaderWireFormat( byte[] buffer, int bufferIndex ) { command = buffer[bufferIndex + CMD_OFFSET]; errorCode = readInt4( buffer, bufferIndex + ERROR_CODE_OFFSET ); flags = buffer[bufferIndex + FLAGS_OFFSET]; @@ -546,13 +385,15 @@ Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 ); abstract int writeParameterWordsWireFormat( byte[] dst, int dstIndex ); abstract int writeBytesWireFormat( byte[] dst, int dstIndex ); - abstract int readParameterWordsWireFormat( byte[] buffer, - int bufferIndex ) - throws IOException; - abstract int readBytesWireFormat( byte[] buffer, - int bufferIndex ) - throws IOException; + abstract int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ); + abstract int readBytesWireFormat( byte[] buffer, int bufferIndex ); + public int hashCode() { + return mid; + } + public boolean equals( Object obj ) { + return obj instanceof ServerMessageBlock && ((ServerMessageBlock)obj).mid == mid; + } public String toString() { String c; switch( command ) { diff --git a/src/jcifs/smb/SmbComLogoffAndX.java b/src/jcifs/smb/SmbComLogoffAndX.java index bbfaf65..3b7d63c 100644 --- a/src/jcifs/smb/SmbComLogoffAndX.java +++ b/src/jcifs/smb/SmbComLogoffAndX.java @@ -18,9 +18,6 @@ package jcifs.smb; -import java.io.IOException; -import java.io.InputStream; - class SmbComLogoffAndX extends AndXServerMessageBlock { SmbComLogoffAndX( ServerMessageBlock andx ) { @@ -40,10 +37,6 @@ class SmbComLogoffAndX extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComLogoffAndX[" + super.toString() + "]" ); diff --git a/src/jcifs/smb/SmbComNTCreateAndX.java b/src/jcifs/smb/SmbComNTCreateAndX.java index d8779f5..e973662 100644 --- a/src/jcifs/smb/SmbComNTCreateAndX.java +++ b/src/jcifs/smb/SmbComNTCreateAndX.java @@ -18,8 +18,6 @@ package jcifs.smb; -import java.io.IOException; -import java.io.InputStream; import jcifs.util.Hexdump; class SmbComNTCreateAndX extends AndXServerMessageBlock { @@ -199,10 +197,6 @@ class SmbComNTCreateAndX extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComNTCreateAndX[" + super.toString() + diff --git a/src/jcifs/smb/SmbComNTCreateAndXResponse.java b/src/jcifs/smb/SmbComNTCreateAndXResponse.java index a264eed..e030512 100644 --- a/src/jcifs/smb/SmbComNTCreateAndXResponse.java +++ b/src/jcifs/smb/SmbComNTCreateAndXResponse.java @@ -19,8 +19,6 @@ package jcifs.smb; import java.util.Date; -import java.io.IOException; -import java.io.InputStream; import jcifs.util.Hexdump; class SmbComNTCreateAndXResponse extends AndXServerMessageBlock { @@ -85,10 +83,6 @@ class SmbComNTCreateAndXResponse extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComNTCreateAndXResponse[" + super.toString() + diff --git a/src/jcifs/smb/SmbComNegotiate.java b/src/jcifs/smb/SmbComNegotiate.java index 6eb41e3..9f6af4d 100644 --- a/src/jcifs/smb/SmbComNegotiate.java +++ b/src/jcifs/smb/SmbComNegotiate.java @@ -26,6 +26,7 @@ class SmbComNegotiate extends ServerMessageBlock { SmbComNegotiate() { command = SMB_COM_NEGOTIATE; + flags2 = DEFAULT_FLAGS2; } int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) { diff --git a/src/jcifs/smb/SmbComNegotiateResponse.java b/src/jcifs/smb/SmbComNegotiateResponse.java index 5126722..e78ba24 100644 --- a/src/jcifs/smb/SmbComNegotiateResponse.java +++ b/src/jcifs/smb/SmbComNegotiateResponse.java @@ -24,25 +24,11 @@ import jcifs.util.Hexdump; class SmbComNegotiateResponse extends ServerMessageBlock { - int dialectIndex, - securityMode, - security, - maxMpxCount, - maxNumberVcs, - maxBufferSize, - maxRawSize, - sessionKey, - capabilities, - serverTimeZone, - encryptionKeyLength; - boolean encryptedPasswords, - signaturesEnabled, - signaturesRequired; - long serverTime; - byte[] encryptionKey; - String oemDomainName; + int dialectIndex; + SmbTransport.ServerData server; - SmbComNegotiateResponse() { + SmbComNegotiateResponse( SmbTransport.ServerData server ) { + this.server = server; } int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) { @@ -54,74 +40,66 @@ class SmbComNegotiateResponse extends ServerMessageBlock { int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) { int start = bufferIndex; - dialectIndex = readInt2( buffer, bufferIndex ); - bufferIndex += 2; + + dialectIndex = readInt2( buffer, bufferIndex ); bufferIndex += 2; if( dialectIndex > 10 ) { return bufferIndex - start; } - securityMode = buffer[bufferIndex++] & 0xFF; - security = securityMode & 0x01; - encryptedPasswords = ( securityMode & 0x02 ) == 0x02 ? true : false; - signaturesEnabled = ( securityMode & 0x04 ) == 0x04 ? true : false; - signaturesRequired = ( securityMode & 0x08 ) == 0x08 ? true : false; - maxMpxCount = readInt2( buffer, bufferIndex ); - bufferIndex += 2; - maxNumberVcs = readInt2( buffer, bufferIndex ); - bufferIndex += 2; - maxBufferSize = readInt4( buffer, bufferIndex ); - bufferIndex += 4; - maxRawSize = readInt4( buffer, bufferIndex ); - bufferIndex += 4; - sessionKey = readInt4( buffer, bufferIndex ); - bufferIndex += 4; - capabilities = readInt4( buffer, bufferIndex ); - bufferIndex += 4; - serverTime = readTime( buffer, bufferIndex ); - bufferIndex += 8; - serverTimeZone = readInt2( buffer, bufferIndex ); - bufferIndex += 2; - encryptionKeyLength = buffer[bufferIndex++] & 0xFF; + server.securityMode = buffer[bufferIndex++] & 0xFF; + server.security = server.securityMode & 0x01; + server.encryptedPasswords = ( server.securityMode & 0x02 ) == 0x02; + server.signaturesEnabled = ( server.securityMode & 0x04 ) == 0x04; + server.signaturesRequired = ( server.securityMode & 0x08 ) == 0x08; + server.maxMpxCount = readInt2( buffer, bufferIndex ); bufferIndex += 2; + server.maxNumberVcs = readInt2( buffer, bufferIndex ); bufferIndex += 2; + server.maxBufferSize = readInt4( buffer, bufferIndex ); bufferIndex += 4; + server.maxRawSize = readInt4( buffer, bufferIndex ); bufferIndex += 4; + server.sessionKey = readInt4( buffer, bufferIndex ); bufferIndex += 4; + server.capabilities = readInt4( buffer, bufferIndex ); bufferIndex += 4; + server.serverTime = readTime( buffer, bufferIndex ); bufferIndex += 8; + server.serverTimeZone = readInt2( buffer, bufferIndex ); bufferIndex += 2; + server.encryptionKeyLength = buffer[bufferIndex++] & 0xFF; + return bufferIndex - start; } int readBytesWireFormat( byte[] buffer, int bufferIndex ) { int start = bufferIndex; - encryptionKey = new byte[encryptionKeyLength]; - System.arraycopy( buffer, bufferIndex, - encryptionKey, 0, encryptionKeyLength ); - bufferIndex += encryptionKeyLength; - if( byteCount > encryptionKeyLength ) { + server.encryptionKey = new byte[server.encryptionKeyLength]; + System.arraycopy( buffer, bufferIndex, + server.encryptionKey, 0, server.encryptionKeyLength ); + bufferIndex += server.encryptionKeyLength; + if( byteCount > server.encryptionKeyLength ) { int len = 0; - if(( flags2 & FLAGS2_UNICODE ) == FLAGS2_UNICODE ) { - while( buffer[bufferIndex + len] != (byte)0x00 || - buffer[bufferIndex + len + 1] != (byte)0x00 ) { - len += 2; - if( len > 256 ) { - throw new RuntimeException( "zero termination not found" ); + try { + if(( flags2 & FLAGS2_UNICODE ) == FLAGS2_UNICODE ) { + while( buffer[bufferIndex + len] != (byte)0x00 || + buffer[bufferIndex + len + 1] != (byte)0x00 ) { + len += 2; + if( len > 256 ) { + throw new RuntimeException( "zero termination not found" ); + } } - } - try { - oemDomainName = new String( buffer, bufferIndex, len, "UnicodeLittle" ); - } catch( UnsupportedEncodingException uee ) { - if( log.level > 1 ) - uee.printStackTrace( log ); - } - } else { - while( buffer[bufferIndex + len] != (byte)0x00 ) { - len++; - if( len > 256 ) { - throw new RuntimeException( "zero termination not found" ); + server.oemDomainName = new String( buffer, bufferIndex, + len, "UnicodeLittle" ); + } else { + while( buffer[bufferIndex + len] != (byte)0x00 ) { + len++; + if( len > 256 ) { + throw new RuntimeException( "zero termination not found" ); + } } + server.oemDomainName = new String( buffer, bufferIndex, + len, ServerMessageBlock.OEM_ENCODING ); } - try { - oemDomainName = new String( buffer, bufferIndex, len, ServerMessageBlock.OEM_ENCODING ); - } catch( UnsupportedEncodingException uee ) { - } + } catch( UnsupportedEncodingException uee ) { + if( log.level > 1 ) + uee.printStackTrace( log ); } bufferIndex += len; } else { - oemDomainName = new String(); + server.oemDomainName = new String(); } return bufferIndex - start; @@ -131,22 +109,23 @@ class SmbComNegotiateResponse extends ServerMessageBlock { super.toString() + ",wordCount=" + wordCount + ",dialectIndex=" + dialectIndex + - ",securityMode=0x" + Hexdump.toHexString( securityMode, 1 ) + - ",security=" + ( security == SECURITY_SHARE ? "share" : "user" ) + - ",encryptedPasswords=" + encryptedPasswords + - ",maxMpxCount=" + maxMpxCount + - ",maxNumberVcs=" + maxNumberVcs + - ",maxBufferSize=" + maxBufferSize + - ",maxRawSize=" + maxRawSize + - ",sessionKey=0x" + Hexdump.toHexString( sessionKey, 8 ) + - ",capabilities=0x" + Hexdump.toHexString( capabilities, 8 ) + - ",serverTime=" + new Date( serverTime ) + - ",serverTimeZone=" + serverTimeZone + - ",encryptionKeyLength=" + encryptionKeyLength + + ",securityMode=0x" + Hexdump.toHexString( server.securityMode, 1 ) + + ",security=" + ( server.security == SECURITY_SHARE ? "share" : "user" ) + + ",encryptedPasswords=" + server.encryptedPasswords + + ",maxMpxCount=" + server.maxMpxCount + + ",maxNumberVcs=" + server.maxNumberVcs + + ",maxBufferSize=" + server.maxBufferSize + + ",maxRawSize=" + server.maxRawSize + + ",sessionKey=0x" + Hexdump.toHexString( server.sessionKey, 8 ) + + ",capabilities=0x" + Hexdump.toHexString( server.capabilities, 8 ) + + ",serverTime=" + new Date( server.serverTime ) + + ",serverTimeZone=" + server.serverTimeZone + + ",encryptionKeyLength=" + server.encryptionKeyLength + ",byteCount=" + byteCount + - ",encryptionKey=0x" + Hexdump.toHexString( encryptionKey, + ",encryptionKey=0x" + Hexdump.toHexString( server.encryptionKey, 0, - encryptionKeyLength * 2 ) + - ",oemDomainName=" + oemDomainName + "]" ); + server.encryptionKeyLength * 2 ) + + ",oemDomainName=" + server.oemDomainName + "]" ); } } + diff --git a/src/jcifs/smb/SmbComOpenAndX.java b/src/jcifs/smb/SmbComOpenAndX.java index 88c8431..8d352fb 100644 --- a/src/jcifs/smb/SmbComOpenAndX.java +++ b/src/jcifs/smb/SmbComOpenAndX.java @@ -19,8 +19,6 @@ package jcifs.smb; import java.util.Date; -import java.io.IOException; -import java.io.InputStream; import jcifs.Config; import jcifs.util.Hexdump; @@ -145,10 +143,6 @@ class SmbComOpenAndX extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComOpenAndX[" + super.toString() + diff --git a/src/jcifs/smb/SmbComOpenAndXResponse.java b/src/jcifs/smb/SmbComOpenAndXResponse.java index 3fd6123..a3a813c 100644 --- a/src/jcifs/smb/SmbComOpenAndXResponse.java +++ b/src/jcifs/smb/SmbComOpenAndXResponse.java @@ -69,10 +69,6 @@ class SmbComOpenAndXResponse extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComOpenAndXResponse[" + super.toString() + diff --git a/src/jcifs/smb/SmbComReadAndX.java b/src/jcifs/smb/SmbComReadAndX.java index 7c920f0..46176c6 100644 --- a/src/jcifs/smb/SmbComReadAndX.java +++ b/src/jcifs/smb/SmbComReadAndX.java @@ -19,8 +19,6 @@ package jcifs.smb; import jcifs.Config; -import java.io.InputStream; -import java.io.IOException; class SmbComReadAndX extends AndXServerMessageBlock { @@ -84,10 +82,6 @@ class SmbComReadAndX extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComReadAndX[" + super.toString() + diff --git a/src/jcifs/smb/SmbComReadAndXResponse.java b/src/jcifs/smb/SmbComReadAndXResponse.java index 397dea4..e027319 100644 --- a/src/jcifs/smb/SmbComReadAndXResponse.java +++ b/src/jcifs/smb/SmbComReadAndXResponse.java @@ -18,15 +18,10 @@ package jcifs.smb; -import java.io.IOException; -import java.io.InputStream; - class SmbComReadAndXResponse extends AndXServerMessageBlock { - private int dataCompactionMode, dataOffset; - byte[] b; - int dataLength, off; + int off, dataCompactionMode, dataLength, dataOffset; SmbComReadAndXResponse() { } @@ -59,15 +54,9 @@ class SmbComReadAndXResponse extends AndXServerMessageBlock { return bufferIndex - start; } int readBytesWireFormat( byte[] buffer, int bufferIndex ) { + // handled special in SmbTransport.doRecv() return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - int pad = dataOffset - ( HEADER_LENGTH + 3 + wordCount * 2 ); - in.read( buffer, bufferIndex, pad ); /* needed for signing */ - in.read( b, off, dataLength ); - return pad + dataLength; - } public String toString() { return new String( "SmbComReadAndXResponse[" + super.toString() + diff --git a/src/jcifs/smb/SmbComSessionSetupAndX.java b/src/jcifs/smb/SmbComSessionSetupAndX.java index 655c750..4c4bd18 100644 --- a/src/jcifs/smb/SmbComSessionSetupAndX.java +++ b/src/jcifs/smb/SmbComSessionSetupAndX.java @@ -19,8 +19,6 @@ package jcifs.smb; import jcifs.Config; -import java.io.IOException; -import java.io.InputStream; class SmbComSessionSetupAndX extends AndXServerMessageBlock { @@ -140,10 +138,6 @@ class SmbComSessionSetupAndX extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { String result = new String( "SmbComSessionSetupAndX[" + super.toString() + diff --git a/src/jcifs/smb/SmbComSessionSetupAndXResponse.java b/src/jcifs/smb/SmbComSessionSetupAndXResponse.java index f4c6e94..37748c7 100644 --- a/src/jcifs/smb/SmbComSessionSetupAndXResponse.java +++ b/src/jcifs/smb/SmbComSessionSetupAndXResponse.java @@ -18,12 +18,8 @@ package jcifs.smb; -import java.io.IOException; -import java.io.InputStream; import java.io.UnsupportedEncodingException; -import jcifs.util.Hexdump; - class SmbComSessionSetupAndXResponse extends AndXServerMessageBlock { private String nativeOs = ""; @@ -65,7 +61,6 @@ class SmbComSessionSetupAndXResponse extends AndXServerMessageBlock { while( buffer[bufferIndex + len] != (byte)0x00 ) { len += 2; if( len > 256 ) { -Hexdump.hexdump( System.err, buffer, 0, 256 ); throw new RuntimeException( "zero termination not found" ); } } @@ -83,10 +78,6 @@ Hexdump.hexdump( System.err, buffer, 0, 256 ); return bufferIndex - start; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { String result = new String( "SmbComSessionSetupAndXResponse[" + super.toString() + diff --git a/src/jcifs/smb/SmbComTransactionResponse.java b/src/jcifs/smb/SmbComTransactionResponse.java index db7f9db..f421b97 100644 --- a/src/jcifs/smb/SmbComTransactionResponse.java +++ b/src/jcifs/smb/SmbComTransactionResponse.java @@ -58,13 +58,14 @@ abstract class SmbComTransactionResponse extends ServerMessageBlock implements E txn_buf = null; } - public void reset() { + void reset() { bufDataStart = 0; isPrimary = hasMore = true; parametersDone = dataDone = false; + received = false; } public boolean hasMoreElements() { - return hasMore; + return errorCode == 0 && hasMore; } public Object nextElement() { if( isPrimary ) { @@ -135,8 +136,7 @@ abstract class SmbComTransactionResponse extends ServerMessageBlock implements E parametersDone = true; } - if( !dataDone && - ( dataDisplacement + dataCount ) == totalDataCount) { + if( !dataDone && ( dataDisplacement + dataCount ) == totalDataCount) { dataDone = true; } diff --git a/src/jcifs/smb/SmbComTreeConnectAndX.java b/src/jcifs/smb/SmbComTreeConnectAndX.java index 13ae5a5..1c8ea57 100644 --- a/src/jcifs/smb/SmbComTreeConnectAndX.java +++ b/src/jcifs/smb/SmbComTreeConnectAndX.java @@ -19,8 +19,6 @@ package jcifs.smb; import jcifs.Config; -import java.io.IOException; -import java.io.InputStream; import java.io.UnsupportedEncodingException; import jcifs.util.Hexdump; @@ -172,10 +170,6 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { String result = new String( "SmbComTreeConnectAndX[" + super.toString() + diff --git a/src/jcifs/smb/SmbComTreeConnectAndXResponse.java b/src/jcifs/smb/SmbComTreeConnectAndXResponse.java index 5704c2d..8116089 100644 --- a/src/jcifs/smb/SmbComTreeConnectAndXResponse.java +++ b/src/jcifs/smb/SmbComTreeConnectAndXResponse.java @@ -18,8 +18,6 @@ package jcifs.smb; -import java.io.IOException; -import java.io.InputStream; import java.io.UnsupportedEncodingException; class SmbComTreeConnectAndXResponse extends AndXServerMessageBlock { @@ -63,10 +61,6 @@ class SmbComTreeConnectAndXResponse extends AndXServerMessageBlock { return bufferIndex - start; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { String result = new String( "SmbComTreeConnectAndXResponse[" + super.toString() + diff --git a/src/jcifs/smb/SmbComWrite.java b/src/jcifs/smb/SmbComWrite.java index f17eda7..98e253e 100644 --- a/src/jcifs/smb/SmbComWrite.java +++ b/src/jcifs/smb/SmbComWrite.java @@ -19,8 +19,6 @@ package jcifs.smb; import jcifs.Config; -import java.io.IOException; -import java.io.InputStream; class SmbComWrite extends ServerMessageBlock { @@ -85,9 +83,6 @@ class SmbComWrite extends ServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComWrite[" + super.toString() + diff --git a/src/jcifs/smb/SmbComWriteAndX.java b/src/jcifs/smb/SmbComWriteAndX.java index a64de35..796e0bc 100644 --- a/src/jcifs/smb/SmbComWriteAndX.java +++ b/src/jcifs/smb/SmbComWriteAndX.java @@ -19,8 +19,6 @@ package jcifs.smb; import jcifs.Config; -import java.io.IOException; -import java.io.InputStream; class SmbComWriteAndX extends AndXServerMessageBlock { @@ -123,10 +121,6 @@ class SmbComWriteAndX extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComWriteAndX[" + super.toString() + diff --git a/src/jcifs/smb/SmbComWriteAndXResponse.java b/src/jcifs/smb/SmbComWriteAndXResponse.java index db6d880..692d832 100644 --- a/src/jcifs/smb/SmbComWriteAndXResponse.java +++ b/src/jcifs/smb/SmbComWriteAndXResponse.java @@ -18,9 +18,6 @@ package jcifs.smb; -import java.io.IOException; -import java.io.InputStream; - class SmbComWriteAndXResponse extends AndXServerMessageBlock { long count; @@ -41,10 +38,6 @@ class SmbComWriteAndXResponse extends AndXServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount, - byte[] buffer, int bufferIndex ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComWriteAndXResponse[" + super.toString() + diff --git a/src/jcifs/smb/SmbComWriteResponse.java b/src/jcifs/smb/SmbComWriteResponse.java index e263395..368c4dd 100644 --- a/src/jcifs/smb/SmbComWriteResponse.java +++ b/src/jcifs/smb/SmbComWriteResponse.java @@ -18,9 +18,6 @@ package jcifs.smb; -import java.io.IOException; -import java.io.InputStream; - class SmbComWriteResponse extends ServerMessageBlock { long count; @@ -41,9 +38,6 @@ class SmbComWriteResponse extends ServerMessageBlock { int readBytesWireFormat( byte[] buffer, int bufferIndex ) { return 0; } - int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException { - return 0; - } public String toString() { return new String( "SmbComWriteResponse[" + super.toString() + diff --git a/src/jcifs/smb/SmbConstants.java b/src/jcifs/smb/SmbConstants.java new file mode 100644 index 0000000..b545a5b --- /dev/null +++ b/src/jcifs/smb/SmbConstants.java @@ -0,0 +1,137 @@ +package jcifs.smb; + +import java.util.LinkedList; +import java.net.InetAddress; +import java.util.TimeZone; +import jcifs.Config; + +interface SmbConstants { + + static final int DEFAULT_PORT = 445; + + static final int DEFAULT_MAX_MPX_COUNT = 10; + static final int DEFAULT_RESPONSE_TIMEOUT = 10000; + static final int DEFAULT_SO_TIMEOUT = 15000; + static final int DEFAULT_RCV_BUF_SIZE = 60416; + static final int DEFAULT_SND_BUF_SIZE = 16644; + static final int DEFAULT_SSN_LIMIT = 250; + + static final InetAddress LADDR = Config.getLocalHost(); + static final int LPORT = Config.getInt( "jcifs.smb.client.lport", 0 ); + static final int MAX_MPX_COUNT = Config.getInt( "jcifs.smb.client.maxMpxCount", DEFAULT_MAX_MPX_COUNT ); + static final int SND_BUF_SIZE = Config.getInt( "jcifs.smb.client.snd_buf_size", DEFAULT_SND_BUF_SIZE ); + static final int RCV_BUF_SIZE = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE ); + static final boolean USE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", true ); + static final boolean FORCE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", false ); + static final boolean USE_NTSTATUS = Config.getBoolean( "jcifs.smb.client.useNtStatus", true ); + static final boolean SIGNPREF = Config.getBoolean("jcifs.smb.client.signingPreferred", false ); + 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 int FLAGS_NONE = 0x00; + static final int FLAGS_LOCK_AND_READ_WRITE_AND_UNLOCK = 0x01; + static final int FLAGS_RECEIVE_BUFFER_POSTED = 0x02; + static final int FLAGS_PATH_NAMES_CASELESS = 0x08; + static final int FLAGS_PATH_NAMES_CANONICALIZED = 0x10; + static final int FLAGS_OPLOCK_REQUESTED_OR_GRANTED = 0x20; + static final int FLAGS_NOTIFY_OF_MODIFY_ACTION = 0x40; + static final int FLAGS_RESPONSE = 0x80; + + static final int FLAGS2_NONE = 0x0000; + static final int FLAGS2_LONG_FILENAMES = 0x0001; + static final int FLAGS2_EXTENDED_ATTRIBUTES = 0x0002; + static final int FLAGS2_SECURITY_SIGNATURES = 0x0004; + static final int FLAGS2_EXTENDED_SECURITY_NEGOTIATION = 0x0800; + static final int FLAGS2_RESOLVE_PATHS_IN_DFS = 0x1000; + static final int FLAGS2_PERMIT_READ_IF_EXECUTE_PERM = 0x2000; + static final int FLAGS2_STATUS32 = 0x4000; + static final int FLAGS2_UNICODE = 0x8000; + + static final int CAP_NONE = 0x0000; + static final int CAP_RAW_MODE = 0x0001; + static final int CAP_MPX_MODE = 0x0002; + static final int CAP_UNICODE = 0x0004; + static final int CAP_LARGE_FILES = 0x0008; + static final int CAP_NT_SMBS = 0x0010; + static final int CAP_RPC_REMOTE_APIS = 0x0020; + static final int CAP_STATUS32 = 0x0040; + static final int CAP_LEVEL_II_OPLOCKS = 0x0080; + static final int CAP_LOCK_AND_READ = 0x0100; + static final int CAP_NT_FIND = 0x0200; + static final int CAP_DFS = 0x1000; + + // file attribute encoding + static final int ATTR_READONLY = 0x01; + static final int ATTR_HIDDEN = 0x02; + static final int ATTR_SYSTEM = 0x04; + static final int ATTR_VOLUME = 0x08; + static final int ATTR_DIRECTORY = 0x10; + static final int ATTR_ARCHIVE = 0x20; + + // extended file attribute encoding(others same as above) + static final int ATTR_COMPRESSED = 0x800; + static final int ATTR_NORMAL = 0x080; + static final int ATTR_TEMPORARY = 0x100; + + // flags for move and copy + static final int FLAGS_TARGET_MUST_BE_FILE = 0x0001; + static final int FLAGS_TARGET_MUST_BE_DIRECTORY = 0x0002; + static final int FLAGS_COPY_TARGET_MODE_ASCII = 0x0004; + static final int FLAGS_COPY_SOURCE_MODE_ASCII = 0x0008; + static final int FLAGS_VERIFY_ALL_WRITES = 0x0010; + static final int FLAGS_TREE_COPY = 0x0020; + + // open function + static final int OPEN_FUNCTION_FAIL_IF_EXISTS = 0x0000; + static final int OPEN_FUNCTION_OVERWRITE_IF_EXISTS = 0x0020; + + static final int PID = (int)( Math.random() * 65536d ); + + static final int SECURITY_SHARE = 0x00; + static final int SECURITY_USER = 0x01; + + static final int CMD_OFFSET = 4; + static final int ERROR_CODE_OFFSET = 5; + static final int FLAGS_OFFSET = 9; + static final int SIGNATURE_OFFSET = 14; + static final int TID_OFFSET = 24; + static final int HEADER_LENGTH = 32; + + static final long MILLISECONDS_BETWEEN_1970_AND_1601 = 11644473600000L; + static final TimeZone TZ = TimeZone.getDefault(); + + static final boolean USE_BATCHING = Config.getBoolean( "jcifs.smb.client.useBatching", true ); + static final String OEM_ENCODING = + Config.getProperty( "jcifs.encoding", + System.getProperty( "file.encoding" )); + static final int DEFAULT_FLAGS2 = + FLAGS2_LONG_FILENAMES | + FLAGS2_EXTENDED_ATTRIBUTES | + ( USE_EXTSEC ? FLAGS2_EXTENDED_SECURITY_NEGOTIATION : 0 ) | + ( SIGNPREF ? FLAGS2_SECURITY_SIGNATURES : 0 ) | + ( USE_NTSTATUS ? FLAGS2_STATUS32 : 0 ) | + ( USE_UNICODE ? FLAGS2_UNICODE : 0 ); + static final int DEFAULT_CAPABILITIES = + ( USE_NTSMBS ? CAP_NT_SMBS : 0 ) | + ( USE_NTSTATUS ? CAP_STATUS32 : 0 ) | + ( USE_UNICODE ? CAP_UNICODE : 0 ) | + CAP_DFS; + static final int FLAGS2 = Config.getInt( "jcifs.smb.client.flags2", DEFAULT_FLAGS2 ); + static final int CAPABILITIES = Config.getInt( "jcifs.smb.client.capabilities", DEFAULT_CAPABILITIES ); + static final boolean TCP_NODELAY = Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false ); + static final int RESPONSE_TIMEOUT = + Config.getInt( "jcifs.smb.client.responseTimeout", DEFAULT_RESPONSE_TIMEOUT ); + + static final LinkedList CONNECTIONS = new LinkedList(); + + static final int SSN_LIMIT = + Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT ); + static final int SO_TIMEOUT = + Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT ); + 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( null, 0, null, 0 ); +} diff --git a/src/jcifs/smb/SmbFile.java b/src/jcifs/smb/SmbFile.java index 9675d0f..c77fdae 100644 --- a/src/jcifs/smb/SmbFile.java +++ b/src/jcifs/smb/SmbFile.java @@ -653,8 +653,8 @@ public class SmbFile extends URLConnection { } return blank_resp; } - void sendTransaction( SmbComTransaction request, - SmbComTransactionResponse response ) throws SmbException { + void send( ServerMessageBlock request, + ServerMessageBlock response ) throws SmbException { for( ;; ) { connect0(); if( tree.inDfs ) { @@ -669,9 +669,9 @@ public class SmbFile extends URLConnection { throw new SmbException( dr.server, uhe ); } - trans = SmbTransport.getSmbTransport( addr, 0 ); + trans = SmbTransport.getSmbTransport( addr, url.getPort() ); tree = trans.getSmbSession( auth ).getSmbTree( dr.share, null ); - unc = dr.nodepath + unc.substring( dr.path.length() ); + unc = request.path = dr.nodepath + unc.substring( dr.path.length() ); if( request.path.charAt( request.path.length() - 1 ) == '\\' ) { request.path = unc + '\\'; } else { @@ -679,44 +679,6 @@ public class SmbFile extends URLConnection { } dfsReferral = dr; /* for getDfsPath */ } - } - if( tree.inDfs ) { - request.flags2 |= ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS; - } else { - request.flags2 &= ~ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS; - } - try { - tree.sendTransaction( request, response ); - break; - } catch( DfsReferral dr ) { - if( dr.resolveHashes ) { - throw dr; - } - request.reset(); - } - } - } - void send( ServerMessageBlock request, - ServerMessageBlock response ) throws SmbException { - for( ;; ) { - connect0(); - if( tree.inDfs ) { - DfsReferral dr = tree.session.transport.lookupReferral( unc ); - if( dr != null ) { - UniAddress addr; - SmbTransport trans; - - try { - addr = UniAddress.getByName( dr.server ); - } catch( UnknownHostException uhe ) { - throw new SmbException( dr.server, uhe ); - } - - trans = SmbTransport.getSmbTransport( addr, url.getPort() ); - tree = trans.getSmbSession( auth ).getSmbTree( dr.share, null ); - unc = request.path = dr.nodepath + unc.substring( dr.path.length() ); - dfsReferral = dr; /* for getDfsPath */ - } request.flags2 |= ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS; } else { request.flags2 &= ~ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS; @@ -728,6 +690,7 @@ public class SmbFile extends URLConnection { if( dr.resolveHashes ) { throw dr; } + request.reset(); } } } @@ -1227,8 +1190,7 @@ public class SmbFile extends URLConnection { Trans2QueryPathInformationResponse response = new Trans2QueryPathInformationResponse( infoLevel ); - sendTransaction( new Trans2QueryPathInformation( path, - infoLevel ), response ); + send( new Trans2QueryPathInformation( path, infoLevel ), response ); return response.info; } else { @@ -1652,7 +1614,7 @@ public class SmbFile extends URLConnection { do { int n; - sendTransaction( req, resp ); + send( req, resp ); more = resp.status == SmbException.ERROR_MORE_DATA; @@ -1712,7 +1674,7 @@ public class SmbFile extends URLConnection { if( log.level > 2 ) log.println( "doFindFirstNext: " + req.path ); - sendTransaction( req, resp ); + send( req, resp ); sid = resp.sid; req = new Trans2FindNext2( sid, resp.resumeKey, resp.lastName ); @@ -1755,7 +1717,7 @@ public class SmbFile extends URLConnection { req.reset( resp.resumeKey, resp.lastName ); resp.reset(); - sendTransaction( req, resp ); + send( req, resp ); } send( new SmbComFindClose2( sid ), blank_resp() ); @@ -1976,7 +1938,7 @@ try { off += resp.dataLength; } - dest.sendTransaction( new Trans2SetFileInformation( + dest.send( new Trans2SetFileInformation( dest.fid, attributes, createTime, lastModified ), new Trans2SetFileInformationResponse() ); dest.close( 0L ); @@ -2158,7 +2120,7 @@ try { int level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION; response = new Trans2QueryFSInformationResponse( level ); - sendTransaction( new Trans2QueryFSInformation( level ), response ); + send( new Trans2QueryFSInformation( level ), response ); size = response.info.getCapacity(); } else if( getUncPath0().length() > 1 && type != TYPE_NAMED_PIPE ) { @@ -2183,20 +2145,33 @@ try { */ public long getDiskFreeSpace() throws SmbException { if( getType() == TYPE_SHARE || type == TYPE_FILESYSTEM ) { - Trans2QueryFSInformationResponse response; - int level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION; + int level = Trans2QueryFSInformationResponse.SMB_FS_FULL_SIZE_INFORMATION; + try { + return queryFSInformation(level); + } catch( SmbException ex ) { + if(ex.getNtStatus() == NtStatus.NT_STATUS_INVALID_INFO_CLASS) { + // SMB_FS_FULL_SIZE_INFORMATION not supported by the server. + level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION; + return queryFSInformation(level); + } + throw ex; + } + } + return 0L; + } - response = new Trans2QueryFSInformationResponse( level ); - sendTransaction( new Trans2QueryFSInformation( level ), response ); + private long queryFSInformation( int level ) throws SmbException { + Trans2QueryFSInformationResponse response; - if( type == TYPE_SHARE ) { - size = response.info.getCapacity(); - sizeExpiration = System.currentTimeMillis() + attrExpirationPeriod; - } + response = new Trans2QueryFSInformationResponse( level ); + send( new Trans2QueryFSInformation( level ), response ); - return response.info.getFree(); + if( type == TYPE_SHARE ) { + size = response.info.getCapacity(); + sizeExpiration = System.currentTimeMillis() + attrExpirationPeriod; } - return 0L; + + return response.info.getFree(); } /** @@ -2273,7 +2248,7 @@ try { } f = open0( O_RDONLY | SmbComNTCreateAndX.FILE_WRITE_ATTRIBUTES << 16, attrs, options ); - sendTransaction( new Trans2SetFileInformation( f, attrs, ctime, mtime ), + send( new Trans2SetFileInformation( f, attrs, ctime, mtime ), new Trans2SetFileInformationResponse() ); close( f, 0L ); diff --git a/src/jcifs/smb/SmbFileInputStream.java b/src/jcifs/smb/SmbFileInputStream.java index 2acaf49..70133dc 100644 --- a/src/jcifs/smb/SmbFileInputStream.java +++ b/src/jcifs/smb/SmbFileInputStream.java @@ -65,7 +65,11 @@ public class SmbFileInputStream extends InputStream { SmbFileInputStream( SmbFile file, int openFlags ) throws SmbException, MalformedURLException, UnknownHostException { this.file = file; this.openFlags = openFlags; - file.open( openFlags, SmbFile.ATTR_NORMAL, 0 ); + if (file.type != SmbFile.TYPE_NAMED_PIPE) { + file.open( openFlags, SmbFile.ATTR_NORMAL, 0 ); + } else { + file.connect0(); + } readSize = Math.min( file.tree.session.transport.rcv_buf_size - 70, file.tree.session.transport.server.maxBufferSize - 70 ); } @@ -184,7 +188,7 @@ public class SmbFileInputStream extends InputStream { req = new TransPeekNamedPipe( file.unc, file.fid ); resp = new TransPeekNamedPipeResponse( pipe ); - pipe.sendTransaction( req, resp ); + pipe.send( req, resp ); if( resp.status == TransPeekNamedPipeResponse.STATUS_DISCONNECTED || resp.status == TransPeekNamedPipeResponse.STATUS_SERVER_END_CLOSED ) { file.opened = false; diff --git a/src/jcifs/smb/SmbFileOutputStream.java b/src/jcifs/smb/SmbFileOutputStream.java index cb3d658..8f7c6c8 100644 --- a/src/jcifs/smb/SmbFileOutputStream.java +++ b/src/jcifs/smb/SmbFileOutputStream.java @@ -133,11 +133,10 @@ write, and/or delete the file while the jCIFS user has the file open. } if( file instanceof SmbNamedPipe && file.unc.startsWith( "\\pipe\\" )) { file.unc = file.unc.substring( 5 ); - file.sendTransaction( new TransWaitNamedPipe( "\\pipe" + file.unc ), + file.send( new TransWaitNamedPipe( "\\pipe" + file.unc ), new TransWaitNamedPipeResponse() ); } file.open( openFlags, SmbFile.ATTR_NORMAL, 0 ); - this.openFlags &= ~(SmbFile.O_CREAT | SmbFile.O_TRUNC); /* in case close and reopen */ writeSize = file.tree.session.transport.snd_buf_size - 70; useNTSmbs = file.tree.session.transport.hasCapability( ServerMessageBlock.CAP_NT_SMBS ); @@ -203,7 +202,7 @@ write, and/or delete the file while the jCIFS user has the file open. // ensure file is open if( file.isOpen() == false ) { if( file instanceof SmbNamedPipe ) { - file.sendTransaction( new TransWaitNamedPipe( "\\pipe" + file.unc ), + file.send( new TransWaitNamedPipe( "\\pipe" + file.unc ), new TransWaitNamedPipeResponse() ); } file.open( openFlags, SmbFile.ATTR_NORMAL, 0 ); diff --git a/src/jcifs/smb/SmbSession.java b/src/jcifs/smb/SmbSession.java index dc5dd15..0af140c 100644 --- a/src/jcifs/smb/SmbSession.java +++ b/src/jcifs/smb/SmbSession.java @@ -71,7 +71,7 @@ public final class SmbSession { UniAddress dc = new UniAddress( addr ); SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 ); if (USERNAME == null) { - trans.negotiate(); + trans.connect(); if (SmbTransport.log.level > 2) SmbTransport.log.println( "Default credentials (jcifs.smb.client.username/password)" + @@ -133,7 +133,7 @@ public final class SmbSession { public static byte[] getChallenge( UniAddress dc, int port ) throws SmbException, UnknownHostException { SmbTransport trans = SmbTransport.getSmbTransport( dc, port ); - trans.negotiate(); + trans.connect(); return trans.server.encryptionKey; } /** @@ -160,7 +160,7 @@ public final class SmbSession { } else { Trans2FindFirst2 req = new Trans2FindFirst2( "\\", "*", SmbFile.ATTR_DIRECTORY ); Trans2FindFirst2Response resp = new Trans2FindFirst2Response(); - tree.sendTransaction( req, resp ); + tree.send( req, resp ); } } @@ -212,14 +212,6 @@ public final class SmbSession { } return transport; } - void sendTransaction( SmbComTransaction request, - SmbComTransactionResponse response ) throws SmbException { - // transactions are not batchable - sessionSetup( null, null ); - request.uid = uid; - request.auth = auth; - transport().sendTransaction( request, response ); - } void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { if( response != null ) { @@ -236,14 +228,14 @@ public final class SmbSession { void sessionSetup( ServerMessageBlock andx, ServerMessageBlock andxResponse ) throws SmbException { - expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT; - synchronized( transport() ) { if( sessionSetup ) { return; } - transport.negotiate(); + expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT; + + transport.connect(); /* * Session Setup And X Request / Response @@ -296,11 +288,7 @@ synchronized( transport ) { t.treeDisconnect( inError ); } - if( transport.server.security == ServerMessageBlock.SECURITY_SHARE ) { - return; - } - - if( !inError ) { + if( !inError && transport.server.security != ServerMessageBlock.SECURITY_SHARE ) { /* * Logoff And X Request / Response @@ -313,6 +301,7 @@ synchronized( transport ) { } catch( SmbException se ) { } } + sessionSetup = false; } finally { transport = SmbTransport.NULL_TRANSPORT; diff --git a/src/jcifs/smb/SmbTransport.java b/src/jcifs/smb/SmbTransport.java index c8b2621..dd440a0 100644 --- a/src/jcifs/smb/SmbTransport.java +++ b/src/jcifs/smb/SmbTransport.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * Copyright (C) 2005 "Michael B. Allen" * "Eric Glass" * * This library is free software; you can redistribute it and/or @@ -19,126 +19,53 @@ package jcifs.smb; -import jcifs.netbios.NbtSocket; -import jcifs.netbios.NbtException; -import jcifs.netbios.NbtAddress; -import jcifs.UniAddress; -import jcifs.Config; -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.SocketException; -import java.net.UnknownHostException; - -import java.security.MessageDigest; - -import java.util.Arrays; -import java.util.LinkedList; -import java.util.ListIterator; -import java.util.Enumeration; -import java.util.HashMap; - -import jcifs.util.LogStream; -import jcifs.util.Hexdump; - -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 = 16644; - 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 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 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 LinkedList CONNECTIONS = new LinkedList(); - private static final int MAGIC[] = { 0xFF, 'S', 'M', 'B' }; - - private static final int ST_GROUND = 0; - private static final int ST_NEGOTIATING = 1; - private static final int ST_NEGOTIATED = 2; - -private static byte[] snd_buf = new byte[0xFFFF]; -private static byte[] rcv_buf = new byte[0xFFFF]; - - private int state; - 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 referrals = new LinkedList(); - private Mid[] mids = new Mid[MAX_MPX_COUNT]; - private short mid_next; - private IOException socketException; - private long sessionExpiration = System.currentTimeMillis() + SO_TIMEOUT; - - static final int SSN_LIMIT = - Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT ); - static final int SO_TIMEOUT = - Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT ); - 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; +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 final SmbTransport NULL_TRANSPORT = new SmbTransport(); - class Mid { - short mid; + 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; - public int hashCode() { - return mid; - } - public boolean equals( Object obj ) { - return ((Mid)obj).mid == mid; + 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; - // NT 4 Workstation is 0x43FD int capabilities; String oemDomainName; int securityMode; @@ -154,6 +81,21 @@ private static byte[] rcv_buf = new byte[0xFFFF]; 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; @@ -162,53 +104,12 @@ private static byte[] rcv_buf = new byte[0xFFFF]; int sessionKey = 0x00000000; boolean useUnicode = USE_UNICODE; String tconHostName; - ServerData server; - SigningDigest digest = null; - LinkedList sessions; - - 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() { @@ -247,23 +148,20 @@ private static byte[] rcv_buf = new byte[0xFFFF]; 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; + int p1 = ( port == 0 || port == DEFAULT_PORT ) ? 0 : port; + int p2 = ( this.port == 0 || this.port == DEFAULT_PORT ) ? 0 : this.port; + InetAddress la1 = localAddr == null ? LADDR : localAddr; + InetAddress la2 = this.localAddr == null ? LADDR : 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(); + try { + connect( RESPONSE_TIMEOUT ); + } catch( IOException ioe ) { + throw new SmbException( "", ioe ); } return (capabilities & cap) == cap; } @@ -273,255 +171,370 @@ private static byte[] rcv_buf = new byte[0xFFFF]; auth != NtlmPasswordAuthentication.NULL && NtlmPasswordAuthentication.NULL.equals( auth ) == false; } - void tryClose( boolean inError ) { - SmbSession ssn; - if( socket == null ) { - inError = true; - } + void ssn139() throws IOException { + Name calledName = new Name( address.firstCalledName(), 0x20, null ); + do { + 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 ); - ListIterator iter = sessions.listIterator(); - while( iter.hasNext() ) { - ssn = (SmbSession)iter.next(); - ssn.logoff( inError ); - } - if( socket != null ) { - try { - socket.close(); - } catch( IOException ioe ) { + 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 (port == 139) { + ssn139(); + } 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. + */ + peekKey(); /* try to read header */ + 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 ); } - digest = null; - in = null; - out = null; - socket = null; - thread = null; - responseTable.clear(); - referrals.clear(); - sessions.clear(); - synchronized( CONNECTIONS ) { - CONNECTIONS.remove( this ); - } - state = ST_GROUND; } - void start() throws Exception { - thread = new Thread( this, "JCIFS-SmbTransport" ); - thread.setDaemon( true ); - thread.start(); - - wait( RESPONSE_TIMEOUT ); /* wait for the thread to be started and socket opened */ - - if( socket == null ) { /* failed to open socket for some reason */ - throw new SmbException( "Timeout trying to open socket", socketException ); + public void connect() throws SmbException { + try { + super.connect( RESPONSE_TIMEOUT ); + } catch( TransportException te ) { + throw new SmbException( "", te ); } } - public void run() { - Mid mid = new Mid(); - int i, m, nbtlen; - ServerMessageBlock response; + protected void doConnect() throws IOException { + /* + * Negotiate Protocol Request / Response + */ + SmbComNegotiateResponse resp = new SmbComNegotiateResponse( server ); try { - Object obj; - NbtAddress naddr; - String calledName; + negotiate( 445, resp ); + } catch( ConnectException ce ) { + negotiate( 139, resp ); + } - 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 - } - } + if( resp.dialectIndex > 10 ) { + throw new SmbException( "This client does not support the negotiated dialect." ); + } - calledName = address.firstCalledName(); - do { - try { - socket = new NbtSocket( naddr, calledName, port, localAddr, localPort ); - if( TCP_NODELAY ) { - socket.setTcpNoDelay( true ); - } - socket.setSoTimeout( SO_TIMEOUT ); - in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE ); - out = socket.getOutputStream(); - break; - } catch( NbtException ne ) { - if( ne.errorClass == NbtException.ERR_SSN_SRVC && - ( ne.errorCode == NbtException.CALLED_NOT_PRESENT || - ne.errorCode == NbtException.NOT_LISTENING_CALLED )) { - if( log.level > 2 ) - ne.printStackTrace( log ); - } else { - throw ne; - } - } - } while(( calledName = address.nextCalledName()) != null ); + /* Adjust negotiated values */ - if( socket == null ) { - throw new IOException( "Failed to establish session with " + address ); + 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 ); + iter.remove(); + } + out.close(); + in.close(); + socket.close(); + } - /* Save the calledName for using on SMB_COM_TREE_CONNECT + 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 { + n = readn( in, sbuf, 0, 4 ); + } while (sbuf[0] == 0x85); /* Dodge NetBIOS keep-alive */ + /* read smb header */ + if ((n = readn( in, sbuf, 4, 32 )) < 32) { + return null; /* stream closed */ + } + 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( calledName == NbtAddress.SMBSERVER_NAME ) { - tconHostName = address.getHostAddress(); - } else { - tconHostName = calledName; + + 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 */ } - } catch( IOException ioe ) { - socketException = ioe; - if( log.level > 1 ) - ioe.printStackTrace( log ); - return; - } finally { - synchronized( this ) { - notifyAll(); + /* out of phase maybe? */ + /* inch forward 1 byte and try again */ + for (int i = 0; i < 7; i++) { + sbuf[i] = sbuf[i + 1]; } + int b; + if ((b = in.read()) == 0) return null; + sbuf[7] = (byte)b; } - while( thread == Thread.currentThread() ) { - try { - 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; - } - } + key.mid = Encdec.dec_uint16le( sbuf, 34 ); - nbtlen = 4 + in.available(); + /* 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(). + */ -synchronized( rcv_buf ) { - rcv_buf[0] = (byte)0xFF; - rcv_buf[1] = (byte)'S'; - rcv_buf[2] = (byte)'M'; - rcv_buf[3] = (byte)'B'; + return key; + } - 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; + protected void doSend( Request request ) throws IOException { + synchronized (BUF) { + int n = ((ServerMessageBlock)request).encode( BUF, 4 ); + Encdec.enc_uint32be( n & 0xFFFF, BUF, 0 ); /* 4 byte session message header */ + out.write( BUF, 0, 4 + n ); + } + } + + 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 instanceof SmbComReadAndXResponse) { + 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 */ } - ((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( log.level > 1 ) - log.println( "bad smb header, purging session message: " + address ); - in.skip( in.available() ); - continue; + return; + } + readn( in, BUF, 4 + 32, size - 32 ); + resp.decode( BUF, 4 ); + if (resp instanceof SmbComTransactionResponse) { + ((SmbComTransactionResponse)resp).nextElement(); + } + } + } + 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 ); } - 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( log.level > 2 ) { - log.println( "no handler for mid=" + mid.mid + - ", purging session message: " + address ); + 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 ); + } + } + void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { + + connect(); /* must negotiate before we can test flags2, useUnicode, etc */ + + request.flags2 |= flags2; + request.useUnicode = useUnicode; + + try { + if (response == null) { + doSend( request ); + return; + } else if (request instanceof SmbComTransaction) { + 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 ); } - in.skip( in.available() ); - continue; + req.nextElement(); + } else { + makeKey( req ); } - synchronized( response ) { - response.useUnicode = useUnicode; - - if( log.level > 3 ) - log.println( "new data read from socket: " + address ); - - if( response instanceof SmbComTransactionResponse ) { - Enumeration e = (Enumeration)response; - if( e.hasMoreElements() ) { - e.nextElement(); - } else { - if( log.level > 2 ) - log.println( "more responses to transaction than expected" ); - continue; - } - if((m = response.readWireFormat( in, rcv_buf, 0 )) != nbtlen ) { - if( log.level > 1 ) { - log.println( "decoded " + m + " but nbtlen=" + - nbtlen + ", purging session message" ); - } - in.skip( in.available() ); - } - response.received = true; - if( log.level > 3 ) - log.println( response ); - - 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 { - response.readWireFormat( in, rcv_buf, 0 ); - response.received = true; - - if( log.level > 3 ) { - ServerMessageBlock smb = response; - - do { - log.println( smb ); - } while( smb instanceof AndXServerMessageBlock && - ( smb = ((AndXServerMessageBlock)smb).andx ) != null ); - if( log.level > 5 ) { - Hexdump.hexdump( log, rcv_buf, 0, Math.min( response.length, 1024 )); + synchronized (response_map) { + response.received = false; + resp.isReceived = false; + try { + response_map.put( req, resp ); + + /* + * Send multiple fragments + */ + + do { + doSend( 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( digest != null ) { - synchronized( outLock ) { - digest.verify(rcv_buf, 0, response); - } + if (response.errorCode != 0) { + checkStatus( req, resp ); } - - response.notify(); + } catch( InterruptedException ie ) { + throw new TransportException( ie ); + } finally { + response_map.remove( req ); } } - } else { - // it's a request(break oplock) - } -} - } catch( InterruptedIOException iioe ) { - if( responseTable.size() == 0 ) { - tryClose( false ); - } else if( log.level > 1 ) { - log.println( "soTimeout has occured but there are " + - responseTable.size() + " pending requests" ); - } - } catch( IOException ioe ) { - synchronized( this ) { - tryClose( true ); - } - if( log.level > 0 && - ioe.getMessage().startsWith( "Connection reset" ) == false ) { - log.println( ioe.getMessage() + ": " + address ); - ioe.printStackTrace( log ); + } finally { + BufferCache.releaseBuffer( req.txn_buf ); + BufferCache.releaseBuffer( resp.txn_buf ); } + + } else { + 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 + "]"; } - synchronized DfsReferral getDfsReferral( NtlmPasswordAuthentication auth, String path ) throws SmbException { + /* DFS */ + + synchronized DfsReferral getDfsReferral( NtlmPasswordAuthentication auth, + String path ) throws SmbException { String subpath, node, host; DfsReferral dr = new DfsReferral(); int p, n, i, s; @@ -529,7 +542,7 @@ synchronized( rcv_buf ) { SmbTree ipc = getSmbSession( auth ).getSmbTree( "IPC$", null ); Trans2GetDfsReferralResponse resp = new Trans2GetDfsReferralResponse(); - ipc.sendTransaction( new Trans2GetDfsReferral( path ), resp ); + ipc.send( new Trans2GetDfsReferral( path ), resp ); subpath = path.substring( 0, resp.pathConsumed ); node = resp.referral.node; @@ -574,434 +587,5 @@ synchronized( rcv_buf ) { return null; } - void send( ServerMessageBlock request, - ServerMessageBlock response ) throws SmbException { - Mid mid = null; - - if( request.command != request.SMB_COM_NEGOTIATE ) - negotiate(); - - request.flags2 |= flags2; - request.useUnicode = useUnicode; - - if( response == null ) { - synchronized( outLock ) { - try { - mid = aquireMid(); - request.mid = mid.mid; -synchronized( snd_buf ) { - request.digest = digest; - request.response = null; - int length = request.writeWireFormat(snd_buf, 4); - out.write(snd_buf, 4, length); - out.flush(); - - if( log.level > 3 ) { - ServerMessageBlock smb = request; - - do { - log.println( smb ); - } while( smb instanceof AndXServerMessageBlock && - ( smb = ((AndXServerMessageBlock)smb).andx ) != null ); - if( log.level > 5 ) { - Hexdump.hexdump( log, snd_buf, 0, Math.min( request.length, 1024 )); - } - } -} - } catch( IOException ioe ) { - tryClose( true ); - throw new SmbException( "An error occured sending the request.", ioe ); - } finally { - releaseMid( mid ); - } - } - - return; - } - - // now for the normal case where response is not null - - synchronized( response ) { - try { - synchronized( outLock ) { - response.received = false; - mid = aquireMid(); - request.mid = mid.mid; - responseTable.put( mid, response ); -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(); - - if( log.level > 3 ) { - ServerMessageBlock smb = request; - - do { - log.println( smb ); - } while( smb instanceof AndXServerMessageBlock && - ( smb = ((AndXServerMessageBlock)smb).andx ) != null ); - if( log.level > 5 ) { - Hexdump.hexdump( log, snd_buf, 0, request.length ); - } - } } - } - - // 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 { - responseTable.remove( mid ); - synchronized( outLock ) { - 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 { - synchronized( outLock ) { - mid = aquireMid(); - } - request.txn_buf = BufferCache.getBuffer(); - response.txn_buf = BufferCache.getBuffer(); - - request.nextElement(); - if( request.hasMoreElements() ) { - // multi-part request - - SmbComBlankResponse interimResponse = new SmbComBlankResponse(); - - synchronized( interimResponse ) { - try { - synchronized( outLock ) { - request.mid = mid.mid; - responseTable.put( mid, interimResponse ); -synchronized(snd_buf) { - request.digest = digest; - request.response = response; - int length = request.writeWireFormat(snd_buf, 4); - out.write(snd_buf, 4, length); - out.flush(); - - if( log.level > 3 ) { - log.println( request ); - if( log.level > 5 ) { - Hexdump.hexdump( log, snd_buf, 0, request.length ); - } - } -} - } - - 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 ); - } - } finally { - responseTable.remove( mid ); - } - } - - request.nextElement(); - } - - synchronized( response ) { - try { - synchronized( outLock ) { - request.mid = mid.mid; - responseTable.put( mid, response ); - do { -synchronized( snd_buf ) { - request.digest = digest; - request.response = response; - int length = request.writeWireFormat(snd_buf, 4); - out.write(snd_buf, 4, length); - out.flush(); - - if( log.level > 3 ) { - log.println( request ); - if( log.level > 5 ) { - Hexdump.hexdump( log, snd_buf, 0, request.length ); - } - } -} - } 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() ); - } finally { - responseTable.remove( mid ); - } - } - } catch( InterruptedException ie ) { - tryClose( true ); - } catch( IOException ioe ) { - tryClose( true ); - throw new SmbException( "An error occured sending the request.", ioe ); - } finally { - synchronized( outLock ) { - 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; - case 0x80000005: - break; - default: - throw new SmbException( response.errorCode, null ); - } - } - synchronized void negotiate0() throws Exception { - start(); /* start the transport thread (which opens the socket) */ - if( this == NULL_TRANSPORT ) { - throw new RuntimeException( "Null transport cannot be used" ); - } - - if( log.level > 2 ) - log.println( "requesting negotiation with " + address ); - - /* - * Negotiate Protocol Request / Response - */ - - SmbComNegotiateResponse response = new SmbComNegotiateResponse(); - send( new SmbComNegotiate(), response ); - - if( response.dialectIndex > 10 ) { - 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; - } - } - } - synchronized void negotiate() throws SmbException { - if( state == ST_GROUND ) { - state = ST_NEGOTIATING; - } else { - while( state != ST_NEGOTIATED ) { - try { - wait(); - } catch( InterruptedException ie ) { - tryClose( true ); - throw new SmbException( "Interrupted opening socket", ie ); - } - } - return; - } - - try { - negotiate0(); - state = ST_NEGOTIATED; - } catch( Exception ex ) { - if( log.level > 1 ) - ex.printStackTrace( log ); - tryClose( true ); - throw new SmbException( "Failed to negotiate", ex ); - } finally { - notifyAll(); - } - } - 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( log.level > 1 ) - log.println( "mid not found" ); - } -} diff --git a/src/jcifs/smb/SmbTree.java b/src/jcifs/smb/SmbTree.java index 7f032de..7e96d6e 100644 --- a/src/jcifs/smb/SmbTree.java +++ b/src/jcifs/smb/SmbTree.java @@ -26,12 +26,10 @@ import jcifs.Config; class SmbTree { - private static final String DEFAULT_SERVICE = Config.getProperty( "jcifs.smb.client.serviceType", "?????" ); - private int tid; private String share; - String service = DEFAULT_SERVICE; + String service = "?????"; SmbSession session; boolean treeConnected, inDfs; @@ -48,31 +46,6 @@ class SmbTree { ( service == null || service.startsWith( "??" ) || this.service.equalsIgnoreCase( service )); } - void sendTransaction( SmbComTransaction request, - SmbComTransactionResponse response ) throws SmbException { - // transactions are not batchable - treeConnect( null, null ); - if( service.equals( "A:" ) == false ) { - switch( ((SmbComTransaction)request).subCommand & 0xFF ) { - case SmbComTransaction.NET_SHARE_ENUM: - case SmbComTransaction.NET_SERVER_ENUM2: - case SmbComTransaction.NET_SERVER_ENUM3: - case SmbComTransaction.TRANS_PEEK_NAMED_PIPE: - case SmbComTransaction.TRANS_WAIT_NAMED_PIPE: - case SmbComTransaction.TRANS_CALL_NAMED_PIPE: - case SmbComTransaction.TRANS_TRANSACT_NAMED_PIPE: - case SmbComTransaction.TRANS2_GET_DFS_REFERRAL: - break; - default: - throw new SmbException( "Invalid operation for " + service + " service" ); - } - } - request.tid = tid; - if( inDfs && request.path != null && request.path.length() > 0 ) { - request.path = '\\' + session.transport().tconHostName + '\\' + share + request.path; - } - session.sendTransaction( request, response ); - } void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { if( response != null ) { @@ -91,6 +64,21 @@ class SmbTree { case ServerMessageBlock.SMB_COM_CLOSE: case ServerMessageBlock.SMB_COM_TREE_DISCONNECT: break; + case ServerMessageBlock.SMB_COM_TRANSACTION: + switch( ((SmbComTransaction)request).subCommand & 0xFF ) { + case SmbComTransaction.NET_SHARE_ENUM: + case SmbComTransaction.NET_SERVER_ENUM2: + case SmbComTransaction.NET_SERVER_ENUM3: + case SmbComTransaction.TRANS_PEEK_NAMED_PIPE: + case SmbComTransaction.TRANS_WAIT_NAMED_PIPE: + case SmbComTransaction.TRANS_CALL_NAMED_PIPE: + case SmbComTransaction.TRANS_TRANSACT_NAMED_PIPE: + case SmbComTransaction.TRANS2_GET_DFS_REFERRAL: + break; + default: + throw new SmbException( "Invalid operation for " + service + " service" ); + } + break; default: throw new SmbException( "Invalid operation for " + service + " service" ); } @@ -100,14 +88,26 @@ class SmbTree { request.flags2 = ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS; request.path = '\\' + session.transport().tconHostName + '\\' + share + request.path; } - session.send( request, response ); + try { + session.send( request, response ); + } catch( SmbException se ) { + if (se.getNtStatus() == se.NT_STATUS_NETWORK_NAME_DELETED) { + /* Someone removed the share while we were + * connected. Bastards! Disconnect this tree + * so that it reconnects cleanly should the share + * reappear in this client's lifetime. + */ + treeDisconnect( true ); + } + throw se; + } } void treeConnect( ServerMessageBlock andx, ServerMessageBlock andxResponse ) throws SmbException { String unc; synchronized( session.transport() ) { - if( treeConnected ) { + if (treeConnected) { return; } @@ -116,7 +116,7 @@ synchronized( session.transport() ) { * established. */ - session.transport.negotiate(); + session.transport.connect(); unc = "\\\\" + session.transport.tconHostName + '\\' + share; @@ -128,9 +128,9 @@ synchronized( session.transport() ) { session.transport.log.println( "treeConnect: unc=" + unc + ",service=" + service ); SmbComTreeConnectAndXResponse response = - new SmbComTreeConnectAndXResponse( andxResponse ); + new SmbComTreeConnectAndXResponse( andxResponse ); SmbComTreeConnectAndX request = - new SmbComTreeConnectAndX( session, unc, service, andx ); + new SmbComTreeConnectAndX( session, unc, service, andx ); session.send( request, response ); tid = response.tid; @@ -141,13 +141,13 @@ synchronized( session.transport() ) { } void treeDisconnect( boolean inError ) { synchronized( session.transport ) { - if( treeConnected == false ) { - return; - } - if( !inError ) { + if (treeConnected && !inError) { try { send( new SmbComTreeDisconnect(), null ); } catch( SmbException se ) { + if (session.transport.log.level > 1) { + se.printStackTrace( session.transport.log ); + } } } treeConnected = false; diff --git a/src/jcifs/smb/Trans2QueryFSInformationResponse.java b/src/jcifs/smb/Trans2QueryFSInformationResponse.java index 5d11e16..ed15a2a 100644 --- a/src/jcifs/smb/Trans2QueryFSInformationResponse.java +++ b/src/jcifs/smb/Trans2QueryFSInformationResponse.java @@ -25,6 +25,7 @@ class Trans2QueryFSInformationResponse extends SmbComTransactionResponse { // information levels static final int SMB_INFO_ALLOCATION = 1; static final int SMB_QUERY_FS_SIZE_INFO = 0x103; + static final int SMB_FS_FULL_SIZE_INFORMATION = 1007; class SmbInfoAllocation implements AllocInfo { long alloc; // Also handles SmbQueryFSSizeInfo @@ -77,6 +78,8 @@ class Trans2QueryFSInformationResponse extends SmbComTransactionResponse { return readSmbInfoAllocationWireFormat( buffer, bufferIndex ); case SMB_QUERY_FS_SIZE_INFO: return readSmbQueryFSSizeInfoWireFormat( buffer, bufferIndex ); + case SMB_FS_FULL_SIZE_INFORMATION: + return readFsFullSizeInformationWireFormat( buffer, bufferIndex ); default: return 0; } @@ -110,19 +113,42 @@ class Trans2QueryFSInformationResponse extends SmbComTransactionResponse { SmbInfoAllocation info = new SmbInfoAllocation(); - info.alloc = readInt4( buffer, bufferIndex ); - bufferIndex += 4; - info.alloc |= readInt4( buffer, bufferIndex ) << 32L; - bufferIndex += 4; + info.alloc = readInt8( buffer, bufferIndex ); + bufferIndex += 8; - info.free = readInt4( buffer, bufferIndex ); + info.free = readInt8( buffer, bufferIndex ); + bufferIndex += 8; + + info.sectPerAlloc = readInt4( buffer, bufferIndex ); bufferIndex += 4; - info.free |= readInt4( buffer, bufferIndex ) << 32L; + + info.bytesPerSect = readInt4( buffer, bufferIndex ); bufferIndex += 4; + this.info = info; + + return bufferIndex - start; + } + int readFsFullSizeInformationWireFormat( byte[] buffer, int bufferIndex ) + { + int start = bufferIndex; + + SmbInfoAllocation info = new SmbInfoAllocation(); + + // Read total allocation units. + info.alloc = readInt8( buffer, bufferIndex ); + bufferIndex += 8; + + // read caller available allocation units + info.free = readInt8( buffer, bufferIndex ); + bufferIndex += 8; + + // skip actual free units + bufferIndex += 8; + info.sectPerAlloc = readInt4( buffer, bufferIndex ); bufferIndex += 4; - + info.bytesPerSect = readInt4( buffer, bufferIndex ); bufferIndex += 4; @@ -130,6 +156,7 @@ class Trans2QueryFSInformationResponse extends SmbComTransactionResponse { return bufferIndex - start; } + public String toString() { return new String( "Trans2QueryFSInformationResponse[" + super.toString() + "]" ); diff --git a/src/jcifs/smb/TransactNamedPipeInputStream.java b/src/jcifs/smb/TransactNamedPipeInputStream.java index 0a0285e..3581feb 100644 --- a/src/jcifs/smb/TransactNamedPipeInputStream.java +++ b/src/jcifs/smb/TransactNamedPipeInputStream.java @@ -33,9 +33,10 @@ class TransactNamedPipeInputStream extends SmbFileInputStream { Object lock; - TransactNamedPipeInputStream( SmbNamedPipe pipe ) throws SmbException, MalformedURLException, UnknownHostException { + TransactNamedPipeInputStream( SmbNamedPipe pipe ) throws SmbException, + MalformedURLException, UnknownHostException { super( pipe, ( pipe.pipeType & 0xFFFF0000 ) | SmbFile.O_EXCL ); - this.dcePipe = ( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT ) == SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT; + this.dcePipe = ( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT ) != SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT; lock = new Object(); } public int read() throws IOException { diff --git a/src/jcifs/smb/TransactNamedPipeOutputStream.java b/src/jcifs/smb/TransactNamedPipeOutputStream.java index 9f1bbbd..90033a6 100644 --- a/src/jcifs/smb/TransactNamedPipeOutputStream.java +++ b/src/jcifs/smb/TransactNamedPipeOutputStream.java @@ -51,9 +51,9 @@ class TransactNamedPipeOutputStream extends OutputStream { if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_CALL ) == SmbNamedPipe.PIPE_TYPE_CALL ) { - pipe.sendTransaction( new TransWaitNamedPipe( path ), + pipe.send( new TransWaitNamedPipe( path ), new TransWaitNamedPipeResponse() ); - pipe.sendTransaction( new TransCallNamedPipe( path, b, off, len ), + pipe.send( new TransCallNamedPipe( path, b, off, len ), new TransCallNamedPipeResponse( pipe )); } else if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_TRANSACT ) == SmbNamedPipe.PIPE_TYPE_TRANSACT ) { @@ -62,7 +62,7 @@ class TransactNamedPipeOutputStream extends OutputStream { if (dcePipe) { req.maxDataCount = 1024; } - pipe.sendTransaction( req, new TransTransactNamedPipeResponse( pipe )); + pipe.send( req, new TransTransactNamedPipeResponse( pipe )); } } } diff --git a/src/jcifs/util/transport/Request.java b/src/jcifs/util/transport/Request.java new file mode 100644 index 0000000..3f3034d --- /dev/null +++ b/src/jcifs/util/transport/Request.java @@ -0,0 +1,4 @@ +package jcifs.util.transport; + +public interface Request { +} diff --git a/src/jcifs/util/transport/Response.java b/src/jcifs/util/transport/Response.java new file mode 100644 index 0000000..eba5d1c --- /dev/null +++ b/src/jcifs/util/transport/Response.java @@ -0,0 +1,6 @@ +package jcifs.util.transport; + +public abstract class Response { + public long expiration; + public boolean isReceived; +} diff --git a/src/jcifs/util/transport/Transport.java b/src/jcifs/util/transport/Transport.java new file mode 100644 index 0000000..c180f6d --- /dev/null +++ b/src/jcifs/util/transport/Transport.java @@ -0,0 +1,235 @@ +package jcifs.util.transport; + +import java.io.*; +import java.net.*; +import java.util.*; +import jcifs.util.LogStream; + +/** + * This class simplifies communication for protocols that support + * multiplexing requests. It encapsulates a stream and some protocol + * knowledge (provided by a concrete subclass) so that connecting, + * disconnecting, sending, and receiving can be syncronized + * properly. Apparatus is provided to send and receive requests + * concurrently. + */ + +public abstract class Transport implements Runnable { + + static int id = 0; + static LogStream log = LogStream.getInstance(); + + public static int readn( InputStream in, + byte[] b, + int off, + int len ) throws IOException { + int i = 0, n = -5; + + while (i < len) { + n = in.read( b, off + i, len - i ); + if (n <= 0) { + break; + } + i += n; + } + + return i; + } + + /* state values + * 0 - not connected + * 1 - connecting + * 2 - run connected + * 3 - connected + * 4 - error + */ + int state = 0; + + String name = "Transport" + id++; + Thread thread; + TransportException te; + + protected HashMap response_map = new HashMap( 4 ); + + protected abstract void makeKey( Request request ) throws IOException; + protected abstract Request peekKey() throws IOException; + protected abstract void doSend( Request request ) throws IOException; + protected abstract void doRecv( Response response ) throws IOException; + protected abstract void doSkip() throws IOException; + + public void sendrecv( Request request, + Response response, + long timeout ) throws IOException { + synchronized (response_map) { + makeKey( request ); + response.isReceived = false; + try { + response_map.put( request, response ); + doSend( request ); + response.expiration = System.currentTimeMillis() + timeout; + while (!response.isReceived) { + response_map.wait( timeout ); + timeout = response.expiration - System.currentTimeMillis(); + if (timeout <= 0) { + throw new TransportException( name + + " timedout waiting for response to " + + request ); + } + } + } catch( InterruptedException ie ) { + throw new TransportException( ie ); + } finally { + response_map.remove( request ); + } + } + } + private void loop() { + while( thread == Thread.currentThread() ) { + try { + Request key = peekKey(); + if (key == null) return; + synchronized (response_map) { + Response response = (Response)response_map.get( key ); + if (response == null) { + if (log.level > 2) + log.println( "Invalid key, skipping message" ); + doSkip(); + } else { + doRecv( response ); + response.isReceived = true; + response_map.notifyAll(); + } + } + } catch( IOException ex ) { + String msg = ex.getMessage(); + boolean hard = true; + + if (log.level > 2) + ex.printStackTrace( log ); + + if (msg != null && msg.equals( "Read timed out" )) { + hard = false; + } + try { + disconnect( hard ); + } catch( IOException ioe ) { + ioe.printStackTrace( log ); + } + } + } + } + + /* Build a connection. Only one thread will ever call this method at + * any one time. If this method throws an exception or the connect timeout + * expires an encapsulating TransportException will be thrown from connect + * and the transport will be in error. + */ + + protected abstract void doConnect() throws Exception; + + /* Tear down a connection. If the hard parameter is true, the diconnection + * procedure should not initiate or wait for any outstanding requests on + * this transport. + */ + + protected abstract void doDisconnect( boolean hard ) throws IOException; + + public synchronized void connect( long timeout ) throws TransportException { + switch (state) { + case 0: + break; + case 3: + return; // already connected + case 4: + throw new TransportException( "Connection in error", te ); + default: + throw new TransportException( "Invalid state: " + state ); + } + + state = 1; + te = null; + thread = new Thread( this, name ); + thread.setDaemon( true ); + + synchronized (thread) { + thread.start(); + try { + thread.wait( timeout ); /* wait for doConnect */ + } catch( InterruptedException ie ) { + throw new TransportException( ie ); + } + + switch (state) { + case 1: /* doConnect never returned */ + te = new TransportException( "Connection timeout" ); + case 2: + if (te != null) { /* doConnect throw Exception */ + state = 4; /* error */ + thread = null; + throw te; + } + state = 3; /* Success! */ + return; + default: + te = new TransportException( "Invalid state: " + state ); + } + } + } + public synchronized void disconnect( boolean hard ) throws IOException { + switch (state) { + case 0: /* not connected - just return */ + return; + case 3: /* connected - go ahead and disconnect */ + if (response_map.size() != 0 && !hard) { + break; /* outstanding requests */ + } + doDisconnect( hard ); + case 4: /* in error - reset the transport */ + thread = null; + state = 0; + break; + default: + throw new TransportException( "Invalid state: " + state ); + } + } + public void run() { + Thread run_thread = Thread.currentThread(); + Exception ex0 = null; + + try { + /* We cannot synchronize (run_thread) here or the caller's + * thread.wait( timeout ) cannot reaquire the lock and + * return which would render the timeout effectively useless. + */ + doConnect(); + } catch( Exception ex ) { + ex0 = ex; // Defer to below where we're locked + return; + } finally { + synchronized (run_thread) { + if (run_thread != thread) { + /* Thread no longer the one setup for this transport -- + * doConnect returned too late, just ignore. + */ + if (ex0 != null) { + ex0.printStackTrace(); + } + return; + } + if (ex0 != null) { + te = new TransportException( ex0 ); + } + state = 2; // run connected + run_thread.notify(); + } + } + + /* Proccess responses + */ + loop(); + } + + public String toString() { + return name; + } +} diff --git a/src/jcifs/util/transport/TransportException.java b/src/jcifs/util/transport/TransportException.java new file mode 100644 index 0000000..994fe7f --- /dev/null +++ b/src/jcifs/util/transport/TransportException.java @@ -0,0 +1,38 @@ +package jcifs.util.transport; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +public class TransportException extends IOException { + + private Throwable rootCause; + + public TransportException() { + } + public TransportException( String msg ) { + super( msg ); + } + public TransportException( Throwable rootCause ) { + this.rootCause = rootCause; + } + public TransportException( String msg, Throwable rootCause ) { + super( msg ); + this.rootCause = rootCause; + } + + public Throwable getRootCause() { + return rootCause; + } + public String toString() { + if( rootCause != null ) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter( sw ); + rootCause.printStackTrace( pw ); + return super.toString() + "\n" + sw; + } else { + return super.toString(); + } + } +} + -- 2.11.0