jcifs-0.9.2 from tgz
authorFelix Schumacher <p0354740@isib001.(none)>
Wed, 6 Aug 2008 14:17:41 +0000 (16:17 +0200)
committerFelix Schumacher <p0354740@isib001.(none)>
Wed, 6 Aug 2008 14:17:41 +0000 (16:17 +0200)
Removed the HTTP redirect from the filter.

Tue Jun  1 23:23:08 EDT 2004
jcifs-0.9.1 released

If the "guest" account is enabled on a CIFS server it is possible for jCIFS
to  successfully  authenticate  even  with  an  invalid  username.  Windows
networks  virtually  always  disable  this account but apparently it is not
difficult to enable this condition when using Samba. NTLM HTTP Filter users
that  are  not  certain the "guest" account is disable should upgrade. This
release eliminates the possability of authenticating anyone without a valid
username.  Specifically,  a  small  clause  as  been  added  that throws an
SmbAuthException  if  the  server responds with the "is logged in as guest"
bit on.

Thu May 27 23:25:57 EDT 2004
jcifs-0.9.0 released

The  0.9 series is no longer beta. Aside from a very small code change this
release only includes documentation updates.

29 files changed:
CHANGES.txt
README.txt
build.xml
examples/ntlm.prp [deleted file]
examples/runtests.sh
examples/web.xml [new file with mode: 0644]
src/jcifs/Config.java
src/jcifs/UniAddress.java
src/jcifs/http/NetworkExplorer.java
src/jcifs/http/NtlmHttpFilter.java
src/jcifs/http/NtlmSsp.java
src/jcifs/netbios/Name.java
src/jcifs/netbios/NameServiceClient.java
src/jcifs/netbios/NbtAddress.java
src/jcifs/ntlmssp/NtlmMessage.java
src/jcifs/smb/AndXServerMessageBlock.java
src/jcifs/smb/NetServerEnum2.java
src/jcifs/smb/NetServerEnum2Response.java
src/jcifs/smb/NtStatus.java
src/jcifs/smb/NtlmPasswordAuthentication.java
src/jcifs/smb/ServerMessageBlock.java
src/jcifs/smb/SigningDigest.java
src/jcifs/smb/SmbComSessionSetupAndX.java
src/jcifs/smb/SmbComSessionSetupAndXResponse.java
src/jcifs/smb/SmbComTransaction.java
src/jcifs/smb/SmbFile.java
src/jcifs/smb/SmbSession.java
src/jcifs/smb/SmbTransport.java
src/jcifs/smb/SmbTree.java

index eddd740..378efb4 100644 (file)
+Thu May 27 23:25:57 EDT 2004
+jcifs-0.9.0 released
+
+The 0.9 series is no longer beta as there have been no reports of problems.
+The  documentation  has  been updated but still needs a little work. Please
+report anything inaccurate or confusing. 
+
+Thu May 13 23:34:43 EDT 2004
+jcifs-0.9.0p released
+
+Thus begins the 0.9 series. See multiple entries below for details.
+
+Thu May 13 18:52:52 EDT 2004
+
+NetServerEnum2  has  been  added  to  support large lists of workgroups and
+servers.  Note  that  enumerating large lists of shares is still limited by
+one 64K buffer.
+
+The  NtlmHttpFilter  has been modified to support "preauthentication" using
+the  default  credentials  so that a valid signing key can be generated for
+servers  that  require  SMB  signing  (although it will probably still work
+without). 
+
+Mon May 10 21:56:49 EDT 2004
+
+Several  minor  changes  have  been  made  to  the NTLM HTTP Authentication
+Filter.  First,  it  is  now not possible for an NtlmPasswordAuthentication
+object (NPA) with externally supplied hashes (i.e. via NTLM HTTP Filter) to
+be  used  with  an SMB_COM_SESSION_SETUP if the challenge used to build the
+hashes  no  longer  matches  the  transport over which the request is being
+issued  (i.e.  the  challenge has expired). Second, should such a condition
+arise  an SmbAuthException will be thrown from SmbSession.sessionSetup with
+a status of NT_STATUS_ACCESS_VIOLATION (this status code is not returned by
+the  server  in  this  case but is not used by any other natrually occuring
+SmbAuthException  but  could in theory be emitted as a plain SmbException).
+The  NtlmHttpFilter will catch this exception and issue an HTTP redirect to
+the requested URL thereby reinitiating the NTLM negotiation. In theory this
+condition cannot arise as the NPA's presence in the HttpSession is all that
+is  necessary for the request to bypass NTLM and call chain.doFilter but it
+is  believed  there  are  unforseen  conditions  under which the Filter can
+provoke  NTLM  to  be renegotiated back-to-back thereby causing the Network
+Password  dialog  to  appear  (clustering env?) so this modification should
+ensures  bad  password hashes are never passed to the domain controller and
+any  error  will  be  transparent to the user due to the redirect (i.e. the
+Network Password dialog will not be provoked).
+
+The  NetworkExplorer  servlet  has  been  adjusted to accomodate underlying
+changes  that  manafested themselves as excessive netbios name querying for
+workgoup  and  server names. The NT_STATUS_ACCESS_VIOLATION challenge check
+has   also  been  implemented  in  NetworkExplorer.  These  changes  permit
+NetworkExplorer to browse across DFS shares. When a directory is discovered
+to  be  in  DFS,  a  DfsReferral  is  thrown.  This  exception is caught by
+NetworkExplorer  which then issues a redirect with a new URL build with the
+DfsReferral.node string. 
+
 Sun May  2 22:57:30 EDT 2004
 
-Started to add additional WINS entry support but still only the first entry is used.
+Multiple WINS servers may now be specified as a comma separated list.
+
+Most  SMB  signature  code has been moved into jcifs/smb/SigningDigest.java
+where  it's  state  can  more easily be tracked. This is more favorable for
+dealing  with issues such as failure during signature initialization or the
+scenario   where   NULL   creds  to  IPC$  should  not  use  signing  after
+LOGON_FAILURE with previous session setup.
+
+The    behavior    of    SmbNamedPipe.getOutputStream   has   changed.   If
+PIPE_TYPE_TRANSACT    and    PIPE_TYPE_CALL    are    NOT    specified    a
+TRANS_WAIT_NAMED_PIPE  will  be  issued  before  the  file  is opened. This
+emulates a WaitNamedPipe follow by CreateFile client.
+
+The  return  value of readWriteFormat is now checked against the NBT header
+length (from in.available()). If it does not match it is skip()'d and a log
+message is written. This should allow jCIFS to get by the OS/400 bug in the
+Negotiate response.
+
+The  ssnLimit  property  will  now  cause  new  transports to be created to
+accomodate  new  sessions  as  opposed  to the previous behavior of closing
+stale  sessions  when  the  ssnLimit  is  reached.  Values can be 0 meaning
+unlimited,  1  meaning strict 1:1 sessions:transports, and N for N sessions
+per  transport. A value of 1 should permit the NTLM HTTP Filter to operated
+with  domain  controllers  that  require SMB signatures. This functionality
+should prove to be useful for a variety of other reasons as well.
+
+Added  additional checks to close NbtSocket in connect() in the event of an
+error.  This  should  curb  the  CLOSE_WAIT  sockets  reported  by Gary but
+apparently  this  is not enough to completely eliminate them as traces show
+even an ACK'd FIN can still leave a socket in this state.
+
+The SmbFiles resulting from listing a workgroup could result in those files
+have type TYPE_WORKGROUP when they should have been TYPE_SERVER.
+
+Several  bugs  in the SMB signatures code have been fixed; 1) a concurrency
+flaw  could  result  in the signing digest being updated inappropriately 2)
+the  signature  of  an  errant session setup should be ignored 3) a padding
+byte  was  not  properly  considered  that  could  sporatically  result  in
+"Unverifiable  signature"  errors  reading  files  (this is the outstanding
+mystery bug mentioned in the 0.7.19 release).
 
-Most SMB signature code has been moved into jcifs/smb/SigningDigest.java where it's state can more easily be tracked. This is more favorable for dealing with issues such as failure during signature initialization or the scenario where NULL creds to IPC$ should not use signing after LOGON_FAILURE with previous session setup.
-The behavior of SmbNamedPipe.getOutputStream has changed. If PIPE_TYPE_TRANSACT and PIPE_TYPE_CALL are NOT specified a TRANS_WAIT_NAMED_PIPE will be issued before the file is opened. This emulates a WaitNamedPipe follow by CreateFile client.
-The return value of readWriteFormat is now checked against the NBT header length (from in.available()). If it does not match it is skip()'d and a log message is written. This should allow jCIFS to get by the OS/400 bug in the Negotiate response.
-The ssnLimit property will now cause new transports to be created to accomodate new sessions as opposed to the previous behavior of closing stale sessions when the ssnLimit is reached. Values can be 0 meaning unlimited, 1 meaning strict 1:1 sessions:transports, and N for N sessions per transport. A value of 1 should permit the NTLM HTTP Filter to operated with domain controllers that require SMB signatures. This functionality should prove to be useful for a variety of other reasons as well.
-Added additional checks to close NbtSocket in connect() in the event of an error. This should curb the CLOSE_WAIT sockets reported by Gary but apparently this is not enough to completely eliminate them as traces show even an ACK'd FIN can still leave a socket in this state.
-The SmbFiles resulting from listing a workgroup could result in those files have type TYPE_WORKGROUP when they should have been TYPE_SERVER.
-Several bugs in the SMB signatures code have been fixed; 1) a concurrency flaw could result in the signing digest being updated inappropriately 2) the signature of an errant session setup should be ignored 3) a padding byte was not properly considered that could sporatically result in "Unverifiable signature" errors reading files (this is the outstanding mystery bug mentioned in the 0.7.19 release).
 Fixed some incorrect path handling in the DFS referral code.
-Two property defaults have been changed; jcifs.smb.client.listSize from 1200 to 65535 and jcifs.smb.client.listCount from 15 to 200. For high latency networks I recommend changing the values back.
-All access specifiers have been reviewed and changed to private or protected wherever possible and appropriate.
-The NetBIOS socket OutputStream has been reduced to a virtually useless shell. The NetBIOS header is now handled within ServerMessageBlock.java. Unfortunately it does not appear to have improved performance considerably. It's hard to tell from the testing performed.
-The MpxControl inner class has been removed in favor of something much simpler. It no longer creates Integer objects with each transmission. Unfortunately it does not appear to have improved performance either.
+
+Two  property  defaults  have  been changed; jcifs.smb.client.listSize from
+1200  to  65535  and  jcifs.smb.client.listCount  from  15 to 200. For high
+latency networks I recommend changing the values back.
+
+All  access  specifiers  have  been  reviewed  and  changed  to  private or
+protected wherever possible and appropriate.
+
+The  NetBIOS  socket  OutputStream  has been reduced to a virtually useless
+shell.  The  NetBIOS  header is now handled within ServerMessageBlock.java.
+Unfortunately it does not appear to have improved performance considerably.
+It's hard to tell from the testing performed.
+
+The  MpxControl  inner  class  has  been removed in favor of something much
+simpler.  It  no  longer  creates  Integer  objects with each transmission.
+Unfortunately it does not appear to have improved performance either. 
 
 Tue Feb 10 23:44:45 EST 2004
 jcifs-0.8.0 released
index fd30bf5..5de5b2b 100644 (file)
@@ -1,3 +1,30 @@
+Removed the HTTP redirect from the filter.
+
+Tue Jun  1 23:23:08 EDT 2004
+jcifs-0.9.1 released
+
+If the "guest" account is enabled on a CIFS server it is possible for jCIFS
+to  successfully  authenticate  even  with  an  invalid  username.  Windows
+networks  virtually  always  disable  this account but apparently it is not
+difficult to enable this condition when using Samba. NTLM HTTP Filter users
+that  are  not  certain the "guest" account is disable should upgrade. This
+release eliminates the possability of authenticating anyone without a valid
+username.  Specifically,  a  small  clause  as  been  added  that throws an
+SmbAuthException  if  the  server responds with the "is logged in as guest"
+bit on. 
+
+Thu May 27 23:25:57 EDT 2004
+jcifs-0.9.0 released
+
+The  0.9 series is no longer beta. Aside from a very small code change this
+release only includes documentation updates. 
+
+Thu May 13 23:34:43 EDT 2004
+jcifs-0.9.0p released
+
+Thus  begins the 0.9 series. See CHANGES.txt for details. The documentation
+hasn't been revisited so some of it is incorrect. 
+
 Tue Feb 10 23:44:45 EST 2004
 jcifs-0.8.0 released
 
index babab71..0d3d126 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -1,6 +1,6 @@
 <project name="jcifs" default="usage" basedir=".">
 
-    <property name="version" value="0.9.0p6"/>
+    <property name="version" value="0.9.2"/>
 
     <target name="usage">
         <echo>
@@ -64,8 +64,9 @@ dependencies: Checks that all class dependencies are met.
             author="true"
             version="true"
             use="true"
-            sourcefiles="src/jcifs/Config.java,src/jcifs/UniAddress.java,src/jcifs/http/NetworkExplorer.java,src/jcifs/http/NtlmHttpFilter.java,src/jcifs/http/NtlmServlet.java,src/jcifs/http/NtlmSsp.java,src/jcifs/netbios/NbtAddress.java,src/jcifs/smb/DosFileFilter.java,src/jcifs/smb/NtlmAuthenticator.java,src/jcifs/smb/NtlmPasswordAuthentication.java,src/jcifs/smb/SmbAuthException.java,src/jcifs/smb/SmbException.java,src/jcifs/smb/SmbFile.java,src/jcifs/smb/SmbFileFilter.java,src/jcifs/smb/SmbFileInputStream.java,src/jcifs/smb/SmbFilenameFilter.java,src/jcifs/smb/SmbFileOutputStream.java,src/jcifs/smb/SmbNamedPipe.java,src/jcifs/smb/SmbRandomAccessFile.java,src/jcifs/smb/SmbSession.java"
-            windowtitle="jCIFS API">
+            sourcefiles="src/jcifs/Config.java,src/jcifs/UniAddress.java,src/jcifs/netbios/NbtAddress.java,src/jcifs/smb/DosFileFilter.java,src/jcifs/smb/NtlmAuthenticator.java,src/jcifs/smb/NtlmPasswordAuthentication.java,src/jcifs/smb/SmbAuthException.java,src/jcifs/smb/SmbException.java,src/jcifs/smb/SmbFile.java,src/jcifs/smb/SmbFileFilter.java,src/jcifs/smb/SmbFileInputStream.java,src/jcifs/smb/SmbFilenameFilter.java,src/jcifs/smb/SmbFileOutputStream.java,src/jcifs/smb/SmbNamedPipe.java,src/jcifs/smb/SmbRandomAccessFile.java,src/jcifs/smb/SmbSession.java"
+            windowtitle="JCIFS API">
+
             <sourcepath path="src"/>
             <classpath>
                 <pathelement path="${java.class.path}"/>
@@ -74,7 +75,7 @@ dependencies: Checks that all class dependencies are met.
                 </fileset>
             </classpath>
         </javadoc>
-        <copy file="docs/allclasses-frame.html" tofile="docs/api/allclasses-frame.html" overwrite="yes"/>
+        <!--copy file="docs/allclasses-frame.html" tofile="docs/api/allclasses-frame.html" overwrite="yes"/-->
     </target>
 
     <target name="all" depends="jar,javadoc"/>
@@ -94,6 +95,19 @@ dependencies: Checks that all class dependencies are met.
             </fileset>
         </delete>
         <delete dir="docs/api" quiet="true"/>
+        <delete quiet="true">
+            <fileset dir="docs">
+                <include name="index.html"/>
+                <include name="pipes.html"/>
+                <include name="faq.html"/>
+                <include name="wins.html"/>
+                <include name="capture.html"/>
+                <include name="httpclient.html"/>
+                <include name="resolver.html"/>
+                <include name="authhandler.html"/>
+                <include name="ntlmhttpauth.html"/>
+            </fileset>
+        </delete>
     </target>
 
     <target name="jcifs" depends="all,clean"/>
@@ -164,4 +178,35 @@ dependencies: Checks that all class dependencies are met.
         <checksum file="jcifs-${version}.tgz"/>
     </target>
 
+    <target name="docs">
+        <style basedir="docs" destdir="docs" extension=".html" style="plain.xsl"
+                includes="pipes.xml,faq.xml,wins.xml,capture.xml,httpclient.xml,resolver.xml,authhandler.xml,ntlmhttpauth.xml">
+<param name="date" expression="Jun 8, 2004"/>
+<param name="lib" expression="jcifs-0.9.2"/>
+<param name="title" expression="JCIFS"/>
+<param name="copyright" expression="The JCIFS Project"/>
+<param name="edge" expression="#808080"/>
+<param name="mainpane" expression="#ffffff"/>
+<param name="leftpane" expression="#FFD700"/>
+<param name="middlepane" expression="#ffffff"/>
+<param name="footer" expression="#808080"/>
+<param name="text1" expression="#000000"/>
+<param name="text2" expression="#000080"/>
+        </style>
+        <style basedir="docs" destdir="docs" extension=".html" style="proj.xsl"
+                includes="index.xml">
+<param name="date" expression="Jun 8, 2004"/>
+<param name="lib" expression="jcifs-0.9.2"/>
+<param name="title" expression="JCIFS"/>
+<param name="copyright" expression="The JCIFS Project"/>
+<param name="edge" expression="#808080"/>
+<param name="mainpane" expression="#ffffff"/>
+<param name="leftpane" expression="#FFD700"/>
+<param name="middlepane" expression="#ffffff"/>
+<param name="footer" expression="#808080"/>
+<param name="text1" expression="#000000"/>
+<param name="text2" expression="#000080"/>
+        </style>
+    </target>
+
 </project>
diff --git a/examples/ntlm.prp b/examples/ntlm.prp
deleted file mode 100644 (file)
index 5087008..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-! Lookup any domain contorller in the FOONET<1C> domain
-
-;jcifs.smb.client.domain=foonet
-
-! Or explicitly specify any SMB server to use as a
-! "Domain Controller". This could be a real PDC or
-! preferrably a BDC or just a plain workstation
-
-jcifs.smb.client.domainController=192.168.1.15
-
-! WINS server is only necessary if you are using the
-! jcifs.smb.client.domain property to lookup a domain
-! controller
-
-;jcifs.netbios.wins=136.135.65.85
-
-! On machines with multiple interfaces it is usually
-! necessary to set the broadcast address. See the jCIFS FAQ.
-
-jcifs.netbios.baddr=192.168.1.255
-
-! If we're sure we have a WINS server this is a
-! little more direct
-
-;jcifs.resolveOrder=WINS
-
-! Users will have to re-authenticate after 600000ms
-! (10 minutes) if no clients trigger activity on the socket
-! to the domain controller
-
-jcifs.smb.client.soTimeout=600000
-
-! Uncomment this if it's not working to see what's going on.
-! Logging output is directed to System.err. On Tomcat this
-! goes to logs/catalina.out. Not sure about Resin.
-
-;jcifs.util.loglevel=10
index 0940d65..6978e66 100644 (file)
@@ -5,7 +5,7 @@ CLASSPATH=../build:.
 PROPERTIES=../../miallen.prp
 RUN="${JAVA_HOME}/bin/java -cp ${CLASSPATH} -Djcifs.properties=${PROPERTIES}"
 
-SERVER=miallen2
+SERVER=rnycwbmallen1
 SHARE=pub
 WRITE_DIR=test
 SRC_DIR=test/variety
diff --git a/examples/web.xml b/examples/web.xml
new file mode 100644 (file)
index 0000000..ec3c7f1
--- /dev/null
@@ -0,0 +1,59 @@
+<web-app id='/'>
+
+<!--
+-->
+<filter
+    filter-name='ntlm'
+    filter-class='jcifs.http.NtlmHttpFilter'>
+    <init-param>
+        <param-name>jcifs.http.domainController</param-name>
+        <param-value>172.23.22.27</param-value>
+    </init-param>
+    <init-param>
+        <param-name>jcifs.smb.client.soTimeout</param-name>
+        <param-value>8000</param-value>
+    </init-param>
+    <init-param>
+        <param-name>jcifs.smb.client.domain</param-name>
+        <param-value>AMRS</param-value>
+    </init-param>
+    <init-param>
+        <param-name>jcifs.smb.client.username</param-name>
+        <param-value>produser1</param-value>
+    </init-param>
+    <init-param>
+        <param-name>jcifs.smb.client.password</param-name>
+        <param-value>control96</param-value>
+    </init-param>
+    <init-param>
+        <param-name>jcifs.smb.client.signingPreferred</param-name>
+        <param-value>true</param-value>
+    </init-param>
+</filter>
+<filter-mapping
+    url-pattern='/*'
+    filter-name='ntlm'/>
+
+<!--
+<servlet
+    servlet-name='NetworkExplorer'
+    servlet-class='jcifs.http.NetworkExplorer'>
+    <init-param>
+        <param-name>jcifs.resolveOrder</param-name>
+        <param-value>WINS,DNS</param-value>
+    </init-param>
+    <init-param>
+        <param-name>jcifs.netbios.wins</param-name>
+        <param-value>146.125.87.65,169.242.200.2</param-value>
+    </init-param>
+    <init-param>
+        <param-name>jcifs.smb.client.domain</param-name>
+        <param-value>AMRS</param-value>
+    </init-param>
+</servlet>
+<servlet-mapping
+    servlet-name='NetworkExplorer'
+    url-pattern='/ne/*'/>
+-->
+
+</web-app>
index e3faadb..6a4419e 100644 (file)
@@ -276,6 +276,12 @@ public class Config {
         return def;
     }
 
+    /**
+     * Retrieve an array of <tt>InetAddress</tt> created from a property
+     * value containting a <tt>delim</tt> separated list of hostnames and/or
+     * ipaddresses.
+     */
+
     public static InetAddress[] getInetAddressArray( String key, String delim, InetAddress[] def ) {
         String p = getProperty( key );
         if( p != null ) {
index ef27421..504334b 100644 (file)
@@ -40,8 +40,9 @@ import jcifs.util.LogStream;
  * jCIFS name resolution properties can greatly affect the behavior of
  * the client and may be necessary for proper operation.
  * <p>
- * This class should be used in favor of <tt>InetAddress</tt> to resolve hostnames on LANs and WANs that
- * support a mixture of NetBIOS/WINS and DNS resolvable hosts.
+ * This class should be used in favor of <tt>InetAddress</tt> to resolve
+ * hostnames on LANs and WANs that support a mixture of NetBIOS/WINS and
+ * DNS resolvable hosts.
  */
 
 public class UniAddress {
@@ -58,7 +59,7 @@ public class UniAddress {
 
     static {
         String ro = Config.getProperty( "jcifs.resolveOrder" );
-        InetAddress nbns = NbtAddress.getNBNSAddress();
+        InetAddress nbns = NbtAddress.getWINSAddress();
 
         try {
             baddr = Config.getInetAddress( "jcifs.netbios.baddr",
@@ -160,7 +161,7 @@ public class UniAddress {
     static NbtAddress lookupServerOrWorkgroup( String name, InetAddress svr )
                                                     throws UnknownHostException {
         Sem sem = new Sem( 2 );
-        int type = NbtAddress.isNBNS( svr ) ? 0x1b : 0x1d;
+        int type = NbtAddress.isWINS( svr ) ? 0x1b : 0x1d;
 
         QueryThread q1x = new QueryThread( sem, name, type, null, svr );
         QueryThread q20 = new QueryThread( sem, name, 0x20, null, svr );
@@ -187,13 +188,13 @@ public class UniAddress {
         }
     }
 
-/** 
- * Determines the address of a host given it's host name. The name can be a
- * machine name like "jcifs.samba.org",  or an IP address like "192.168.1.15".
- *
- * @param host NetBIOS or DNS hostname to resolve
- * @throws java.net.UnknownHostException if there is an error resolving the name
- */
+    /** 
    * Determines the address of a host given it's host name. The name can be a
    * machine name like "jcifs.samba.org",  or an IP address like "192.168.1.15".
    *
    * @param host NetBIOS or DNS hostname to resolve
    * @throws java.net.UnknownHostException if there is an error resolving the name
    */
 
     public static UniAddress getByName( String hostname )
                                         throws UnknownHostException {
@@ -228,6 +229,12 @@ public class UniAddress {
         return Character.isDigit( hostname.charAt( 0 )) == false;
     }
 
+    /**
+     * Lookup <tt>hostname</tt> and return it's <tt>UniAddress</tt>. If the
+     * <tt>possibleNTDomainOrWorkgroup</tt> parameter is <tt>true</tt> an
+     * addtional name query will be performed to locate a master browser.
+     */
+
     public static UniAddress getByName( String hostname,
                                         boolean possibleNTDomainOrWorkgroup )
                                         throws UnknownHostException {
@@ -257,9 +264,9 @@ public class UniAddress {
                             continue;
                         }
                         if( possibleNTDomainOrWorkgroup ) {
-                            addr = lookupServerOrWorkgroup( hostname, NbtAddress.getNBNSAddress() );
+                            addr = lookupServerOrWorkgroup( hostname, NbtAddress.getWINSAddress() );
                         } else {
-                            addr = NbtAddress.getByName( hostname, 0x20, null, NbtAddress.getNBNSAddress() );
+                            addr = NbtAddress.getByName( hostname, 0x20, null, NbtAddress.getWINSAddress() );
                         }
                         break;
                     case RESOLVER_BCAST:
@@ -294,8 +301,10 @@ public class UniAddress {
     String calledName;
 
     /**
-     * Wrap an <tt>InetAddress</tt> or <tt>NbtAddress</tt>.
+     * Create a <tt>UniAddress</tt> by wrapping an <tt>InetAddress</tt> or
+     * <tt>NbtAddress</tt>.
      */
+
     public UniAddress( Object addr ) {
         if( addr == null ) {
             throw new IllegalArgumentException();
@@ -303,17 +312,28 @@ public class UniAddress {
         this.addr = addr;
     }
 
+    /**
+     * Return the IP address of this address as a 32 bit integer.
+     */
+
     public int hashCode() {
         return addr.hashCode();
     }
+
+    /**
+     * Compare two addresses for equality. Two <tt>UniAddress</tt>s are equal
+     * if they are both <tt>UniAddress' and refer to the same IP address.
+     */
+
     public boolean equals( Object obj ) {
         return obj instanceof UniAddress && addr.hashCode() == obj.hashCode();
-// addr.equals( ((UniAddress)obj).addr );
     }
 
-/** Guess first called name to try for session establishment. This
- * methods are used by the smb package.
- */
+    /**
+     * Guess first called name to try for session establishment. This
+     * method is used exclusively by the <tt>jcifs.smb</tt> package.
+     */
+
     public String firstCalledName() {
         if( addr instanceof NbtAddress ) {
             return ((NbtAddress)addr).firstCalledName();
@@ -335,9 +355,12 @@ public class UniAddress {
 
         return calledName;
     }
-/** Guess next called name to try for session establishment. This
- * methods are used by the smb package.
- */
+
+    /**
+     * Guess next called name to try for session establishment. This
+     * method is used exclusively by the <tt>jcifs.smb</tt> package.
+     */
+
     public String nextCalledName() {
         if( addr instanceof NbtAddress ) {
             return ((NbtAddress)addr).nextCalledName();
@@ -347,21 +370,41 @@ public class UniAddress {
         }
         return null;
     }
+
+    /**
+     * Return the underlying <tt>NbtAddress</tt> or <tt>InetAddress</tt>.
+     */
+
     public Object getAddress() {
         return addr;
     }
+
+    /**
+     * Return the hostname of this address such as "MYCOMPUTER".
+     */
+
     public String getHostName() {
         if( addr instanceof NbtAddress ) {
             return ((NbtAddress)addr).getHostName();
         }
         return ((InetAddress)addr).getHostName();
     }
+
+    /**
+     * Return the IP address as text such as "192.168.1.15".
+     */
+
     public String getHostAddress() {
         if( addr instanceof NbtAddress ) {
             return ((NbtAddress)addr).getHostAddress();
         }
         return ((InetAddress)addr).getHostAddress();
     }
+
+    /**
+     * Return the a text representation of this address such as
+     * <tt>MYCOMPUTER/192.168.1.15</tt>.
+     */
     public String toString() {
         return addr.toString();
     }
index c6af505..279a66a 100644 (file)
@@ -57,8 +57,8 @@ public class NetworkExplorer extends HttpServlet {
         int n;
         String name;
 
-        Config.setProperty( "jcifs.smb.client.soTimeout", "300000" );
-        Config.setProperty( "jcifs.smb.client.attrExpirationPeriod", "120000" );
+        Config.setProperty( "jcifs.smb.client.soTimeout", "600000" );
+        Config.setProperty( "jcifs.smb.client.attrExpirationPeriod", "300000" );
 
         Enumeration e = getInitParameterNames();
         while( e.hasMoreElements() ) {
@@ -206,6 +206,10 @@ public class NetworkExplorer extends HttpServlet {
                     continue;
                 }
             } catch( SmbAuthException sae ) {
+            } catch( SmbException se ) {
+                if( se.getNtStatus() != se.NT_STATUS_UNSUCCESSFUL ) {
+                    throw se;
+                }
             }
             if( dirents[i].isDirectory() ) {
                 dirCount++;
@@ -372,9 +376,12 @@ public class NetworkExplorer extends HttpServlet {
         if( p == len ) {
             return null;
         }
-        do {                                   /* collect server name */
-            out[i++] = (ch = pathInfo.charAt( p++ ));
-        } while( p < len && ch != '/' );
+
+                                               /* collect server name */
+        while ( p < len && ( ch = pathInfo.charAt( p )) != '/' ) {
+            out[i++] = ch;
+            p++;
+        }
         while( p < len && pathInfo.charAt( p ) == '/' ) {
             p++;
         }
@@ -406,7 +413,8 @@ public class NetworkExplorer extends HttpServlet {
         msg = req.getHeader( "Authorization" );
         offerBasic = enableBasic && (insecureBasic || req.isSecure());
 
-        if( msg != null && (msg.startsWith( "NTLM " ) || (offerBasic && msg.startsWith("Basic ")))) {
+        if( msg != null && (msg.startsWith( "NTLM " ) ||
+                    (offerBasic && msg.startsWith("Basic ")))) {
 
             if( msg.startsWith("NTLM ")) {
                 byte[] challenge;
@@ -418,12 +426,12 @@ public class NetworkExplorer extends HttpServlet {
                     dc = UniAddress.getByName( server, possibleWorkgroup );
                 }
 
-                req.getSession();
+                req.getSession(); /* ensure session id is set for cluster env. */
                 challenge = SmbSession.getChallenge( dc );
                 if(( ntlm = NtlmSsp.authenticate( req, resp, challenge )) == null ) {
                     return;
                 }
-            } else {
+            } else { /* Basic */
                 String auth = new String( Base64.decode( msg.substring(6) ), "US-ASCII" );
                 int index = auth.indexOf( ':' );
                 String user = (index != -1) ? auth.substring(0, index) : auth;
@@ -473,6 +481,13 @@ public class NetworkExplorer extends HttpServlet {
             if( ssn != null ) {
                 ssn.removeAttribute( "npa-" + server );
             }
+            if( sae.getNtStatus() == sae.NT_STATUS_ACCESS_VIOLATION ) {
+                /* Server challenge no longer valid for
+                 * externally supplied password hashes.
+                 */
+                resp.sendRedirect( req.getRequestURL().toString() );
+                return;
+            }
             resp.setHeader( "WWW-Authenticate", "NTLM" );
             if (offerBasic) {
                 resp.addHeader( "WWW-Authenticate", "Basic realm=\"" + realm + "\"");
@@ -484,9 +499,6 @@ public class NetworkExplorer extends HttpServlet {
         } catch( DfsReferral dr ) {
             StringBuffer redir = req.getRequestURL();
             String qs = req.getQueryString();
-if( true ) {
-    throw new RuntimeException( "DFS referrals with NetworkExplorer are currently disabled because they can lead to account lockout." );
-}
             redir = new StringBuffer( redir.substring( 0, redir.length() - req.getPathInfo().length() ));
             redir.append( dr.node.replace( '\\', '/' ));
             redir.append( '/' );
index fc6b940..730f138 100644 (file)
@@ -44,16 +44,12 @@ import jcifs.netbios.NbtAddress;
 
 public class NtlmHttpFilter implements Filter {
 
-    private String defaultDomain;
 
+    private String defaultDomain;
     private String domainController;
-
     private boolean loadBalance;
-
     private boolean enableBasic;
-
     private boolean insecureBasic;
-
     private String realm;
 
     public void init( FilterConfig filterConfig ) throws ServletException {
@@ -84,6 +80,7 @@ public class NtlmHttpFilter implements Filter {
         realm = Config.getProperty("jcifs.http.basicRealm");
         if (realm == null) realm = "jCIFS";
     }
+
     public void destroy() {
     }
     public void doFilter( ServletRequest request,
@@ -128,8 +125,19 @@ public class NtlmHttpFilter implements Filter {
                 ntlm = new NtlmPasswordAuthentication(domain, user, password);
             }
             try {
+
                 SmbSession.logon( dc, ntlm );
+
             } catch( SmbAuthException sae ) {
+                if( sae.getNtStatus() == sae.NT_STATUS_ACCESS_VIOLATION ) {
+                    /* Server challenge no longer valid for
+                     * externally supplied password hashes.
+                     */
+                    HttpSession ssn = req.getSession(false);
+                    if (ssn != null) {
+                        ssn.removeAttribute( "NtlmHttpAuth" );
+                    }
+                }
                 resp.setHeader( "WWW-Authenticate", "NTLM" );
                 if (offerBasic) {
                     resp.addHeader( "WWW-Authenticate", "Basic realm=\"" +
index 35e0a68..146cf5e 100644 (file)
@@ -96,7 +96,7 @@ public class NtlmSsp implements NtlmFlags {
                 byte[] ntResponse = type3.getNTResponse();
                 if (ntResponse == null) ntResponse = new byte[0];
                 return new NtlmPasswordAuthentication(type3.getDomain(),
-                        type3.getUser(), lmResponse, ntResponse);
+                        type3.getUser(), challenge, lmResponse, ntResponse);
             }
         } else {
             resp.setHeader("WWW-Authenticate", "NTLM");
index acc6716..b06b783 100644 (file)
@@ -30,9 +30,8 @@ class Name {
     private static final String DEFAULT_SCOPE = Config.getProperty( "jcifs.netbios.scope" );
 
     static final String OEM_ENCODING =
-            Config.getProperty( "jcifs.smb.client.codepage",
-                    Config.getProperty( "jcifs.encoding",
-                            System.getProperty( "file.encoding" )));
+                Config.getProperty( "jcifs.encoding",
+                        System.getProperty( "file.encoding" ));
 
     String name, scope;
     int hexCode;
index 78f59db..5eef004 100644 (file)
@@ -93,7 +93,7 @@ class NameServiceClient implements Runnable {
              * been specified.
              */
 
-            if( NbtAddress.getNBNSAddress() == null ) {
+            if( NbtAddress.getWINSAddress() == null ) {
                 resolveOrder = new int[2];
                 resolveOrder[0] = RESOLVER_LMHOSTS;
                 resolveOrder[1] = RESOLVER_BCAST;
@@ -112,7 +112,7 @@ class NameServiceClient implements Runnable {
                 if( s.equalsIgnoreCase( "LMHOSTS" )) {
                     tmp[i++] = RESOLVER_LMHOSTS;
                 } else if( s.equalsIgnoreCase( "WINS" )) {
-                    if( NbtAddress.getNBNSAddress() == null ) {
+                    if( NbtAddress.getWINSAddress() == null ) {
                         if( log.level > 1 ) {
                             log.println( "NetBIOS resolveOrder specifies WINS however the " +
                                     "jcifs.netbios.wins property has not been set" );
@@ -210,33 +210,49 @@ class NameServiceClient implements Runnable {
     void send( NameServicePacket request, NameServicePacket response,
                                             int timeout ) throws IOException {
         Integer nid = null;
+        int count = 0;
 
         synchronized( response ) {
-            try {
-                synchronized( LOCK ) {
-                    request.nameTrnId = getNextNameTrnId();
-                    nid = new Integer( request.nameTrnId );
+            do {
+                try {
+                    synchronized( LOCK ) {
+                        request.nameTrnId = getNextNameTrnId();
+                        nid = new Integer( request.nameTrnId );
 
-                    out.setAddress( request.addr );
-                    out.setLength( request.writeWireFormat( snd_buf, 0 ));
-                    response.received = false;
+                        out.setAddress( request.addr );
+                        out.setLength( request.writeWireFormat( snd_buf, 0 ));
+                        response.received = false;
 
-                    responseTable.put( nid, response );
-                    ensureOpen( timeout + 1000 );
-                    socket.send( out );
+                        responseTable.put( nid, response );
+                        ensureOpen( timeout + 1000 );
+                        socket.send( out );
 
-                    if( log.level > 2 ) {
-                        log.println( request );
-                        Hexdump.hexdump( log, snd_buf, 0, out.getLength() );
+                        if( log.level > 2 ) {
+                            log.println( request );
+                            Hexdump.hexdump( log, snd_buf, 0, out.getLength() );
+                        }
                     }
-                }
 
-                response.wait( timeout );
+                    response.wait( timeout );
 
-            } catch( InterruptedException ie ) {
-            } finally {
-                responseTable.remove( nid );
-            }
+                } catch( InterruptedException ie ) {
+                } finally {
+                    responseTable.remove( nid );
+                }
+
+                if( !response.received &&
+                            NbtAddress.NBNS.length > 1 &&
+                            NbtAddress.isWINS( request.addr )) {
+                                /* Message was sent to WINS but
+                                 * failed to receive response.
+                                 * Try a different WINS server.
+                                 */
+                    request.addr = NbtAddress.switchWINS();
+                    if( count == 0 ) {
+                        count = NbtAddress.NBNS.length - 1;
+                    }
+                }
+            } while( count-- > 0 );
         }
     }
 
@@ -291,7 +307,7 @@ class NameServiceClient implements Runnable {
                         if( resolveOrder[i] == RESOLVER_WINS &&
                                 name.name != NbtAddress.MASTER_BROWSER_NAME &&
                                 name.hexCode != 0x1d ) {
-                            request.addr = NbtAddress.getNBNSAddress();
+                            request.addr = NbtAddress.getWINSAddress();
                             request.isBroadcast = false;
                         } else {
                             request.addr = baddr;
index ffee207..889a6a4 100644 (file)
@@ -130,7 +130,7 @@ public final class NbtAddress {
 
     public static final int H_NODE = 3;
 
-    private static final InetAddress[] NBNS = Config.getInetAddressArray( "jcifs.netbios.wins", ",", new InetAddress[0] );
+    static final InetAddress[] NBNS = Config.getInetAddressArray( "jcifs.netbios.wins", ",", new InetAddress[0] );
 
     /* Construct the shared static client object that will
      * conduct all encoding and decoding of NetBIOS name service
@@ -509,11 +509,10 @@ public final class NbtAddress {
         }
     }
 
-    public static InetAddress getNBNSAddress() {
+    public static InetAddress getWINSAddress() {
         return NBNS.length == 0 ? null : NBNS[nbnsIndex];
     }
-
-    public static boolean isNBNS( InetAddress svr ) {
+    public static boolean isWINS( InetAddress svr ) {
         for( int i = 0; svr != null && i < NBNS.length; i++ ) {
             if( svr.hashCode() == NBNS[i].hashCode() ) {
                 return true;
@@ -521,6 +520,10 @@ public final class NbtAddress {
         }
         return false;
     }
+    static InetAddress switchWINS() {
+        nbnsIndex = (nbnsIndex + 1) < NBNS.length ? nbnsIndex + 1 : 0;
+        return NBNS.length == 0 ? null : NBNS[nbnsIndex];
+    }
 
     Name hostName;
     int address, nodeType;
index 2a5fd50..c9ed00f 100644 (file)
@@ -35,9 +35,8 @@ public abstract class NtlmMessage implements NtlmFlags {
     };
 
     private static final String OEM_ENCODING =
-            Config.getProperty("jcifs.smb.client.codepage",
-                    Config.getProperty("jcifs.encoding",
-                            System.getProperty("file.encoding")));
+                Config.getProperty("jcifs.encoding",
+                        System.getProperty("file.encoding"));
 
     private int flags;
 
index 925c8ba..b21eb95 100644 (file)
@@ -71,9 +71,15 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock {
 
     int writeWireFormat( byte[] dst, int dstIndex ) {
         int start = headerStart = dstIndex;
+
         dstIndex += writeHeaderWireFormat( dst, dstIndex );
         dstIndex += writeAndXWireFormat( dst, dstIndex );
         length = dstIndex - start;
+
+        if( digest != null ) {
+            digest.sign( dst, headerStart, length, this, response );
+        }
+
         return length;
     }
 
@@ -224,6 +230,10 @@ abstract class AndXServerMessageBlock extends ServerMessageBlock {
             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
index c76838c..8c553ed 100644 (file)
@@ -1,5 +1,6 @@
 /* jcifs smb client library in Java
  * Copyright (C) 2000  "Michael B. Allen" <jcifs at samba dot org>
+ *                             Gary Rambo <grambo aventail.com>
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -25,9 +26,12 @@ class NetServerEnum2 extends SmbComTransaction {
     static final int SV_TYPE_ALL         = 0xFFFFFFFF;
     static final int SV_TYPE_DOMAIN_ENUM = 0x80000000;
 
-    static final String DESCR = "WrLehDz\u0000B16BBDz\u0000";
+    static final String[] DESCR = {
+        "WrLehDz\u0000B16BBDz\u0000",
+        "WrLehDzz\u0000B16BBDz\u0000"
+    };
 
-    String domain;
+    String domain, lastName = null;
     int serverTypes;
 
     NetServerEnum2( String domain, int serverTypes ) {
@@ -44,20 +48,26 @@ class NetServerEnum2 extends SmbComTransaction {
         timeout = 5000;
     }
 
+    void reset( int key, String lastName ) {
+        super.reset();
+        this.lastName = lastName;
+    }
+
     int writeSetupWireFormat( byte[] dst, int dstIndex ) {
         return 0;
     }
     int writeParametersWireFormat( byte[] dst, int dstIndex ) {
         int start = dstIndex;
         byte[] descr;
+        int which = subCommand == NET_SERVER_ENUM2 ? 0 : 1;
 
         try {
-            descr = DESCR.getBytes( "ASCII" );
+            descr = DESCR[which].getBytes( "ASCII" );
         } catch( UnsupportedEncodingException uee ) {
             return 0;
         }
 
-        writeInt2( NET_SERVER_ENUM2, dst, dstIndex );
+        writeInt2( subCommand & 0xFF, dst, dstIndex );
         dstIndex += 2;
         System.arraycopy( descr, 0, dst, dstIndex, descr.length );
         dstIndex += descr.length;
@@ -68,6 +78,9 @@ class NetServerEnum2 extends SmbComTransaction {
         writeInt4( serverTypes, dst, dstIndex );
         dstIndex += 4;
         dstIndex += writeString( domain.toUpperCase(), dst, dstIndex, false );
+        if( which == 1 ) {
+            dstIndex += writeString( lastName.toUpperCase(), dst, dstIndex, false );
+        }
 
         return dstIndex - start;
     }
@@ -84,6 +97,10 @@ class NetServerEnum2 extends SmbComTransaction {
         return 0;
     }
     public String toString() {
-        return new String( "NetServerEnum2[" + super.toString() + ",name=" + name + ",serverTypes=" + (serverTypes == SV_TYPE_ALL ? "SV_TYPE_ALL" : "SV_TYPE_DOMAIN_ENUM" ) + "]" );
+        return new String( "NetServerEnum2[" + super.toString() +
+                ",name=" + name +
+                ",serverTypes=" + (serverTypes == SV_TYPE_ALL ?
+                        "SV_TYPE_ALL" : "SV_TYPE_DOMAIN_ENUM" ) +
+                "]" );
     }
 }
index dabb0fa..5c89a7b 100644 (file)
@@ -1,5 +1,6 @@
 /* jcifs smb client library in Java
  * Copyright (C) 2000  "Michael B. Allen" <jcifs at samba dot org>
+ *                             Gary Rambo <grambo aventail.com>
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -62,6 +63,8 @@ class NetServerEnum2Response extends SmbComTransactionResponse {
 
     private int converter, totalAvailableEntries;
 
+    String lastName;
+
     NetServerEnum2Response() {
     }
 
@@ -93,7 +96,7 @@ class NetServerEnum2Response extends SmbComTransactionResponse {
     }
     int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) {
         int start = bufferIndex;
-        ServerInfo1 e;
+        ServerInfo1 e = null;
 
         results = new ServerInfo1[numEntries];
         for( int i = 0; i < numEntries; i++ ) {
@@ -113,6 +116,7 @@ class NetServerEnum2Response extends SmbComTransactionResponse {
             if( log.level > 2 )
                 log.println( e );
         }
+        lastName = numEntries == 0 ? null : e.name;
 
         return bufferIndex - start;
     }
@@ -122,6 +126,7 @@ class NetServerEnum2Response extends SmbComTransactionResponse {
                 ",status=" + status +
                 ",converter=" + converter +
                 ",entriesReturned=" + numEntries +
-                ",totalAvailableEntries=" + totalAvailableEntries + "]" );
+                ",totalAvailableEntries=" + totalAvailableEntries +
+                ",lastName=" + lastName + "]" );
     }
 }
index 8e0213a..58f9782 100644 (file)
@@ -28,6 +28,7 @@ public interface NtStatus {
     public static final int NT_STATUS_UNSUCCESSFUL = 0xC0000001;
     public static final int NT_STATUS_NOT_IMPLEMENTED = 0xC0000002;
     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_FILE = 0xC000000f;
     public static final int NT_STATUS_ACCESS_DENIED = 0xC0000022;
@@ -68,6 +69,7 @@ public interface NtStatus {
         NT_STATUS_UNSUCCESSFUL,
         NT_STATUS_NOT_IMPLEMENTED,
         NT_STATUS_INVALID_INFO_CLASS,
+        NT_STATUS_ACCESS_VIOLATION,
         NT_STATUS_INVALID_HANDLE,
         NT_STATUS_NO_SUCH_FILE,
         NT_STATUS_ACCESS_DENIED,
@@ -109,6 +111,7 @@ public interface NtStatus {
         "A device attached to the system is not functioning.",
         "Incorrect function.",
         "The parameter is incorrect.",
+        "Invalid access to memory location.",
         "The handle is invalid.",
         "The system cannot find the file specified.",
         "Access is denied.",
index aceb373..a25bf29 100644 (file)
@@ -51,7 +51,7 @@ public final class NtlmPasswordAuthentication implements Principal, Serializable
     private static final String DEFAULT_USERNAME =
             Config.getProperty("jcifs.smb.client.username", "GUEST");
 
-    private static final String DEFAULT_PASSWORD =
+    static final String DEFAULT_PASSWORD =
             Config.getProperty("jcifs.smb.client.password", "");
 
     private static final Random RANDOM = new Random();
@@ -156,10 +156,12 @@ public final class NtlmPasswordAuthentication implements Principal, Serializable
         }
     }
 
-public  static final NtlmPasswordAuthentication NULL =
+    static final NtlmPasswordAuthentication NULL =
                 new NtlmPasswordAuthentication( "", "", "" );
     static final NtlmPasswordAuthentication GUEST =
                 new NtlmPasswordAuthentication( "?", "GUEST", "" );
+    static final NtlmPasswordAuthentication DEFAULT =
+                new NtlmPasswordAuthentication( null );
 
     String domain;
     String username;
@@ -168,6 +170,7 @@ public  static final NtlmPasswordAuthentication NULL =
     byte[] unicodeHash;
     boolean hashesExternal = false;
     byte[] clientChallenge = null;
+    byte[] challenge = null;
 
 /**
  * Create an <tt>NtlmPasswordAuthentication</tt> object from the userinfo
@@ -221,14 +224,15 @@ public  static final NtlmPasswordAuthentication NULL =
  * class which is in turn used by NTLM HTTP authentication functionality.
  */
     public NtlmPasswordAuthentication( String domain, String username,
-                                    byte[] ansiHash, byte[] unicodeHash ) {
+                    byte[] challenge, byte[] ansiHash, byte[] unicodeHash ) {
         if( domain == null || username == null ||
                                     ansiHash == null || unicodeHash == null ) {
-            throw new IllegalArgumentException( "External credentials cannot null" );
+            throw new IllegalArgumentException( "External credentials cannot be null" );
         }
         this.domain = domain;
         this.username = username;
         this.password = null;
+        this.challenge = challenge;
         this.ansiHash = ansiHash;
         this.unicodeHash = unicodeHash;
         hashesExternal = true;
index 833c8df..f6ac392 100644 (file)
@@ -105,9 +105,8 @@ abstract class ServerMessageBlock {
 
     static final boolean USE_BATCHING = Config.getBoolean( "jcifs.smb.client.useBatching", true );
     static final String OEM_ENCODING =
-            Config.getProperty( "jcifs.smb.client.codepage",
-                    Config.getProperty( "jcifs.encoding",
-                            System.getProperty( "file.encoding" )));
+                Config.getProperty( "jcifs.encoding",
+                        System.getProperty( "file.encoding" ));
 
     static LogStream log = LogStream.getInstance();
 
@@ -304,6 +303,8 @@ abstract class ServerMessageBlock {
     boolean verifyFailed;
     NtlmPasswordAuthentication auth = null;
     String path;
+    SigningDigest digest = null;
+    ServerMessageBlock response;
 
     ServerMessageBlock() {
         flags = (byte)( FLAGS_PATH_NAMES_CASELESS | FLAGS_PATH_NAMES_CANONICALIZED );
@@ -408,6 +409,11 @@ Hexdump.hexdump( System.err, src, 0, 256 );
         dstIndex += byteCount;
 
         length = dstIndex - start;
+
+        if( digest != null ) {
+            digest.sign( dst, headerStart, length, this, response );
+        }
+
         return length;
     }
     int readWireFormat( InputStream in,
index 1852b76..12c47dc 100644 (file)
@@ -21,7 +21,6 @@ public class SigningDigest {
     private byte[] macSigningKey;
     private int updates;
     private int signSequence;
-    boolean sessionSetup;
 
     public SigningDigest( SmbTransport transport,
                 NtlmPasswordAuthentication auth ) throws SmbException {
index 4cc0676..6063a05 100644 (file)
@@ -35,11 +35,16 @@ class SmbComSessionSetupAndX extends AndXServerMessageBlock {
     private String accountName, primaryDomain;
 
     SmbSession session;
+    NtlmPasswordAuthentication auth;
 
-    SmbComSessionSetupAndX( SmbSession session, ServerMessageBlock andx ) {
+    SmbComSessionSetupAndX( SmbSession session, ServerMessageBlock andx ) throws SmbException {
         super( andx );
         command = SMB_COM_SESSION_SETUP_ANDX;
         this.session = session;
+        this.auth = session.auth;
+        if( auth.hashesExternal && auth.challenge != session.transport.server.encryptionKey ) {
+            throw new SmbAuthException( SmbException.NT_STATUS_ACCESS_VIOLATION );
+        }
     }
 
     int getBatchLimit( byte command ) {
@@ -49,12 +54,11 @@ class SmbComSessionSetupAndX extends AndXServerMessageBlock {
         int start = dstIndex;
 
         if( session.transport.server.security == SECURITY_USER &&
-                        ( session.auth.hashesExternal ||
-                        session.auth.password.length() > 0 )) {
+                        ( auth.hashesExternal || auth.password.length() > 0 )) {
             if( session.transport.server.encryptedPasswords ) {
                 // encrypted
-                accountPassword = session.auth.getAnsiHash( session.transport.server.encryptionKey );
-                unicodePassword = session.auth.getUnicodeHash( session.transport.server.encryptionKey );
+                accountPassword = auth.getAnsiHash( session.transport.server.encryptionKey );
+                unicodePassword = auth.getUnicodeHash( session.transport.server.encryptionKey );
                 passwordLength = unicodePasswordLength = 24;
                 // fix for win9x clients
                 if (unicodePassword.length == 0) unicodePasswordLength = 0;
@@ -62,14 +66,14 @@ class SmbComSessionSetupAndX extends AndXServerMessageBlock {
                 throw new RuntimeException( "Plain text passwords are disabled" );
             } else if( useUnicode ) {
                 // plain text
-                String password = session.auth.getPassword();
+                String password = auth.getPassword();
                 accountPassword = new byte[0];
                 passwordLength = 0;
                 unicodePassword = new byte[(password.length() + 1) * 2];
                 unicodePasswordLength = writeString( password, unicodePassword, 0 );
             } else {
                 // plain text
-                String password = session.auth.getPassword();
+                String password = auth.getPassword();
                 accountPassword = new byte[(password.length() + 1) * 2];
                 passwordLength = writeString( password, accountPassword, 0 );
                 unicodePassword = new byte[0];
@@ -106,12 +110,11 @@ class SmbComSessionSetupAndX extends AndXServerMessageBlock {
     int writeBytesWireFormat( byte[] dst, int dstIndex ) {
         int start = dstIndex;
 
-        accountName = session.auth.username.toUpperCase();
-        primaryDomain = session.auth.domain.toUpperCase();
+        accountName = auth.username.toUpperCase();
+        primaryDomain = auth.domain.toUpperCase();
 
         if( session.transport.server.security == SECURITY_USER &&
-                        ( session.auth.hashesExternal ||
-                        session.auth.password.length() > 0 )) {
+                        ( auth.hashesExternal || auth.password.length() > 0 )) {
             System.arraycopy( accountPassword, 0, dst, dstIndex, passwordLength );
             dstIndex += passwordLength;
             System.arraycopy( unicodePassword, 0, dst, dstIndex, unicodePasswordLength );
index a379d8b..f4c6e94 100644 (file)
@@ -26,11 +26,12 @@ import jcifs.util.Hexdump;
 
 class SmbComSessionSetupAndXResponse extends AndXServerMessageBlock {
 
-    private boolean isLoggedInAsGuest;
     private String nativeOs = "";
     private String nativeLanMan = "";
     private String primaryDomain = "";
 
+    boolean isLoggedInAsGuest;
+
     SmbComSessionSetupAndXResponse( ServerMessageBlock andx ) {
         super( andx );
     }
index cdc8db5..6896e01 100644 (file)
@@ -63,6 +63,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati
 
     static final int NET_SHARE_ENUM   = 0x0000;
     static final int NET_SERVER_ENUM2 = 0x0068;
+    static final int NET_SERVER_ENUM3 = 0x00D7;
 
     static final byte TRANS_PEEK_NAMED_PIPE     = (byte)0x23;
     static final byte TRANS_WAIT_NAMED_PIPE     = (byte)0x53;
index 4f83144..7a37317 100644 (file)
@@ -34,17 +34,16 @@ import jcifs.netbios.NbtAddress;
 import java.util.Date;
 
 /**
- * <p>
  * This class represents a resource on an SMB network. Mainly these
  * resources are files and directories however an <code>SmbFile</code>
  * may also refer to servers and workgroups. If the resource is a file or
  * directory the methods of <code>SmbFile</code> follow the behavior of
  * the well known {@link java.io.File} class. One fundamental difference
- * is the usage of a URL scheme<b>*</b> to specify the target file or
+ * is the usage of a URL scheme [1] to specify the target file or
  * directory. SmbFile URLs have the following syntax:
  *
  * <blockquote><pre>
- *     smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]]
+ *     smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]][?[param=value[param2=value2[...]]]
  * </pre></blockquote>
  *
  * This example:
@@ -53,27 +52,28 @@ import java.util.Date;
  *     smb://storage15/public/foo.txt
  * </pre></blockquote>
  *
- * would referece the file <code>foo.txt</code> in the share
+ * would reference the file <code>foo.txt</code> in the share
  * <code>public</code> on the server <code>storage15</code>. In addition
  * to referencing files and directories, jCIFS can also address servers,
  * and workgroups.
-<p>
- * <font color="#800000"><i>Please note that beginning with jcifs-0.7.0b4 all SMB URLs that represent workgroups, servers, shares, or directories require a trailing slash '/'. This will break older code and you may or may not get an exception. For example:</i>
-<blockquote><pre>
-smb://server/share/path/to/dir/  <-- GOOD
-
-smb://server/share/path/to/dir   <-- BAD
-</pre></blockquote>
-To assist you with this, the <tt>getName</tt> method will now include a slash '/' after the name if the URL refers to a directory (e.g. 'dir/').
-</font>
-<p>
-When using the <tt>java.net.URL</tt> class with 'smb://' URLs it is necessary to first call the static <tt>jcifs.Config.registerSmbURLHandler();</tt> method (prior to jcifs-0.7.0b12 it was <tt>Class.forName( "jcifs.Config" );</tt> but this is no longer necessary).
-<p>
-The userinfo component of the SMB URL (<tt>domain;user:pass</tt>) must be URL encoded if it contains reserved characters. According to RFC 2396 these characters are non US-ASCII characters and most meta characters however jCIFS will work correctly with anything but '@' which is used to delimit the userinfo component from the server and '%' which is the URL escape character itself.
-<p>
-When used in conjunction with the <code>list</code>
- * method, this functionality can be usefull for network diagnostics
- * tools or "Network Neighborhood" like functionality. The server
+ * <p>
+ * <font color="#800000"><i>Important: all SMB URLs that represent
+ * workgroups, servers, shares, or directories require a trailing slash '/'.
+ * </i></font>
+ * <p>
+ * When using the <tt>java.net.URL</tt> class with
+ * 'smb://' URLs it is necessary to first call the static
+ * <tt>jcifs.Config.registerSmbURLHandler();</tt> method. This is required
+ * to register the SMB protocol handler.
+ * <p>
+ * The userinfo component of the SMB URL (<tt>domain;user:pass</tt>) must
+ * be URL encoded if it contains reserved characters. According to RFC 2396
+ * these characters are non US-ASCII characters and most meta characters
+ * however jCIFS will work correctly with anything but '@' which is used
+ * to delimit the userinfo component from the server and '%' which is the
+ * URL escape character itself.
+ * <p>
+ * The server
  * component may a traditional NetBIOS name, a DNS name, or IP
  * address. These name resolution mechanisms and their resolution order
  * can be changed (See <a href="../../../resolver.html">Setting Name
@@ -84,9 +84,8 @@ When used in conjunction with the <code>list</code>
  * JCIFS Properties</a>). Here are some examples of SMB URLs with brief
  * descriptions of what they do:
  *
- * <p><b>*</b> This URL scheme is based largely on the <a target="_top"
- * href="http://www.ietf.org/internet-drafts/draft-crhertel-smb-url-02.txt">SMB
- * Filesharing URL Scheme</a> IETF draft.
+ * <p>[1] This URL scheme is based largely on the <i>SMB
+ * Filesharing URL Scheme</i> IETF draft.
  * 
  * <p><table border="1" cellpadding="3" cellspacing="0" width="100%">
  * <tr bgcolor="#ccccff">
@@ -156,6 +155,15 @@ When used in conjunction with the <code>list</code>
  * URLs that represent workgroups, servers, shares, or directories require a trailing slash '/'.
  * </td></tr>
  *
+ * <tr><td width="20%">
+ * <code>smb://MYGROUP/?SERVER=192.168.10.15</code></td><td>
+ * SMB URLs support some query string parameters. In this example
+ * the <code>SERVER</code> parameter is used to override the
+ * server name service lookup to contact the server 192.168.10.15
+ * (presumably known to be a master
+ * browser) for the server list in workgroup <code>MYGROUP</code>.
+ * </td></tr>
+ *
  * </table>
  * 
  * <p>A second constructor argument may be specified to augment the URL
@@ -264,19 +272,31 @@ public class SmbFile extends URLConnection {
 
     // share access
 /**
- * When specified as the <tt>shareAccess</tt> constructor parameter, other SMB clients (including other threads macking calls into jCIFS) will not be permitted to access the target file and will receive "The file is being accessed by another process" message.
+ * When specified as the <tt>shareAccess</tt> constructor parameter,
+ * other SMB clients (including other threads making calls into jCIFS)
+ * will not be permitted to access the target file and will receive "The
+ * file is being accessed by another process" message.
  */
     public static final int FILE_NO_SHARE     = 0x00;
 /**
- * When specified as the <tt>shareAccess</tt> constructor parameter, other SMB clients will be permitted to read from the target file while this file is open. This constant may be logically OR'd with other share access flags.
+ * When specified as the <tt>shareAccess</tt> constructor parameter,
+ * other SMB clients will be permitted to read from the target file while
+ * this file is open. This constant may be logically OR'd with other share
+ * access flags.
  */
     public static final int FILE_SHARE_READ   = 0x01;
 /**
- * When specified as the <tt>shareAccess</tt> constructor parameter, other SMB clients will be permitted to write to the target file while this file is open. This constant may be logically OR'd with other share access flags.
+ * When specified as the <tt>shareAccess</tt> constructor parameter,
+ * other SMB clients will be permitted to write to the target file while
+ * this file is open. This constant may be logically OR'd with other share
+ * access flags.
  */
     public static final int FILE_SHARE_WRITE  = 0x02;
 /**
- * When specified as the <tt>shareAccess</tt> constructor parameter, other SMB clients will be permitted to delete the target file while this file is open. This constant may be logically OR'd with other share access flags.
+ * When specified as the <tt>shareAccess</tt> constructor parameter,
+ * other SMB clients will be permitted to delete the target file while
+ * this file is open. This constant may be logically OR'd with other share
+ * access flags.
  */
     public static final int FILE_SHARE_DELETE = 0x04;
 
@@ -289,11 +309,35 @@ public class SmbFile extends URLConnection {
     static final int O_TRUNC  = 0x0002;
 
     // file attribute encoding
+/** 
+ * A file with this bit on as returned by <tt>getAttributes()</tt> or set
+ * with <tt>setAttributes()</tt> will be read-only
+ */ 
     public static final int ATTR_READONLY   = 0x01;
+/** 
+ * A file with this bit on as returned by <tt>getAttributes()</tt> or set
+ * with <tt>setAttributes()</tt> will be hidden
+ */
     public static final int ATTR_HIDDEN     = 0x02;
+/**
+ * A file with this bit on as returned by <tt>getAttributes()</tt> or set
+ * with <tt>setAttributes()</tt> will be a system file
+ */
     public static final int ATTR_SYSTEM     = 0x04;
+/**
+ * A file with this bit on as returned by <tt>getAttributes()</tt> is
+ * a volume
+ */
     public static final int ATTR_VOLUME     = 0x08;
+/**
+ * A file with this bit on as returned by <tt>getAttributes()</tt> is
+ * a directory
+ */
     public static final int ATTR_DIRECTORY  = 0x10;
+/**
+ * A file with this bit on as returned by <tt>getAttributes()</tt> or set
+ * with <tt>setAttributes()</tt> is an archived file
+ */
     public static final int ATTR_ARCHIVE    = 0x20;
 
     // extended file attribute encoding(others same as above)
@@ -398,8 +442,8 @@ public class SmbFile extends URLConnection {
  * the <code>parent SmbFile</code>. See the description above for examples
  * of using the second <code>name</code> parameter.
  *
- * @param   parent A base <code>SmbFile</code>
- * @param   child A path string relative to the <code>parent</code> paremeter
+ * @param   context A base <code>SmbFile</code>
+ * @param   name A path string relative to the <code>parent</code> paremeter
  * @throws  MalformedURLException
  *          If the <code>parent</code> and <code>child</code> parameters
  *          do not follow the prescribed syntax
@@ -407,7 +451,8 @@ public class SmbFile extends URLConnection {
  *          If the server or workgroup of the <tt>context</tt> file cannot be determined
  */
 
-    public SmbFile( SmbFile context, String name ) throws MalformedURLException, UnknownHostException {
+    public SmbFile( SmbFile context, String name )
+                throws MalformedURLException, UnknownHostException {
         this( context.isWorkgroup0() ?
             new URL( null, "smb://" + name, Handler.SMB_HANDLER ) :
             new URL( context.url, name, Handler.SMB_HANDLER ), context.auth );
@@ -427,13 +472,13 @@ public class SmbFile extends URLConnection {
  */
 
     public SmbFile( String context, String name ) throws MalformedURLException {
-        this( new URL( new URL( null, context, Handler.SMB_HANDLER ), name, Handler.SMB_HANDLER ));
+        this( new URL( new URL( null, context, Handler.SMB_HANDLER ),
+                name, Handler.SMB_HANDLER ));
     }
 
 /**
  * Constructs an SmbFile representing a resource on an SMB network such
  * as a file or directory.
-The second parameter may be constructed explicitly or retreived with <tt>HttpServletRequest.getUserPrincipal()</tt> if NTLM HTTP authentication has been successfully negotiated.
  *
  * @param   url A URL string
  * @param   auth The credentials the client should use for authentication
@@ -445,9 +490,12 @@ The second parameter may be constructed explicitly or retreived with <tt>HttpSer
         this( new URL( null, url, Handler.SMB_HANDLER ), auth );
     }
 /**
- * Constructs an SmbFile representing a file on an SMB network.
-The second parameter may be constructed explicitly or retreived with <tt>HttpServletRequest.getUserPrincipal()</tt> if NTLM HTTP authentication has been successfully negotiated.
-The <tt>shareAccess</tt> parameter controls what permissions other clients have when trying to access the same file while this instance is still open. This value is either <tt>FILE_NO_SHARE</tt> or any combination of <tt>FILE_SHARE_READ</tt>, <tt>FILE_SHARE_WRITE</tt>, and <tt>FILE_SHARE_DELETE</tt> logically OR'd together.
+ * Constructs an SmbFile representing a file on an SMB network. The
+ * <tt>shareAccess</tt> parameter controls what permissions other
+ * clients have when trying to access the same file while this instance
+ * is still open. This value is either <tt>FILE_NO_SHARE</tt> or any
+ * combination of <tt>FILE_SHARE_READ</tt>, <tt>FILE_SHARE_WRITE</tt>,
+ * and <tt>FILE_SHARE_DELETE</tt> logically OR'd together.
  *
  * @param   url A URL string
  * @param   auth The credentials the client should use for authentication
@@ -468,7 +516,6 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * as a file or directory. The second parameter is a relative path from
  * the <code>context</code>. See the description above for examples of
  * using the second <code>name</code> parameter.
-The third parameter may be constructed explicitly or retreived with <tt>HttpServletRequest.getUserPrincipal()</tt> if NTLM HTTP authentication has been successfully negotiated.
  *
  * @param   context A URL string
  * @param   name A path string relative to the <code>context</code> paremeter
@@ -485,9 +532,12 @@ The third parameter may be constructed explicitly or retreived with <tt>HttpServ
  * Constructs an SmbFile representing a resource on an SMB network such
  * as a file or directory. The second parameter is a relative path from
  * the <code>context</code>. See the description above for examples of
- * using the second <code>name</code> parameter.
-The third parameter may be constructed explicitly or retreived with <tt>HttpServletRequest.getUserPrincipal()</tt> if NTLM HTTP authentication has been successfully negotiated.
-The <tt>shareAccess</tt> parameter controls what permissions other clients have when trying to access the same file while this instance is still open. This value is either <tt>FILE_NO_SHARE</tt> or any combination of <tt>FILE_SHARE_READ</tt>, <tt>FILE_SHARE_WRITE</tt>, and <tt>FILE_SHARE_DELETE</tt> logically OR'd together.
+ * using the second <code>name</code> parameter. The <tt>shareAccess</tt>
+ * parameter controls what permissions other clients have when trying
+ * to access the same file while this instance is still open. This
+ * value is either <tt>FILE_NO_SHARE</tt> or any combination
+ * of <tt>FILE_SHARE_READ</tt>, <tt>FILE_SHARE_WRITE</tt>, and
+ * <tt>FILE_SHARE_DELETE</tt> logically OR'd together.
  *
  * @param   context A URL string
  * @param   name A path string relative to the <code>context</code> paremeter
@@ -516,7 +566,8 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     }
 /**
  * Constructs an SmbFile representing a resource on an SMB network such
- * as a file or directory from a <tt>URL</tt> object and an <tt>NtlmPasswordAuthentication object which may be constructed explicitly or retreived with <tt>HttpServletRequest.getUserPrincipal()</tt> if NTLM HTTP authentication has been successfully negotiated.
+ * as a file or directory from a <tt>URL</tt> object and an
+ * <tt>NtlmPasswordAuthentication</tt> object.
  *
  * @param   url The URL of the target resource
  * @param   auth The credentials the client should use for authentication
@@ -548,7 +599,10 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         } else {
             this.unc = context.unc + '\\' + name;
         }
-        this.type = type == TYPE_WORKGROUP ? 0 : type;
+    /* why? am I going around in circles?
+     *  this.type = type == TYPE_WORKGROUP ? 0 : type;
+     */
+        this.type = type;
         this.attributes = attributes;
         this.createTime = createTime;
         this.lastModified = lastModified;
@@ -644,9 +698,48 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         }
     }
 
+    static String queryLookup( String query, String param ) {
+        char in[] = query.toCharArray();
+        int i, ch, st, eq;
+
+        st = eq = 0;
+        for( i = 0; i < in.length; i++) {
+            ch = in[i];
+            if( ch == '&' ) {
+                if( eq > st ) {
+                    String p = new String( in, st, eq - st );
+                    if( p.equalsIgnoreCase( param )) {
+                        eq++;
+                        return new String( in, eq, i - eq );
+                    }
+                }
+                st = i + 1;
+            } else if( ch == '=' ) {
+                eq = i;
+            }
+        }
+        if( eq > st ) {
+            String p = new String( in, st, eq - st );
+            if( p.equalsIgnoreCase( param )) {
+                eq++;
+                return new String( in, eq, in.length - eq );
+            }
+        }
+
+        return null;
+    }
+
     UniAddress getAddress() throws UnknownHostException {
         String host = url.getHost();
         String path = url.getPath();
+        String query = url.getQuery();
+
+        if( query != null ) {
+            String server = queryLookup( query, "server" );
+            if( server != null && server.length() > 0 ) {
+                return UniAddress.getByName( server );
+            }
+        }
 
         if( host.length() == 0 ) {
             return UniAddress.getByName( NbtAddress.getByName(
@@ -668,6 +761,10 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
             throw new SmbException( "Failed to connect to server", ioe );
         }
     }
+/**
+ * It is not necessary to call this method directly. This is the
+ * <tt>URLConnection</tt> implementation of <tt>connect()</tt>.
+ */
     public void connect() throws IOException {
         SmbTransport trans;
         SmbSession ssn;
@@ -693,7 +790,8 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
                 ssn = trans.getSmbSession( NtlmPasswordAuthentication.NULL );
                 tree = ssn.getSmbTree( null, null );
                 tree.treeConnect( null, null );
-            } else if(( a = NtlmAuthenticator.requestNtlmPasswordAuthentication( url.toString(), sae )) != null ) {
+            } else if(( a = NtlmAuthenticator.requestNtlmPasswordAuthentication(
+                        url.toString(), sae )) != null ) {
                 auth = a;
                 ssn = trans.getSmbSession( auth );
                 tree = ssn.getSmbTree( share, null );
@@ -715,11 +813,13 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
             log.println( "open0: " + unc );
 
         /*
-         * Open AndX Request / Response
+         * NT Create AndX / Open AndX Request / Response
          */
+
         if( tree.session.transport.hasCapability( ServerMessageBlock.CAP_NT_SMBS )) {
             SmbComNTCreateAndXResponse response = new SmbComNTCreateAndXResponse();
-            send( new SmbComNTCreateAndX( unc, flags, shareAccess, attrs, options, null ), response );
+            send( new SmbComNTCreateAndX( unc, flags, shareAccess,
+                    attrs, options, null ), response );
             f = response.fid;
             attributes = response.extFileAttributes & ATTR_GET_MASK;
             attrExpiration = System.currentTimeMillis() + attrExpirationPeriod;
@@ -772,8 +872,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * the root URL <code>smb://</code> is also <code>smb://</code>. If this
  * <tt>SmbFile</tt> refers to a workgroup, server, share, or directory,
  * the name will include a trailing slash '/' so that composing new
- * <tt>SmbFile</tt>s will maintain the trailing slash requirement introduced
- * in jcifs-0.7.0b4.
+ * <tt>SmbFile</tt>s will maintain the trailing slash requirement.
  *
  * @return  The last component of the URL associated with this SMB
  *          resource or <code>smb://</code> if the resource is <code>smb://</code>
@@ -851,11 +950,13 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         if( unc == null ) {
             char[] in = url.getPath().toCharArray();
             char[] out = new char[in.length];
-            int i, o, state, s;
+            int length = in.length, i, o, state, s;
 
+                              /* The canonicalization routine
+                               */
             state = 0;
             o = 0;
-            for( i = 0; i < in.length; i++ ) {
+            for( i = 0; i < length; i++ ) {
                 switch( state ) {
                     case 0:
                         if( in[i] != '/' ) {
@@ -868,13 +969,13 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
                         if( in[i] == '/' ) {
                             break;
                         } else if( in[i] == '.' &&
-                                    (( i + 1 ) >= in.length || in[i + 1] == '/' )) {
+                                    (( i + 1 ) >= length || in[i + 1] == '/' )) {
                             i++;
                             break;
-                        } else if(( i + 1 ) < in.length &&
+                        } else if(( i + 1 ) < length &&
                                     in[i] == '.' &&
                                     in[i + 1] == '.' &&
-                                    (( i + 2 ) >= in.length || in[i + 2] == '/' )) {
+                                    (( i + 2 ) >= length || in[i + 2] == '/' )) {
                             i += 2;
                             if( o == 1 ) break;
                             do {
@@ -947,8 +1048,8 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
 
 /**
  * Retrieves the share associated with this SMB resource. In
- * the case of <code>smb://</code>, <code>smb://workgroup</code>,
- * and <code>smb://server</code> URLs which do not specify a share,
+ * the case of <code>smb://</code>, <code>smb://workgroup/</code>,
+ * and <code>smb://server/</code> URLs which do not specify a share,
  * <code>null</code> will be returned.
  *
  * @return  The share component or <code>null</code> if there is no share
@@ -1172,7 +1273,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * Tests to see if the file this <code>SmbFile</code> represents
  * exists and is not marked read-only. By default, resources are
  * considered to be read-only and therefore for <code>smb://</code>,
- * <code>smb://workgroup</code>, and <code>smb://server</code> resources
+ * <code>smb://workgroup/</code>, and <code>smb://server/</code> resources
  * will be read-only.
  *
  * @return  <code>true</code> if the resource exists is not marked
@@ -1215,7 +1316,9 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     }
 
 /**
- * Tests to see if the file this SmbFile represents is marked as hidden.
+ * Tests to see if the file this SmbFile represents is marked as
+ * hidden. This method will also return true for shares with names that
+ * end with '$' such as <code>IPC$</code> or <code>C$</code>.
  *
  * @return <code>true</code> if the <code>SmbFile</code> is marked as being hidden
  */
@@ -1234,7 +1337,9 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     }
 
 /**
- * Retrieves the DFS path or <tt>null</tt> if the path specified does not fall within a DFS volume.
+ * If the path of this <code>SmbFile</code> falls within a DFS volume,
+ * this method will return the referral path to which it maps. Otherwise
+ * <code>null</code> is returned.
  */
 
     public String getDfsPath() throws SmbException {
@@ -1249,9 +1354,9 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     }
 
 /**
- * Retrieve the time this <code>SmbFile</code> was created. The value returned is suitable
- * for constructing a {@link java.util.Date} object and is adjusted for
- * the servers timezone differential. Times should be the same as those
+ * Retrieve the time this <code>SmbFile</code> was created. The value
+ * returned is suitable for constructing a {@link java.util.Date} object
+ * (i.e. seconds since Epoch 1970). Times should be the same as those
  * reported using the properties dialog of the Windows Explorer program.
  *
  * For Win95/98/Me this is actually the last write time. It is currently
@@ -1260,7 +1365,6 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * @return The number of milliseconds since the 00:00:00 GMT, January 1,
  *         1970 as a <code>long</code> value
  */
-
     public long createTime() throws SmbException {
         if( getUncPath0().length() > 1 ) {
             exists();
@@ -1270,15 +1374,14 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     }
 /**
  * Retrieve the last time the file represented by this
- * <code>SmbFile</code> was modified. The value returned is suitable
- * for constructing a {@link java.util.Date} object and is adjusted for
- * the servers timezone differential. Times should be the same as those
- * reported using the properties dialog of the Windows Explorer program.
+ * <code>SmbFile</code> was modified. The value returned is suitable for
+ * constructing a {@link java.util.Date} object (i.e. seconds since Epoch
+ * 1970). Times should be the same as those reported using the properties
+ * dialog of the Windows Explorer program.
  *
  * @return The number of milliseconds since the 00:00:00 GMT, January 1,
  *         1970 as a <code>long</code> value
  */
-
     public long lastModified() throws SmbException {
         if( getUncPath0().length() > 1 ) {
             exists();
@@ -1286,7 +1389,6 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         }
         return 0L;
     }
-
 /**
  * List the contents of this SMB resource. The list returned by this
  * method will be;
@@ -1297,10 +1399,10 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * <li> all available NetBIOS workgroups or domains if this resource is
  * the top level URL <code>smb://</code>,
  * <li> all servers registered as members of a NetBIOS workgroup if this
- * resource refers to a workgroup in a <code>smb://workgroup</code> URL,
+ * resource refers to a workgroup in a <code>smb://workgroup/</code> URL,
  * <li> all browseable shares of a server including printers, IPC
  * services, or disk volumes if this resource is a server URL in the form
- * <code>smb://server</code>,
+ * <code>smb://server/</code>,
  * <li> or <code>null</code> if the resource cannot be resolved.
  * </ul>
  *
@@ -1308,10 +1410,19 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * workgroups, servers, or shares depending on the context of the
  * resource URL
  */
-
     public String[] list() throws SmbException {
         return list( "*", ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM, null, null );
     }
+
+/**
+ * List the contents of this SMB resource. The list returned will be
+ * identical to the list returned by the parameterless <code>list()</code>
+ * method minus filenames filtered by the specified filter.
+ *
+ * @param filter a filename filter to exclude filenames from the results
+ * @throws SmbException
+ # @return An array of filenames
+ */
     public String[] list( SmbFilenameFilter filter ) throws SmbException {
         return list( "*", ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM, filter, null );
     }
@@ -1330,10 +1441,10 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * <li> all available NetBIOS workgroups or domains if this resource is
  * the top level URL <code>smb://</code>,
  * <li> all servers registered as members of a NetBIOS workgroup if this
- * resource refers to a workgroup in a <code>smb://workgroup</code> URL,
+ * resource refers to a workgroup in a <code>smb://workgroup/</code> URL,
  * <li> all browseable shares of a server including printers, IPC
  * services, or disk volumes if this resource is a server URL in the form
- * <code>smb://server</code>,
+ * <code>smb://server/</code>,
  * <li> or <code>null</code> if the resource cannot be resolved.
  * </ul>
  *
@@ -1341,7 +1452,6 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * and directories, workgroups, servers, or shares depending on the context
  * of the resource URL
  */
-
     public SmbFile[] listFiles() throws SmbException {
         return listFiles( "*", ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM, null, null );
     }
@@ -1349,7 +1459,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
 /**
  * The CIFS protocol provides for DOS "wildcards" to be used as
  * a performance enhancement. The client does not have to filter
- * the names ane the server does not have to return all directory
+ * the names and the server does not have to return all directory
  * entries.
  * <p>
  * The wildcard expression may consist of two special meta
@@ -1378,9 +1488,26 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     public SmbFile[] listFiles( String wildcard ) throws SmbException {
         return listFiles( wildcard, ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM, null, null );
     }
+/**
+ * List the contents of this SMB resource. The list returned will be
+ * identical to the list returned by the parameterless <code>listFiles()</code>
+ * method minus files filtered by the specified filename filter.
+ *
+ * @param filter a filter to exclude files from the results
+ * @return An array of <tt>SmbFile</tt> objects
+ * @throws SmbException
+ */
     public SmbFile[] listFiles( SmbFilenameFilter filter ) throws SmbException {
         return listFiles( "*", ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM, filter, null );
     }
+/**
+ * List the contents of this SMB resource. The list returned will be
+ * identical to the list returned by the parameterless <code>listFiles()</code>
+ * method minus filenames filtered by the specified filter.
+ *
+ * @param filter a file filter to exclude files from the results
+ * @return An array of <tt>SmbFile</tt> objects
+ */
     public SmbFile[] listFiles( SmbFileFilter filter ) throws SmbException {
         return listFiles( "*", ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM, null, filter );
     }
@@ -1433,12 +1560,14 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
                 String wildcard,
                 int searchAttributes,
                 SmbFilenameFilter fnf,
-                SmbFileFilter ff ) throws SmbException, UnknownHostException, MalformedURLException {
+                SmbFileFilter ff ) throws SmbException,
+                        UnknownHostException, MalformedURLException {
         SmbComTransaction req;
         SmbComTransactionResponse resp;
         int listType = url.getAuthority().length() == 0 ? 0 : getType();
+        String p = url.getPath();
 
-        if( url.toString().lastIndexOf( '/' ) != ( url.toString().length() - 1 )) {
+        if( p.lastIndexOf( '/' ) != ( p.length() - 1 )) {
             throw new SmbException( url.toString() + " directory must end with '/'" );
         }
 
@@ -1461,33 +1590,40 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
                 throw new SmbException( "The requested list operations is invalid: " + url.toString() );
         }
 
-        sendTransaction( req, resp );
-
-        if( resp.status != SmbException.ERROR_SUCCESS &&
-                resp.status != SmbException.ERROR_MORE_DATA ) {
-            throw new SmbException( resp.status, true );
-        }
-
-        for( int i = 0; i < resp.numEntries; i++ ) {
-            FileEntry e = resp.results[i];
-            String name = e.getName();
-            if( fnf != null && fnf.accept( this, name ) == false ) {
-                continue;
+        do {
+            sendTransaction( req, resp );
+    
+            if( resp.status != SmbException.ERROR_SUCCESS &&
+                    resp.status != SmbException.ERROR_MORE_DATA ) {
+                throw new SmbException( resp.status, true );
             }
-            if( name.length() > 0 ) {
-                SmbFile f = new SmbFile( this, name,
-                            listType == 0 ? TYPE_WORKGROUP : listType,
-                            ATTR_READONLY | ATTR_DIRECTORY, 0L, 0L, 0L );
-                if( ff != null && ff.accept( f ) == false ) {
+    
+            for( int i = 0; i < resp.numEntries; i++ ) {
+                FileEntry e = resp.results[i];
+                String name = e.getName();
+                if( fnf != null && fnf.accept( this, name ) == false ) {
                     continue;
                 }
-                if( files ) {
-                    list.add( f );
-                } else {
-                    list.add( name );
+                if( name.length() > 0 ) {
+                    SmbFile f = new SmbFile( this, name,
+                                listType == 0 ? TYPE_WORKGROUP : (listType << 1),
+                                ATTR_READONLY | ATTR_DIRECTORY, 0L, 0L, 0L );
+                    if( ff != null && ff.accept( f ) == false ) {
+                        continue;
+                    }
+                    if( files ) {
+                        list.add( f );
+                    } else {
+                        list.add( name );
+                    }
                 }
             }
-        }
+            if( listType != 0 || listType != TYPE_WORKGROUP ) {
+                break;
+            }
+            req.subCommand = (byte)SmbComTransaction.NET_SERVER_ENUM3;
+            req.reset( 0, ((NetServerEnum2Response)resp).lastName );
+        } while( resp.status == SmbException.ERROR_MORE_DATA );
     }
     void doFindFirstNext( ArrayList list,
                 boolean files,
@@ -1499,8 +1635,9 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         Trans2FindFirst2Response resp;
         int sid;
         String path = getUncPath0();
+        String p = url.getPath();
 
-        if( url.toString().lastIndexOf( '/' ) != ( url.toString().length() - 1 )) {
+        if( p.lastIndexOf( '/' ) != ( p.length() - 1 )) {
             throw new SmbException( url.toString() + " directory must end with '/'" );
         }
 
@@ -1561,17 +1698,18 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
 
 /**
  * Changes the name of the file this <code>SmbFile</code> represents to the name
- * designated by the <code>SmbFile</code> argument(Remember:
- * <code>SmbFile</code>s are immutible
- * and therefore the path associated with this <code>SmbFile</code> object will not
- * change).
+ * designated by the <code>SmbFile</code> argument.
+ * <p/>
+ * <i>Remember: <code>SmbFile</code>s are immutible and therefore
+ * the path associated with this <code>SmbFile</code> object will not
+ * change). To access the renamed file it is necessary to construct a
+ * new <tt>SmbFile</tt></i>.
  *
  * @param  dest  An <code>SmbFile</code> that represents the new pathname
  * @return <code>true</code> if the file or directory was successfully renamed
  * @throws NullPointerException
  *         If the <code>dest</code> argument is <code>null</code>
  */
-
     public void renameTo( SmbFile dest ) throws SmbException {
         if( getUncPath0().length() == 1 || dest.getUncPath0().length() == 1 ) {
             throw new SmbException( "Invalid operation for workgroups, servers, or shares" );
@@ -1610,7 +1748,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     class WriterThread extends Thread {
         byte[] b;
         int n, off;
-        boolean ready = true;
+        boolean ready;
         SmbFile dest;
         SmbException e = null;
         boolean useNTSmbs;
@@ -1628,6 +1766,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
                 req = new SmbComWrite();
                 resp = new SmbComWriteResponse();
             }
+            ready = false;
         }
 
         synchronized void write( byte[] b, int n, SmbFile dest, int off ) {
@@ -1643,6 +1782,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
             synchronized( this ) {
                 try {
                     for( ;; ) {
+                        notify();
                         ready = true;
                         while( ready ) {
                             wait();
@@ -1657,7 +1797,6 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
                             req.setParam( dest.fid, off, n, b, 0, n );
                             dest.send( req, resp );
                         }
-                        notify();
                     }
                 } catch( SmbException e ) {
                     this.e = e;
@@ -1776,12 +1915,20 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         }
     }
 /**
- * This method will copy the file or directory and it's subcontents
- * represented by this <tt>SmbFile</tt> to the location specified by the
+ * This method will copy the file or directory represented by this
+ * <tt>SmbFile</tt> and it's sub-contents to the location specified by the
  * <tt>dest</tt> parameter. This file and the destination file do not
  * need to be on the same host. This operation does not copy extended
- * file attibutes such as ACLs but regular attributes and create and
- * last write times will be preserved.
+ * file attibutes such as ACLs but it does copy regular attributes as
+ * well as create and last write times. This method is almost twice as
+ * efficient as manually copying as it employs an additional write
+ * thread to read and write data concurrently.
+ * <p/>
+ * It is not possible (nor meaningful) to copy entire workgroups or
+ * servers.
+ *
+ * @param dest the destination file or directory
+ * @throw SmbException
  */
     public void copyTo( SmbFile dest ) throws SmbException {
         SmbComReadAndX req;
@@ -1793,7 +1940,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         /* Should be able to copy an entire share actually
          */
         if( share == null || dest.share == null) {
-            throw new SmbException( "Invalid operation for workgroups, servers, or shares" );
+            throw new SmbException( "Invalid operation for workgroups or servers" );
         }
 
         req = new SmbComReadAndX();
@@ -1832,11 +1979,11 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * This method will delete the file or directory specified by this
  * <code>SmbFile</code>. If the target is a directory, the contents of
  * the directory will be deleted as well. If a file within the directory or
- * it's sub-directories is marked read-only, the read-only status will be removed and the file will be deleted.
+ * it's sub-directories is marked read-only, the read-only status will
+ * be removed and the file will be deleted.
  *
  * @throws SmbException
  */
-
     public void delete() throws SmbException {
         if( tree == null || tree.inDfs ) {
             exists();      /* This is necessary to ensure we
@@ -1882,7 +2029,8 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
             /* Recursively delete directory contents
              */
 
-            SmbFile[] l = listFiles( "*", ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM, null, null );
+            SmbFile[] l = listFiles( "*",
+                    ATTR_DIRECTORY | ATTR_HIDDEN | ATTR_SYSTEM, null, null );
 
             for( int i = 0; i < l.length; i++ ) {
                 l[i].delete();
@@ -1897,11 +2045,14 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     }
 
 /**
- * Returns the length of this <tt>SmbFile</tt> in bytes.
- * If this object is a <tt>TYPE_SHARE</tt> the total capacity of the disk shared in bytes is returned.
- * If this object is a directory or a type other than <tt>TYPE_SHARE</tt>, 0L is returned.
+ * Returns the length of this <tt>SmbFile</tt> in bytes. If this object
+ * is a <tt>TYPE_SHARE</tt> the total capacity of the disk shared in
+ * bytes is returned. If this object is a directory or a type other than
+ * <tt>TYPE_SHARE</tt>, 0L is returned.
  *
- * @return The length of the file in bytes or 0 if this <code>SmbFile</code> is not a file.
+ * @return The length of the file in bytes or 0 if this
+ * <code>SmbFile</code> is not a file.
+ * @throw SmbException
  */
 
     public long length() throws SmbException {
@@ -1933,6 +2084,9 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * represents or the drive on which the directory or file resides. Objects
  * other than <tt>TYPE_SHARE</tt> or <tt>TYPE_FILESYSTEM</tt> will result
  * in 0L being returned.
+ *
+ * @return the free disk space in bytes of the drive on which this file or
+ * directory resides
  */
     public long getDiskFreeSpace() throws SmbException {
         if( getType() == TYPE_SHARE || type == TYPE_FILESYSTEM ) {
@@ -1954,15 +2108,15 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
 
 /**
  * Creates a directory with the path specified by this
- * <code>SmbFile</code>. For this method to be successfull, the target
+ * <code>SmbFile</code>. For this method to be successful, the target
  * must not already exist. This method will fail when
- * used with <code>smb://</code>, <code>smb://workgroup</code>,
- * <code>smb://server</code>, or <code>smb://server/share</code> URLs
- * because workgroups, servers, and shares cannot be dynamically created.
+ * used with <code>smb://</code>, <code>smb://workgroup/</code>,
+ * <code>smb://server/</code>, or <code>smb://server/share/</code> URLs
+ * because workgroups, servers, and shares cannot be dynamically created
+ * (although in the future it may be possible to create shares).
  *
  * @throws SmbException
  */
-
     public void mkdir() throws SmbException {
         String path = getUncPath0();
 
@@ -1981,13 +2135,14 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
 
         attrExpiration = sizeExpiration = 0;
     }
+
 /**
- * Creates a directory with the path specified by this <tt>SmbFile</tt> and any parent directories if necessary.
- * For this method to be successfull, the target
- * must not already exist. This method will fail when
- * used with <code>smb://</code>, <code>smb://workgroup</code>,
- * <code>smb://server</code>, or <code>smb://server/share</code> URLs
- * because workgroups, servers, and shares cannot be dynamically created.
+ * Creates a directory with the path specified by this <tt>SmbFile</tt>
+ * and any parent directories that do not exist. This method will fail
+ * when used with <code>smb://</code>, <code>smb://workgroup/</code>,
+ * <code>smb://server/</code>, or <code>smb://server/share/</code> URLs
+ * because workgroups, servers, and shares cannot be dynamically created
+ * (although in the future it may be possible to create shares).
  *
  * @throws SmbException
  */
@@ -2005,6 +2160,11 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         mkdir();
     }
 
+/**
+ * Create a new file but fail if it already exists. The check for
+ * existance of the file and it's creation are an atomic operation with
+ * respect to other filesystem activities.
+ */
     public void createNewFile() throws SmbException {
         if( getUncPath0().length() == 1 ) {
             throw new SmbException( "Invalid operation for workgroups, servers, or shares" );
@@ -2027,6 +2187,15 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         attrExpiration = 0;
     }
 
+/**
+ * Set the create time of the file. The time is specified as milliseconds
+ * from Jan 1, 1970 which is the same as that which is returned by the
+ * <tt>createTime()</tt> method.
+ * <p/>
+ * This method does not apply to workgroups, servers, or shares.
+ *
+ * @param time the create time as milliseconds since Jan 1, 1970
+ */
     public void setCreateTime( long time ) throws SmbException {
         if( getUncPath0().length() == 1 ) {
             throw new SmbException( "Invalid operation for workgroups, servers, or shares" );
@@ -2034,6 +2203,15 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
 
         setPathInformation( 0, time, 0L );
     }
+/**
+ * Set the last modified time of the file. The time is specified as milliseconds
+ * from Jan 1, 1970 which is the same as that which is returned by the
+ * <tt>lastModified()</tt>, <tt>getLastModified()</tt>, and <tt>getDate()</tt> methods.
+ * <p/>
+ * This method does not apply to workgroups, servers, or shares.
+ *
+ * @param time the last modified time as milliseconds since Jan 1, 1970
+ */
     public void setLastModified( long time ) throws SmbException {
         if( getUncPath0().length() == 1 ) {
             throw new SmbException( "Invalid operation for workgroups, servers, or shares" );
@@ -2042,6 +2220,15 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         setPathInformation( 0, 0L, time );
     }
 
+/**
+ * Return the attributes of this file. Attributes are represented as a
+ * bitset that must be masked with <tt>ATTR_*</tt> constants to determine
+ * if they are set or unset. The value returned is suitable for use with
+ * the <tt>setAttributes()</tt> method.
+ *
+ * @return the <tt>ATTR_*</tt> attributes associated with this file
+ * @throw SmbException
+ */
     public int getAttributes() throws SmbException {
         if( getUncPath0().length() == 1 ) {
             return 0;
@@ -2050,6 +2237,13 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         return attributes & ATTR_GET_MASK;
     }
 
+/**
+ * Set the attributes of this file. Attributes are composed into a
+ * bitset by bitwise ORing the <tt>ATTR_*</tt> constants. Setting the
+ * value returned by <tt>getAttributes</tt> will result in both files
+ * having the same attributes.
+ * @throw SmbException
+ */
     public void setAttributes( int attrs ) throws SmbException {
         if( getUncPath0().length() == 1 ) {
             throw new SmbException( "Invalid operation for workgroups, servers, or shares" );
@@ -2058,10 +2252,22 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         setPathInformation( attrs & ATTR_SET_MASK, 0L, 0L );
     }
 
+/**
+ * Make this file read-only. This is shorthand for <tt>setAttributes(
+ * getAttributes() | ATTR_READ_ONLY )</tt>.
+ *
+ * @throw SmbException
+ */
     public void setReadOnly() throws SmbException {
         setAttributes( getAttributes() | ATTR_READONLY );
     }
 
+/**
+ * Turn off the read-only attribute of this file. This is shorthand for
+ * <tt>setAttributes( getAttributes() & ~ATTR_READONLY )</tt>.
+ *
+ * @throw SmbException
+ */
     public void setReadWrite() throws SmbException {
         setAttributes( getAttributes() & ~ATTR_READONLY );
     }
@@ -2070,13 +2276,12 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * Returns a {@link java.net.URL} for this <code>SmbFile</code>. The
  * <code>URL</code> may be used as any other <code>URL</code> might to
  * access an SMB resource. Currently only retrieving data and information
- * is supported.
+ * is supported (i.e. no <tt>doOutput</tt>).
  *
  * @depricated Use getURL() instead
- *
- * @return   A new <code>{@link java.net.URL}</code> for this <code>SmbFile</code>
+ * @return A new <code>{@link java.net.URL}</code> for this <code>SmbFile</code>
+ * @throw MalformedURLException
  */
-
     public URL toURL() throws MalformedURLException {
         return url;
     }
@@ -2091,6 +2296,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * to make such a determination.
  *
  * @return  A hashcode for this abstract file
+ * @throw SmbException
  */
 
     public int hashCode() {
@@ -2110,10 +2316,11 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * resource. More specifically, two <code>SmbFile</code> objects are
  * equals if their server IP addresses are equal and the canonicalized
  * representation of their URLs, minus authentication parameters, are
- * case insensitivly and lexographically equal. For example, assuming the
- * server <code>angus</code> resolves to the <code>192.168.1.15</code>
- * IP address, the below URLs would result in <code>SmbFile</code>s
- * that are equal.
+ * case insensitivly and lexographically equal.
+ * <p/>
+ * For example, assuming the server <code>angus</code> resolves to the
+ * <code>192.168.1.15</code> IP address, the below URLs would result in
+ * <code>SmbFile</code>s that are equal.
  *
  * <p><blockquote><pre>
  * smb://192.168.1.15/share/DIR/foo.txt
@@ -2123,6 +2330,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * @param   obj Another <code>SmbFile</code> object to compare for equality
  * @return  <code>true</code> if the two objects refer to the same SMB resource
  *          and <code>false</code> otherwise
+ * @throw SmbException
  */
 
     public boolean equals( Object obj ) {
@@ -2136,6 +2344,7 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
  * as <code>getPath</code>.
  *
  * @return  The original URL representation of this SMB resource
+ * @throw SmbException
  */
 
     public String toString() {
@@ -2143,6 +2352,11 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
     }
 
 /* URLConnection implementation */
+/**
+ * This URLConnection method just returns the result of <tt>length()</tt>.
+ *
+ * @return the length of this file or 0 if it refers to a directory
+ */
 
     public int getContentLength() {
         try {
@@ -2151,6 +2365,12 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         }
         return 0;
     }
+
+/**
+ * This URLConnection method just returns the result of <tt>lastModified</tt>.
+ *
+ * @return the last modified data as milliseconds since Jan 1, 1970
+ */
     public long getDate() {
         try {
             return lastModified();
@@ -2158,6 +2378,12 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         }
         return 0L;
     }
+
+/**
+ * This URLConnection method just returns the result of <tt>lastModified</tt>.
+ *
+ * @return the last modified data as milliseconds since Jan 1, 1970
+ */
     public long getLastModified() {
         try {
             return lastModified();
@@ -2165,6 +2391,12 @@ The <tt>shareAccess</tt> parameter controls what permissions other clients have
         }
         return 0L;
     }
+
+/**
+ * This URLConnection method just returns a new <tt>SmbFileInputStream</tt> created with this file.
+ *
+ * @throw IOException thrown by <tt>SmbFileInputStream</tt> constructor
+ */
     public InputStream getInputStream() throws IOException {
         return new SmbFileInputStream( this );
     }
index 91e6548..ec54b9f 100644 (file)
@@ -145,6 +145,7 @@ public final class SmbSession {
     }
     void sessionSetup( ServerMessageBlock andx,
                             ServerMessageBlock andxResponse ) throws SmbException {
+
 synchronized( transport() ) {
         if( sessionSetup ) {
             return;
@@ -152,19 +153,6 @@ synchronized( transport() ) {
 
         transport.negotiate();
 
-        /* Create SMB signature digest if necessary
-         */
-
-        if(( transport.flags2 & ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES ) != 0 &&
-                (transport.dig == null || transport.dig.sessionSetup == false) &&
-                                         /* Only the first SMB_COM_SESSION_SETUP_ANX
-                                          * with creds other than NULL initializes
-                                          * signing */
-                auth != NtlmPasswordAuthentication.NULL &&
-                NtlmPasswordAuthentication.NULL.equals( auth ) == false ) {
-            transport.dig = new SigningDigest( transport, auth );
-        }
-
         /*
          * Session Setup And X Request / Response
          */
@@ -174,13 +162,33 @@ synchronized( transport() ) {
 
         SmbComSessionSetupAndX request = new SmbComSessionSetupAndX( this, andx );
         SmbComSessionSetupAndXResponse response = new SmbComSessionSetupAndXResponse( andxResponse );
+
+        /* Create SMB signature digest if necessary
+         * Only the first SMB_COM_SESSION_SETUP_ANX with creds other than NULL initializes signing.
+         */
+        if( transport.isSignatureSetupRequired( auth )) {
+            if( auth.hashesExternal && NtlmPasswordAuthentication.DEFAULT_PASSWORD != null ) {
+                /* preauthentication
+                 */
+                transport.getSmbSession( NtlmPasswordAuthentication.DEFAULT ).getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
+            }
+            request.digest = new SigningDigest( transport, auth );
+        }
+
         request.auth = auth;
         transport.send( request, response );
 
+        if( response.isLoggedInAsGuest && "GUEST".equals( auth.username )) {
+            throw new SmbAuthException( NtStatus.NT_STATUS_LOGON_FAILURE );
+        }
+
         uid = response.uid;
         sessionSetup = true;
-        if( transport.dig != null )
-            transport.dig.sessionSetup = true;
+
+        if( request.digest != null ) {
+            /* success - install the signing digest */
+            transport.digest = request.digest;
+        }
 }
     }
     void logoff( boolean inError ) {
index 35f5f59..445825a 100644 (file)
@@ -158,7 +158,7 @@ private static byte[] rcv_buf = new byte[0xFFFF];
     boolean useUnicode = USE_UNICODE;
     String tconHostName;
     ServerData server;
-    SigningDigest dig;
+    SigningDigest digest = null;
 
     static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
         return getSmbTransport( address, port, LADDR, LPORT );
@@ -246,6 +246,12 @@ private static byte[] rcv_buf = new byte[0xFFFF];
         }
         return (capabilities & cap) == cap;
     }
+    boolean isSignatureSetupRequired( NtlmPasswordAuthentication auth ) {
+        return ( flags2 & ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES ) != 0 &&
+                digest == null &&
+                auth != NtlmPasswordAuthentication.NULL &&
+                NtlmPasswordAuthentication.NULL.equals( auth ) == false;
+    }
     void ensureOpen() throws IOException {
         if( socket == null ) {
             Object obj;
@@ -320,7 +326,7 @@ private static byte[] rcv_buf = new byte[0xFFFF];
             } catch( IOException ioe ) {
             }
         }
-        dig = null;
+        digest = null;
         in = null;
         out = null;
         socket = null;
@@ -425,9 +431,9 @@ synchronized( rcv_buf ) {
 
                             if( response.errorCode != 0 || e.hasMoreElements() == false ) {
                                 ((SmbComTransactionResponse)response).hasMore = false;
-                                if( dig != null ) {
+                                if( digest != null ) {
                                     synchronized( outLock ) {
-                                        dig.verify(rcv_buf, 0, response);
+                                        digest.verify(rcv_buf, 0, response);
                                     }
                                 }
                                 response.notify();
@@ -449,10 +455,9 @@ synchronized( rcv_buf ) {
                                     Hexdump.hexdump( log, rcv_buf, 0, Math.min( response.length, 1024 ));
                                 }
                             }
-
-                            if( dig != null && (response.errorCode == 0 || response.command != ServerMessageBlock.SMB_COM_SESSION_SETUP_ANDX )) {
+                            if( digest != null ) {
                                 synchronized( outLock ) {
-                                    dig.verify(rcv_buf, 0, response);
+                                    digest.verify(rcv_buf, 0, response);
                                 }
                             }
 
@@ -554,10 +559,9 @@ synchronized( rcv_buf ) {
                     request.mid = mid.mid;
                     ensureOpen();
 synchronized( snd_buf ) {
+                    request.digest = digest;
+                    request.response = null;
                     int length = request.writeWireFormat(snd_buf, 4);
-                    if( dig != null ) {
-                        dig.sign(snd_buf, 4, length, request, null );
-                    }
                     out.write(snd_buf, 4, length);
                     out.flush();
 
@@ -597,10 +601,11 @@ synchronized( snd_buf ) {
                     responseTable.put( mid, response );
                     ensureOpen();
 synchronized( snd_buf ) {
-                    int length = request.writeWireFormat(snd_buf, 4);
-                    if( dig != null ) {
-                        dig.sign( snd_buf, 4, length, request, response );
+                    if( digest != null ) {
+                        request.digest = digest;
+                        request.response = response;
                     }
+                    int length = request.writeWireFormat(snd_buf, 4);
                     out.write(snd_buf, 4, length);
                     out.flush();
 
@@ -652,6 +657,7 @@ synchronized( snd_buf ) {
             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 ) {
@@ -694,10 +700,9 @@ synchronized( snd_buf ) {
                         responseTable.put( mid, interimResponse );
                         ensureOpen();
 synchronized(snd_buf) {
+                        request.digest = digest;
+                        request.response = response;
                         int length = request.writeWireFormat(snd_buf, 4);
-                        if( dig != null ) {
-                            dig.sign(snd_buf, 4, length, request, response);
-                        }
                         out.write(snd_buf, 4, length);
                         out.flush();
 
@@ -727,6 +732,7 @@ synchronized(snd_buf) {
                         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 ) {
@@ -752,10 +758,9 @@ synchronized(snd_buf) {
                     synchronized( outLock ) {
                         ensureOpen();
 synchronized( snd_buf ) {
+                        request.digest = digest;
+                        request.response = response;
                         int length = request.writeWireFormat(snd_buf, 4);
-                        if( dig != null ) {
-                            dig.sign(snd_buf, 4, length, request, response);
-                        }
                         out.write(snd_buf, 4, length);
                         out.flush();
 
@@ -808,6 +813,7 @@ synchronized( snd_buf ) {
             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 ) {
index f594435..7f032de 100644 (file)
@@ -53,9 +53,10 @@ class SmbTree {
         // transactions are not batchable
         treeConnect( null, null );
         if( service.equals( "A:" ) == false ) {
-            switch( ((SmbComTransaction)request).subCommand ) {
+            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: