jcifs-1.2.19 from tgz
authorFelix Schumacher <p0354740@isib001.(none)>
Wed, 6 Aug 2008 14:45:48 +0000 (16:45 +0200)
committerFelix Schumacher <p0354740@isib001.(none)>
Wed, 6 Aug 2008 14:45:48 +0000 (16:45 +0200)
Sun Apr  6 19:46:47 EDT 2008
jcifs-1.2.19 released

This release adds proper support for domain based DFS roots that are not
hosted on domain controllers and eliminates the now-obsolete behavior of
building a merged list of shares across hosts. A new NetrDfsEnumEx RPC
is used to enumerate DFS roots when listing shares. The equals methods
for SmbFile and UniAddress could return true even though the files were
not equal. That issue has been fixed. Some SmbComOpenAndX parameters
were incorrectly swapped which would cause failure on Windows 98.

29 files changed:
README.txt
build.xml
examples/10883563.doc [deleted file]
examples/Append.java
examples/DnsSrv.java [new file with mode: 0644]
examples/FileOpsRenameTo.java [new file with mode: 0644]
examples/InterruptTest.java
examples/ListFiles.java
examples/SlowRead.java
examples/runtests.sh
src/jcifs/UniAddress.java
src/jcifs/dcerpc/DcerpcBinding.java
src/jcifs/dcerpc/msrpc/MsrpcDfsRootEnum.java [new file with mode: 0644]
src/jcifs/dcerpc/msrpc/netdfs.idl [new file with mode: 0644]
src/jcifs/dcerpc/msrpc/netdfs.java [new file with mode: 0644]
src/jcifs/http/NetworkExplorer.java
src/jcifs/smb/Dfs.java [new file with mode: 0644]
src/jcifs/smb/DfsReferral.java
src/jcifs/smb/DosError.java
src/jcifs/smb/NtTransQuerySecurityDesc.java
src/jcifs/smb/NtlmPasswordAuthentication.java
src/jcifs/smb/SmbException.java
src/jcifs/smb/SmbFile.java
src/jcifs/smb/SmbSession.java
src/jcifs/smb/SmbSession.java.orig [deleted file]
src/jcifs/smb/SmbShareInfo.java
src/jcifs/smb/SmbTransport.java
src/jcifs/smb/SmbTree.java
src/jcifs/smb/Trans2GetDfsReferralResponse.java

index 1871ad5..6d56016 100644 (file)
@@ -1,3 +1,14 @@
+Sun Apr  6 19:46:47 EDT 2008
+jcifs-1.2.19 released
+
+This release adds proper support for domain based DFS roots that are not
+hosted on domain controllers and eliminates the now-obsolete behavior of
+building a merged list of shares across hosts. A new NetrDfsEnumEx RPC
+is used to enumerate DFS roots when listing shares. The equals methods
+for SmbFile and UniAddress could return true even though the files were
+not equal. That issue has been fixed. Some SmbComOpenAndX parameters
+were incorrectly swapped which would cause failure on Windows 98.
+
 Mon Feb 18 23:02:02 EST 2008
 jcifs-1.2.18 released
 
index f1c9612..aa09a50 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -1,7 +1,7 @@
 <project name="jcifs" default="usage" basedir=".">
 
-    <property name="version" value="1.2.18"/>
-    <property name="reldate" value="Feb 18, 2008"/>
+    <property name="version" value="1.2.19"/>
+    <property name="reldate" value="Apr 6, 2008"/>
 
     <target name="usage">
         <echo>
diff --git a/examples/10883563.doc b/examples/10883563.doc
deleted file mode 100644 (file)
index 62644d9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-C:\tmp>ktpass /princ HTTP/www.foo.net@WIN.NET /ptype KRB5_NT_PRINCIPAL /desonly /pass asj7j112233hh4455 /mapuser test2\r
-Targeting domain controller: ts0.win.net\r
-Using legacy password setting method\r
-Successfully mapped HTTP/www.foo.net to test2.\r
-Key created.\r
-Account test2 has been set for DES-only encryption.
\ No newline at end of file
index f8fef92..8a3b19a 100644 (file)
@@ -14,8 +14,8 @@ public class Append {
             msg = new String( "this is msg #" + i ).getBytes();
             out.write( msg );
             System.out.write( msg );
-            Thread.sleep( 17000 );
-out = new SmbFileOutputStream( f, true );
+            Thread.sleep( 10000 );
+//out = new SmbFileOutputStream( f, true );
         }
 
         out.close();
diff --git a/examples/DnsSrv.java b/examples/DnsSrv.java
new file mode 100644 (file)
index 0000000..6fce839
--- /dev/null
@@ -0,0 +1,36 @@
+import java.util.*;
+import javax.naming.*;
+import javax.naming.directory.*;
+
+public class DnsSrv {
+
+    String getDomain(String name) throws NamingException {
+        DirContext context;
+        NameNotFoundException ret = null;
+
+        context = new InitialDirContext();
+        for ( ;; ) {
+            try {
+                Attributes attributes = context.getAttributes(
+                    "dns:/_ldap._tcp.dc._msdcs." + name,
+                    new String[] { "SRV" }
+                );
+                return name;
+            } catch (NameNotFoundException nnfe) {
+                ret = nnfe;
+            }
+            int dot = name.indexOf('.');
+            if (dot == -1)
+                break;
+            name = name.substring(dot + 1);
+        }
+
+        throw ret != null ? ret : new NamingException("invalid name");
+    }
+
+    public static void main(String argv[]) throws Exception {
+        DnsSrv dnsSrv = new DnsSrv();
+        System.out.println(dnsSrv.getDomain(argv[0]));
+    }
+}
+
diff --git a/examples/FileOpsRenameTo.java b/examples/FileOpsRenameTo.java
new file mode 100644 (file)
index 0000000..7280f9f
--- /dev/null
@@ -0,0 +1,85 @@
+/* Test the following file operations:
+ * 
+ * canRead
+ *     false - a target that is already open by another process
+ *     false - the target does not exist
+ *     true  - the file exists and there are no sharing issues
+ * canWrite
+ *     true  - the file exists and there are no sharing issues
+ *     false - the file is marked read-only
+ *     false - the file does not exist
+ * delete
+ *     true  - the file existed and was succcessfully deleted
+ *     false - the target did not exist
+ *     false - the target is a share, server, workgroup or similar
+ *     false - the target or file under the target directory failed was read-only
+ * exists
+ *     true  - the target, share, IPC share, named pipe, server, or workgroup exists
+ *     false - the opposite of the above
+ * isDirectory
+ *     true  - the target is a workgroup, server, share, or directory
+ *     false - the target is not one of the above or does not exist
+ * isFile
+ *     direct opposite of isDirectory
+ * isHidden
+ *     true  - target is share ending in $ or marked as hidden
+ * length
+ *     the file was created to be no larger than ~2G and reports back the size specified
+ * mkdir
+ *     true  - a directory was created successfuly
+ *     false - the directory could not be created
+ * renameTo
+ *     true  - the target was renamed
+ */
+
+import jcifs.smb.*;
+import java.io.IOException;
+import java.util.Date;
+
+public class FileOpsRenameTo {
+
+    static final int ATTR_ALL = SmbFile.ATTR_ARCHIVE | SmbFile.ATTR_HIDDEN | SmbFile.ATTR_READONLY | SmbFile.ATTR_SYSTEM;
+
+    public static void main( String argv[] ) throws Exception {
+
+        if( argv.length != 1 ) {
+            System.out.println( "Must provide an SMB URL of a remote location on which tests will be conducted." );
+            System.exit( 1 );
+        }
+
+        SmbFile s = new SmbFile( argv[0] );
+        SmbFile d = new SmbFile( s, "JcifsTestOpsDir/" );
+
+    // Create a file to test against
+
+    SmbFile f = null;
+    try {
+        f = new SmbFile( d, "foo.txt" );
+        SmbFileOutputStream o = new SmbFileOutputStream( f );
+        o.write( "The Common Internet File System (CIFS) is the de-facto file sharing protocol on the Microsoft Windows platform. It is the underlying networking protocol used when accessing shares with Windows Explorer, the Network Neighborhood, via a Map Network Drive...  dialog, the C:\\> net use * \\\\server\\share commands, or smbclient on UNIX, smbfs on Linux, and elsewhere.\r\n".getBytes() );
+        o.close();
+    } catch( IOException ioe ) {
+        System.out.println( "fail - could not create file " + d + "foo.txt: " + ioe.getMessage() );
+    }
+    System.out.println( "okay - created file " + d + "foo.txt" );
+
+    // renameTo - rename the file to bar.txt
+
+        SmbFile b = new SmbFile( d, "bar.txt" );
+
+        try {
+            f.renameTo( b );
+            System.out.println( "okay - renameTo " + f + " to " + b + " successful even with read-only" );
+            try {
+                b.renameTo(f);
+            } catch( SmbException se ) {
+                System.out.println( "fail - but failed to rename file back to original!" );
+                throw se;
+            }
+        } catch( SmbException se ) {
+            se.printStackTrace();
+        }
+
+    }
+}
+
index 1105b4d..63cffab 100644 (file)
@@ -41,6 +41,7 @@ public class InterruptTest extends Thread {
     public static void main( String argv[] ) throws Exception {
         InterruptTest it = new InterruptTest(argv[0]);
         it.start();
+        Thread.sleep(300);
         for (int i = 0; i < 10; i++) {
             Thread.sleep(200);
             it.interrupt();
index 6f0ee57..e894dc6 100644 (file)
@@ -6,16 +6,25 @@ public class ListFiles {
 
     public static void main( String[] argv ) throws Exception {
 
-        SmbFile file = new SmbFile( argv[0] );
+        for (int a = 0; a < argv.length; a++) {
+            SmbFile file;
+            SmbFile[] files = new SmbFile[0];
 
-        long t1 = System.currentTimeMillis();
-        SmbFile[] files = file.listFiles();
-        long t2 = System.currentTimeMillis() - t1;
+            file = new SmbFile( argv[a] );
 
-        for( int i = 0; i < files.length; i++ ) {
-            System.out.print( " " + files[i].getName() );
+            long t1 = System.currentTimeMillis();
+            try {
+                files = file.listFiles();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            long t2 = System.currentTimeMillis() - t1;
+
+            for( int i = 0; i < files.length; i++ ) {
+                System.out.print( " " + files[i].getName() );
+            }
+            System.out.println();
+            System.out.println( files.length + " files in " + t2 + "ms" );
         }
-        System.out.println();
-        System.out.println( files.length + " files in " + t2 + "ms" );
     }
 }
index 4268c27..74a7400 100644 (file)
@@ -13,7 +13,7 @@ public class SlowRead {
         while(( n = in.read( b )) > 0 ) {
             System.out.write( b, 0, n );
             tot += n;
-            Thread.sleep( 17000 );
+            Thread.sleep( 10000 );
         }
 
         in.close();
index 2353870..670504c 100644 (file)
@@ -2,11 +2,11 @@
 
 JAVA_HOME=/usr/local/java
 CLASSPATH=../build:.
-PROPERTIES=../../user10.prp
+PROPERTIES=../../user1.prp
 RUN="${JAVA_HOME}/bin/java -cp ${CLASSPATH} -Djcifs.properties=${PROPERTIES}"
 
 SERVER=dc1.w.net
-SHARE=tmp
+SHARE=target1
 WRITE_DIR=test/
 SRC_DIR=test/Junk
 FILE1=test/Junk/10883563.doc
index 063eea8..2ce79b0 100644 (file)
@@ -25,6 +25,8 @@ import java.util.StringTokenizer;
 import jcifs.netbios.NbtAddress;
 import jcifs.netbios.Lmhosts;
 import jcifs.util.LogStream;
+import javax.naming.*;
+import javax.naming.directory.*;
 
 /**
  * <p>Under normal conditions it is not necessary to use
@@ -315,6 +317,40 @@ public class UniAddress {
         throw new UnknownHostException( hostname );
     }
 
+    /**
+     * Perform DNS SRV lookup on successively shorter suffixes of name
+     * and return successful suffix or throw an UnknownHostException.
+    public static String getDomainByName(String name) throws UnknownHostException {
+        DirContext context;
+        UnknownHostException uhe = null;
+
+        try {
+            context = new InitialDirContext();
+            for ( ;; ) {
+                try {
+                    Attributes attributes = context.getAttributes(
+                        "dns:/_ldap._tcp.dc._msdcs." + name,
+                        new String[] { "SRV" }
+                    );
+                    return name;
+                } catch (NameNotFoundException nnfe) {
+                    uhe = new UnknownHostException(nnfe.getMessage());
+                }
+                int dot = name.indexOf('.');
+                if (dot == -1)
+                    break;
+                name = name.substring(dot + 1);
+            }
+        } catch (NamingException ne) {
+            if (log.level > 1)
+                ne.printStackTrace(log);
+        }
+
+        throw uhe != null ? uhe : new UnknownHostException("invalid name");
+    }
+     */
+
+
     Object addr;
     String calledName;
 
@@ -340,12 +376,16 @@ public class UniAddress {
 
     /**
      * 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.
+     * if they are both <tt>UniAddress</tt>' and refer to the same IP address.
      */
-
+    public boolean equals( Object obj ) {
+        return obj instanceof UniAddress && addr.equals(((UniAddress)obj).addr);
+    }
+/*
     public boolean equals( Object obj ) {
         return obj instanceof UniAddress && addr.hashCode() == obj.hashCode();
     }
+*/
 
     /**
      * Guess first called name to try for session establishment. This
index 17ae43b..77b635b 100644 (file)
@@ -33,6 +33,7 @@ class DcerpcBinding {
         INTERFACES.put("srvsvc", srvsvc.getSyntax());
         INTERFACES.put("lsarpc", lsarpc.getSyntax());
         INTERFACES.put("samr", samr.getSyntax());
+        INTERFACES.put("netdfs", netdfs.getSyntax());
     }
 
     String proto;
diff --git a/src/jcifs/dcerpc/msrpc/MsrpcDfsRootEnum.java b/src/jcifs/dcerpc/msrpc/MsrpcDfsRootEnum.java
new file mode 100644 (file)
index 0000000..dc9a68a
--- /dev/null
@@ -0,0 +1,42 @@
+/* jcifs msrpc client library in Java
+ * Copyright (C) 2008  "Michael B. Allen" <jcifs at samba dot org>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.dcerpc.msrpc;
+
+import jcifs.smb.*;
+import jcifs.dcerpc.ndr.*;
+
+public class MsrpcDfsRootEnum extends netdfs.NetrDfsEnumEx {
+
+    public MsrpcDfsRootEnum(String server) {
+        super(server, 200, 0xFFFF, new netdfs.DfsEnumStruct(), new NdrLong(0));
+        info.level = level;
+        info.e = new netdfs.DfsEnumArray200();
+        ptype = 0;
+        flags = DCERPC_FIRST_FRAG | DCERPC_LAST_FRAG;
+    }
+
+    public FileEntry[] getEntries() {
+        netdfs.DfsEnumArray200 a200 = (netdfs.DfsEnumArray200)info.e;
+        SmbShareInfo[] entries = new SmbShareInfo[a200.count];
+        for (int i = 0; i < a200.count; i++) {
+            entries[i] = new SmbShareInfo(a200.s[i].dfs_name, 0, null);
+        }
+        return entries;
+    }
+}
diff --git a/src/jcifs/dcerpc/msrpc/netdfs.idl b/src/jcifs/dcerpc/msrpc/netdfs.idl
new file mode 100644 (file)
index 0000000..ff2760d
--- /dev/null
@@ -0,0 +1,81 @@
+[
+       uuid(4fc742e0-4a10-11cf-8273-00aa004ae673),
+       version(3.0)
+]
+interface netdfs
+{
+       import "../rpc.idl";
+
+       const uint32_t DFS_VOLUME_FLAVOR_STANDALONE = 0x100;
+       const uint32_t DFS_VOLUME_FLAVOR_AD_BLOB = 0x200;
+
+       const uint32_t DFS_STORAGE_STATE_OFFLINE = 0x0001;
+       const uint32_t DFS_STORAGE_STATE_ONLINE = 0x0002;
+       const uint32_t DFS_STORAGE_STATE_ACTIVE = 0x0004;
+
+       typedef struct {
+               [string] wchar_t *entry_path;
+       } DfsInfo1;
+
+       typedef struct {
+               uint32_t count;
+               [size_is(count)] DfsInfo1 *s;
+       } DfsEnumArray1;
+
+       typedef struct {
+               uint32_t state;
+               [string] wchar_t *server_name;
+               [string] wchar_t *share_name;
+       } DfsStorageInfo;
+
+       typedef struct {
+               [string] wchar_t *path;
+               [string] wchar_t *comment;
+               uint32_t state;
+               uint32_t num_stores;
+               [size_is(num_stores)] DfsStorageInfo *stores;
+       } DfsInfo3;
+
+       typedef struct {
+               uint32_t count;
+               [size_is(count)] DfsInfo3 *s;
+       } DfsEnumArray3;
+
+       typedef struct {
+               [string] wchar_t *dfs_name;
+       } DfsInfo200;
+
+       typedef struct {
+               uint32_t count;
+               [size_is(count)] DfsInfo200 *s;
+       } DfsEnumArray200;
+
+       typedef struct {
+               uint32_t flags;
+               [string] wchar_t *dfs_name;
+       } DfsInfo300;
+
+       typedef struct {
+               uint32_t count;
+               [size_is(count)] DfsInfo300 *s;
+       } DfsEnumArray300;
+
+       typedef union {
+               [case(1)] DfsEnumArray1 *info1;
+               [case(3)] DfsEnumArray3 *info3;
+               [case(200)] DfsEnumArray200 *info200;
+               [case(300)] DfsEnumArray300 *info300;
+       } DfsEnumInfo;
+
+       typedef struct {
+               uint32_t level,
+               [switch_is(level)] DfsEnumInfo e;
+       } DfsEnumStruct;
+
+       [op(0x15)]
+       int NetrDfsEnumEx([in,string,unique] wchar_t dfs_name,
+                       [in] uint32_t level,
+                       [in] uint32_t prefmaxlen,
+                       [in,out,unique] DfsEnumStruct *info,
+                       [in,out,unique] uint32_t *totalentries);
+}
diff --git a/src/jcifs/dcerpc/msrpc/netdfs.java b/src/jcifs/dcerpc/msrpc/netdfs.java
new file mode 100644 (file)
index 0000000..60b1f8b
--- /dev/null
@@ -0,0 +1,494 @@
+package jcifs.dcerpc.msrpc;
+
+import jcifs.dcerpc.*;
+import jcifs.dcerpc.ndr.*;
+
+public class netdfs {
+
+    public static String getSyntax() {
+        return "4fc742e0-4a10-11cf-8273-00aa004ae673:3.0";
+    }
+
+    public static final int DFS_VOLUME_FLAVOR_STANDALONE = 0x100;
+    public static final int DFS_VOLUME_FLAVOR_AD_BLOB = 0x200;
+    public static final int DFS_STORAGE_STATE_OFFLINE = 0x0001;
+    public static final int DFS_STORAGE_STATE_ONLINE = 0x0002;
+    public static final int DFS_STORAGE_STATE_ACTIVE = 0x0004;
+    public static class DfsInfo1 extends NdrObject {
+
+        public String entry_path;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_referent(entry_path, 1);
+
+            if (entry_path != null) {
+                _dst = _dst.deferred;
+                _dst.enc_ndr_string(entry_path);
+
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            int _entry_pathp = _src.dec_ndr_long();
+
+            if (_entry_pathp != 0) {
+                _src = _src.deferred;
+                entry_path = _src.dec_ndr_string();
+
+            }
+        }
+    }
+    public static class DfsEnumArray1 extends NdrObject {
+
+        public int count;
+        public DfsInfo1[] s;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_long(count);
+            _dst.enc_ndr_referent(s, 1);
+
+            if (s != null) {
+                _dst = _dst.deferred;
+                int _ss = count;
+                _dst.enc_ndr_long(_ss);
+                int _si = _dst.index;
+                _dst.advance(4 * _ss);
+
+                _dst = _dst.derive(_si);
+                for (int _i = 0; _i < _ss; _i++) {
+                    s[_i].encode(_dst);
+                }
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            count = (int)_src.dec_ndr_long();
+            int _sp = _src.dec_ndr_long();
+
+            if (_sp != 0) {
+                _src = _src.deferred;
+                int _ss = _src.dec_ndr_long();
+                int _si = _src.index;
+                _src.advance(4 * _ss);
+
+                if (s == null) {
+                    if (_ss < 0 || _ss > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE );
+                    s = new DfsInfo1[_ss];
+                }
+                _src = _src.derive(_si);
+                for (int _i = 0; _i < _ss; _i++) {
+                    if (s[_i] == null) {
+                        s[_i] = new DfsInfo1();
+                    }
+                    s[_i].decode(_src);
+                }
+            }
+        }
+    }
+    public static class DfsStorageInfo extends NdrObject {
+
+        public int state;
+        public String server_name;
+        public String share_name;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_long(state);
+            _dst.enc_ndr_referent(server_name, 1);
+            _dst.enc_ndr_referent(share_name, 1);
+
+            if (server_name != null) {
+                _dst = _dst.deferred;
+                _dst.enc_ndr_string(server_name);
+
+            }
+            if (share_name != null) {
+                _dst = _dst.deferred;
+                _dst.enc_ndr_string(share_name);
+
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            state = (int)_src.dec_ndr_long();
+            int _server_namep = _src.dec_ndr_long();
+            int _share_namep = _src.dec_ndr_long();
+
+            if (_server_namep != 0) {
+                _src = _src.deferred;
+                server_name = _src.dec_ndr_string();
+
+            }
+            if (_share_namep != 0) {
+                _src = _src.deferred;
+                share_name = _src.dec_ndr_string();
+
+            }
+        }
+    }
+    public static class DfsInfo3 extends NdrObject {
+
+        public String path;
+        public String comment;
+        public int state;
+        public int num_stores;
+        public DfsStorageInfo[] stores;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_referent(path, 1);
+            _dst.enc_ndr_referent(comment, 1);
+            _dst.enc_ndr_long(state);
+            _dst.enc_ndr_long(num_stores);
+            _dst.enc_ndr_referent(stores, 1);
+
+            if (path != null) {
+                _dst = _dst.deferred;
+                _dst.enc_ndr_string(path);
+
+            }
+            if (comment != null) {
+                _dst = _dst.deferred;
+                _dst.enc_ndr_string(comment);
+
+            }
+            if (stores != null) {
+                _dst = _dst.deferred;
+                int _storess = num_stores;
+                _dst.enc_ndr_long(_storess);
+                int _storesi = _dst.index;
+                _dst.advance(12 * _storess);
+
+                _dst = _dst.derive(_storesi);
+                for (int _i = 0; _i < _storess; _i++) {
+                    stores[_i].encode(_dst);
+                }
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            int _pathp = _src.dec_ndr_long();
+            int _commentp = _src.dec_ndr_long();
+            state = (int)_src.dec_ndr_long();
+            num_stores = (int)_src.dec_ndr_long();
+            int _storesp = _src.dec_ndr_long();
+
+            if (_pathp != 0) {
+                _src = _src.deferred;
+                path = _src.dec_ndr_string();
+
+            }
+            if (_commentp != 0) {
+                _src = _src.deferred;
+                comment = _src.dec_ndr_string();
+
+            }
+            if (_storesp != 0) {
+                _src = _src.deferred;
+                int _storess = _src.dec_ndr_long();
+                int _storesi = _src.index;
+                _src.advance(12 * _storess);
+
+                if (stores == null) {
+                    if (_storess < 0 || _storess > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE );
+                    stores = new DfsStorageInfo[_storess];
+                }
+                _src = _src.derive(_storesi);
+                for (int _i = 0; _i < _storess; _i++) {
+                    if (stores[_i] == null) {
+                        stores[_i] = new DfsStorageInfo();
+                    }
+                    stores[_i].decode(_src);
+                }
+            }
+        }
+    }
+    public static class DfsEnumArray3 extends NdrObject {
+
+        public int count;
+        public DfsInfo3[] s;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_long(count);
+            _dst.enc_ndr_referent(s, 1);
+
+            if (s != null) {
+                _dst = _dst.deferred;
+                int _ss = count;
+                _dst.enc_ndr_long(_ss);
+                int _si = _dst.index;
+                _dst.advance(20 * _ss);
+
+                _dst = _dst.derive(_si);
+                for (int _i = 0; _i < _ss; _i++) {
+                    s[_i].encode(_dst);
+                }
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            count = (int)_src.dec_ndr_long();
+            int _sp = _src.dec_ndr_long();
+
+            if (_sp != 0) {
+                _src = _src.deferred;
+                int _ss = _src.dec_ndr_long();
+                int _si = _src.index;
+                _src.advance(20 * _ss);
+
+                if (s == null) {
+                    if (_ss < 0 || _ss > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE );
+                    s = new DfsInfo3[_ss];
+                }
+                _src = _src.derive(_si);
+                for (int _i = 0; _i < _ss; _i++) {
+                    if (s[_i] == null) {
+                        s[_i] = new DfsInfo3();
+                    }
+                    s[_i].decode(_src);
+                }
+            }
+        }
+    }
+    public static class DfsInfo200 extends NdrObject {
+
+        public String dfs_name;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_referent(dfs_name, 1);
+
+            if (dfs_name != null) {
+                _dst = _dst.deferred;
+                _dst.enc_ndr_string(dfs_name);
+
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            int _dfs_namep = _src.dec_ndr_long();
+
+            if (_dfs_namep != 0) {
+                _src = _src.deferred;
+                dfs_name = _src.dec_ndr_string();
+
+            }
+        }
+    }
+    public static class DfsEnumArray200 extends NdrObject {
+
+        public int count;
+        public DfsInfo200[] s;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_long(count);
+            _dst.enc_ndr_referent(s, 1);
+
+            if (s != null) {
+                _dst = _dst.deferred;
+                int _ss = count;
+                _dst.enc_ndr_long(_ss);
+                int _si = _dst.index;
+                _dst.advance(4 * _ss);
+
+                _dst = _dst.derive(_si);
+                for (int _i = 0; _i < _ss; _i++) {
+                    s[_i].encode(_dst);
+                }
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            count = (int)_src.dec_ndr_long();
+            int _sp = _src.dec_ndr_long();
+
+            if (_sp != 0) {
+                _src = _src.deferred;
+                int _ss = _src.dec_ndr_long();
+                int _si = _src.index;
+                _src.advance(4 * _ss);
+
+                if (s == null) {
+                    if (_ss < 0 || _ss > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE );
+                    s = new DfsInfo200[_ss];
+                }
+                _src = _src.derive(_si);
+                for (int _i = 0; _i < _ss; _i++) {
+                    if (s[_i] == null) {
+                        s[_i] = new DfsInfo200();
+                    }
+                    s[_i].decode(_src);
+                }
+            }
+        }
+    }
+    public static class DfsInfo300 extends NdrObject {
+
+        public int flags;
+        public String dfs_name;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_long(flags);
+            _dst.enc_ndr_referent(dfs_name, 1);
+
+            if (dfs_name != null) {
+                _dst = _dst.deferred;
+                _dst.enc_ndr_string(dfs_name);
+
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            flags = (int)_src.dec_ndr_long();
+            int _dfs_namep = _src.dec_ndr_long();
+
+            if (_dfs_namep != 0) {
+                _src = _src.deferred;
+                dfs_name = _src.dec_ndr_string();
+
+            }
+        }
+    }
+    public static class DfsEnumArray300 extends NdrObject {
+
+        public int count;
+        public DfsInfo300[] s;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_long(count);
+            _dst.enc_ndr_referent(s, 1);
+
+            if (s != null) {
+                _dst = _dst.deferred;
+                int _ss = count;
+                _dst.enc_ndr_long(_ss);
+                int _si = _dst.index;
+                _dst.advance(8 * _ss);
+
+                _dst = _dst.derive(_si);
+                for (int _i = 0; _i < _ss; _i++) {
+                    s[_i].encode(_dst);
+                }
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            count = (int)_src.dec_ndr_long();
+            int _sp = _src.dec_ndr_long();
+
+            if (_sp != 0) {
+                _src = _src.deferred;
+                int _ss = _src.dec_ndr_long();
+                int _si = _src.index;
+                _src.advance(8 * _ss);
+
+                if (s == null) {
+                    if (_ss < 0 || _ss > 0xFFFF) throw new NdrException( NdrException.INVALID_CONFORMANCE );
+                    s = new DfsInfo300[_ss];
+                }
+                _src = _src.derive(_si);
+                for (int _i = 0; _i < _ss; _i++) {
+                    if (s[_i] == null) {
+                        s[_i] = new DfsInfo300();
+                    }
+                    s[_i].decode(_src);
+                }
+            }
+        }
+    }
+    public static class DfsEnumStruct extends NdrObject {
+
+        public int level;
+        public NdrObject e;
+
+        public void encode(NdrBuffer _dst) throws NdrException {
+            _dst.align(4);
+            _dst.enc_ndr_long(level);
+            int _descr = level;
+            _dst.enc_ndr_long(_descr);
+            _dst.enc_ndr_referent(e, 1);
+
+            if (e != null) {
+                _dst = _dst.deferred;
+                e.encode(_dst);
+
+            }
+        }
+        public void decode(NdrBuffer _src) throws NdrException {
+            _src.align(4);
+            level = (int)_src.dec_ndr_long();
+            _src.dec_ndr_long(); /* union discriminant */
+            int _ep = _src.dec_ndr_long();
+
+            if (_ep != 0) {
+                if (e == null) { /* YOYOYO */
+                    e = new DfsEnumArray1();
+                }
+                _src = _src.deferred;
+                e.decode(_src);
+
+            }
+        }
+    }
+    public static class NetrDfsEnumEx extends DcerpcMessage {
+
+        public int getOpnum() { return 0x15; }
+
+        public int retval;
+        public String dfs_name;
+        public int level;
+        public int prefmaxlen;
+        public DfsEnumStruct info;
+        public NdrLong totalentries;
+
+        public NetrDfsEnumEx(String dfs_name,
+                    int level,
+                    int prefmaxlen,
+                    DfsEnumStruct info,
+                    NdrLong totalentries) {
+            this.dfs_name = dfs_name;
+            this.level = level;
+            this.prefmaxlen = prefmaxlen;
+            this.info = info;
+            this.totalentries = totalentries;
+        }
+
+        public void encode_in(NdrBuffer _dst) throws NdrException {
+            _dst.enc_ndr_string(dfs_name);
+            _dst.enc_ndr_long(level);
+            _dst.enc_ndr_long(prefmaxlen);
+            _dst.enc_ndr_referent(info, 1);
+            if (info != null) {
+                info.encode(_dst);
+
+            }
+            _dst.enc_ndr_referent(totalentries, 1);
+            if (totalentries != null) {
+                totalentries.encode(_dst);
+
+            }
+        }
+        public void decode_out(NdrBuffer _src) throws NdrException {
+            int _infop = _src.dec_ndr_long();
+            if (_infop != 0) {
+                if (info == null) { /* YOYOYO */
+                    info = new DfsEnumStruct();
+                }
+                info.decode(_src);
+
+            }
+            int _totalentriesp = _src.dec_ndr_long();
+            if (_totalentriesp != 0) {
+                totalentries.decode(_src);
+
+            }
+            retval = (int)_src.dec_ndr_long();
+        }
+    }
+}
index 7bfa14a..0a677ca 100644 (file)
@@ -519,7 +519,10 @@ public class NetworkExplorer extends HttpServlet {
             StringBuffer redir = req.getRequestURL();
             String qs = req.getQueryString();
             redir = new StringBuffer( redir.substring( 0, redir.length() - req.getPathInfo().length() ));
-            redir.append( dr.node.replace( '\\', '/' ));
+            redir.append( '/' );
+            redir.append(dr.server);
+            redir.append( '/' );
+            redir.append(dr.share);
             redir.append( '/' );
             if( qs != null ) {
                 redir.append( req.getQueryString() );
diff --git a/src/jcifs/smb/Dfs.java b/src/jcifs/smb/Dfs.java
new file mode 100644 (file)
index 0000000..b486181
--- /dev/null
@@ -0,0 +1,236 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2008  "Michael B. Allen" <jcifs at samba dot org>
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package jcifs.smb;
+
+import java.util.*;
+import java.io.*;
+
+import jcifs.UniAddress;
+import jcifs.util.*;
+import jcifs.Config;
+
+public class Dfs {
+
+    static class CacheEntry {
+        long expiration;
+        HashMap map;
+
+        CacheEntry(long ttl) {
+            if (ttl == 0)
+                ttl = Dfs.TTL;
+            expiration = System.currentTimeMillis() + ttl * 1000L;
+            map = new HashMap();
+        }
+    }
+
+    static LogStream log = LogStream.getInstance();
+    static final boolean strictView = Config.getBoolean("jcifs.smb.client.dfs.strictView", false);
+    static final long TTL = Config.getLong("jcifs.smb.client.dfs.ttl", 300);
+
+    protected static CacheEntry FALSE_ENTRY = new Dfs.CacheEntry(0L);
+
+    protected CacheEntry _domains = null; /* aka trusted domains cache */
+    protected CacheEntry referrals = null;
+
+    public HashMap getTrustedDomains(NtlmPasswordAuthentication auth) throws SmbAuthException {
+        if (_domains != null && System.currentTimeMillis() > _domains.expiration) {
+            _domains = null;
+        }
+        if (_domains != null)
+            return _domains.map;
+        try {
+            UniAddress addr = UniAddress.getByName(auth.domain);
+            SmbTransport trans = SmbTransport.getSmbTransport(addr, 0);
+            DfsReferral[] dr = trans.getDfsReferrals(auth, "", 0);
+            CacheEntry entry = new CacheEntry(Dfs.TTL * 10L);
+            for (int di = 0; di < dr.length; di++) {
+                String domain = dr[di].server;
+                entry.map.put(domain, new HashMap());
+            }
+            _domains = entry;
+            return _domains.map;
+        } catch (IOException ioe) {
+            if (log.level >= 3)
+                ioe.printStackTrace(log);
+            if (strictView && ioe instanceof SmbAuthException) {
+                throw (SmbAuthException)ioe;
+            }
+        }
+        return null;
+    }
+    public boolean isTrustedDomain(String domain,
+                    NtlmPasswordAuthentication auth) throws SmbAuthException
+    {
+        HashMap domains = getTrustedDomains(auth);
+        if (domains == null)
+            return false;
+        domain = domain.toLowerCase();
+        return domains.get(domain) != null;
+    }
+    public SmbTransport getDc(String domain,
+                    NtlmPasswordAuthentication auth) throws SmbAuthException {
+        try {
+            UniAddress addr = UniAddress.getByName(domain);
+            SmbTransport trans = SmbTransport.getSmbTransport(addr, 0);
+            DfsReferral[] dr = trans.getDfsReferrals(auth, "\\" + domain, 1);
+            if (dr.length == 1) {
+                addr = UniAddress.getByName(dr[0].server);
+                return SmbTransport.getSmbTransport(addr, 0);
+            }
+        } catch (IOException ioe) {
+            if (log.level >= 3)
+                ioe.printStackTrace(log);
+            if (strictView && ioe instanceof SmbAuthException) {
+                throw (SmbAuthException)ioe;
+            }
+        }
+        return null;
+    }
+    public DfsReferral getReferral(SmbTransport trans,
+                    String domain,
+                    String root,
+                    String path,
+                    NtlmPasswordAuthentication auth) throws SmbAuthException {
+        try {
+            String p = "\\" + domain + "\\" + root;
+            if (path != null)
+                p += path;
+            DfsReferral[] dr = trans.getDfsReferrals(auth, p, 1);
+            if (dr.length == 1)
+                return dr[0];
+        } catch (IOException ioe) {
+            if (log.level >= 3)
+                ioe.printStackTrace(log);
+            if (strictView && ioe instanceof SmbAuthException) {
+                throw (SmbAuthException)ioe;
+            }
+        }
+        return null;
+    }
+    public DfsReferral resolve(String domain,
+                String root,
+                String path,
+                NtlmPasswordAuthentication auth) throws SmbAuthException {
+        DfsReferral dr = null;
+        long now = System.currentTimeMillis();
+
+        if (root.equals("IPC$")) {
+            return null;
+        }
+        HashMap domains = getTrustedDomains(auth);
+        if (domains != null) {
+            domain = domain.toLowerCase();
+            HashMap roots = (HashMap)domains.get(domain);
+            if (roots != null) {
+                SmbTransport trans = null;
+
+                root = root.toLowerCase();
+
+                CacheEntry links = (CacheEntry)roots.get(root);
+                if (links != null && now > links.expiration) {
+                    roots.remove(root);
+                    links = null;
+                }
+                if (links == null) {
+                    if ((trans = getDc(domain, auth)) == null)
+                        return null;
+
+                    dr = getReferral(trans, domain, root, path, auth);
+                    if (dr != null) {
+                        dr.pathConsumed -= 1 + domain.length() + 1 + root.length();
+                        links = new CacheEntry(0L);
+                        if (path == null)
+                            links.map.put("\\", dr);
+                        roots.put(root, links);
+                    } else if (path == null) {
+                        roots.put(root, Dfs.FALSE_ENTRY);
+                    }
+                } else if (links == Dfs.FALSE_ENTRY) {
+                    links = null;
+                }
+
+                if (links != null) {
+                    String link = "\\";
+                    if (path != null) {
+                        int i = path.indexOf("\\", 1);
+                        link = i > 0 ? path.substring(1, i) : path.substring(1);
+                    }
+
+                    dr = (DfsReferral)links.map.get(link);
+                    if (dr != null && now > dr.expiration) {
+                        dr = null;
+                        links.map.remove(link);
+                    }
+                    if (dr == null) {
+                        if (trans == null)
+                            if ((trans = getDc(domain, auth)) == null)
+                                return null;
+                        dr = getReferral(trans, domain, root, path, auth);
+                        if (dr != null) {
+                            dr.pathConsumed -= 1 + domain.length() + 1 + root.length();
+                            dr.link = link;
+                            links.map.put(link, dr);
+                        }
+                    }
+                }
+            }
+        }
+
+        if (dr == null && path != null) {
+            /* The referrals map is for stand-alone roots
+             */
+            if (referrals != null && now > referrals.expiration) {
+                referrals = null;
+            }
+            if (referrals == null) {
+                referrals = new CacheEntry(0);
+            }
+            String key = "\\" + domain + "\\" + root;
+            if (path.equals("\\") == false) {
+                int s1 = path.indexOf('\\', 1);
+                if (s1 > 0)
+                    path = path.substring(0, s1);
+                key += path;
+            }
+            dr = (DfsReferral)referrals.map.get(key.toLowerCase());
+        }
+
+        return dr;
+    }
+    void insert(String path, DfsReferral dr) {
+        int s1, s2;
+        String server, share, key;
+
+        s1 = path.indexOf('\\', 1);
+        s2 = path.indexOf('\\', s1 + 1);
+        server = path.substring(1, s1);
+        share = path.substring(s1 + 1, s2);
+
+        key = path.substring(0, dr.pathConsumed).toLowerCase();
+        dr.pathConsumed -= 1 + server.length() + 1 + share.length();
+
+        if (referrals != null && (System.currentTimeMillis() + 10000) > referrals.expiration) {
+            referrals = null;
+        }
+        if (referrals == null) {
+            referrals = new CacheEntry(0);
+        }
+        referrals.map.put(key, dr);
+    }
+}
index 584db85..f14e126 100644 (file)
@@ -20,19 +20,23 @@ package jcifs.smb;
 
 public class DfsReferral extends SmbException {
 
-    public String path;     // Path relative to tree from which this referral was thrown
-    public String node;     // Server and share
+    public int pathConsumed;
+    public long ttl;
     public String server;   // Server
     public String share;    // Share
-    public String nodepath; // Path relative to tree
+    public String link;
+    public String path;     // Path relative to tree from which this referral was thrown
     public boolean resolveHashes;
+    public long expiration;
 
     public String toString() {
-        return "DfsReferral[path=" + path +
-            ",node=" + node +
+        return "DfsReferral[pathConsumed=" + pathConsumed +
             ",server=" + server +
             ",share=" + share +
-            ",nodepath=" + nodepath +
+            ",link=" + link +
+            ",path=" + path +
+            ",ttl=" + ttl +
+            ",expiration=" + expiration +
             ",resolveHashes=" + resolveHashes + "]";
     }
 }
index 6735297..666fb5c 100644 (file)
@@ -30,7 +30,7 @@ public interface DosError {
         { 0x00030002, 0xc00000cb },
         { 0x00040002, 0xc00000ca },
         { 0x00050001, 0xc0000022 },
-        { 0x00050002, 0xc00000c9 },
+        { 0x00050002, 0xc000000d },
         { 0x00060001, 0xc0000008 },
         { 0x00060002, 0xc00000cc },
         { 0x00080001, 0xc000009a },
@@ -48,6 +48,7 @@ public interface DosError {
         { 0x00500001, 0xc0000035 },
         { 0x00570001, 0xc0000003 },
         { 0x005a0002, 0xc00000ce },
+        { 0x005b0002, 0xc000000d },
         { 0x006d0001, 0xC000014b },
         { 0x007b0001, 0xc0000033 },
         { 0x00910001, 0xC0000101 },
@@ -93,6 +94,7 @@ public interface DosError {
         "The file exists.",
         "The parameter is incorrect.",
         "Too many Uids active on this session.",
+        "The Uid is not known as a valid user identifier on this session.",
         "The pipe has been ended.",
         "The filename, directory name, or volume label syntax is incorrect.",
         "The directory is not empty.",
index 57daa98..bf80cac 100644 (file)
@@ -65,7 +65,7 @@ class NtTransQuerySecurityDesc extends SmbComNtTransaction {
         return 0;
     }
     public String toString() {
-        return new String( "NtTransGetSecurityDesc[" + super.toString() +
+        return new String( "NtTransQuerySecurityDesc[" + super.toString() +
             ",fid=0x" + Hexdump.toHexString( fid, 4 ) +
             ",securityInformation=0x" + Hexdump.toHexString( securityInformation, 8 ) + "]" );
     }
index 7a9b22c..c7b977d 100644 (file)
@@ -254,6 +254,7 @@ public final class NtlmPasswordAuthentication implements Principal, Serializable
     public String getDomain() {
         return domain;
     }
+
 /**
  * Returns the username.
  */
index 08c140c..8b49b70 100644 (file)
@@ -40,19 +40,22 @@ import jcifs.util.Hexdump;
 public class SmbException extends IOException implements NtStatus, DosError, WinError {
 
     static String getMessageByCode( int errcode ) {
+        /* Note there's a signedness error here because 0xC0000000 based values are
+         * negative so it with NT_STATUS_SUCCESS (0) the binary search will not be
+         * performed properly. The effect is that the code at index 1 is never found
+         * (NT_STATUS_UNSUCCESSFUL). So here we factor out NT_STATUS_SUCCESS
+         * as a special case (which it is).
+         */
+        if (errcode == 0) {
+            return "NT_STATUS_SUCCESS";
+        }
         if(( errcode & 0xC0000000 ) == 0xC0000000 ) {
-            int min = 0;
+            int min = 1; /* Don't include NT_STATUS_SUCCESS */
             int max = NT_STATUS_CODES.length - 1;
 
             while( max >= min ) {
                 int mid = (min + max) / 2;
 
-                /* Note there's a signedness error here because 0xC0000000 based values are
-                 * negative so it with NT_STATUS_SUCCESS (0) the binary search will not be
-                 * performed properly. The effect is that the code at index 1 is never found
-                 * (NT_STATUS_UNSUCCESSFUL). We should just factor out NT_STATUS_SUCCESS
-                 * as a special case (which it is).
-                 */
                 if( errcode > NT_STATUS_CODES[mid] ) {
                     min = mid + 1;
                 } else if( errcode < NT_STATUS_CODES[mid] ) {
index a32e101..f027fed 100644 (file)
@@ -368,6 +368,7 @@ public class SmbFile extends URLConnection implements SmbConstants {
             cnfe.printStackTrace();
         }
         attrExpirationPeriod = Config.getLong( "jcifs.smb.client.attrExpirationPeriod", DEFAULT_ATTR_EXPIRATION_PERIOD );
+        dfs = new Dfs();
     }
 
     /**
@@ -418,7 +419,9 @@ public class SmbFile extends URLConnection implements SmbConstants {
     private boolean isExists;
     private int shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
     private SmbComBlankResponse blank_resp = null;
-    private DfsReferral dfsReferral = null;  // Only used by getDfsPath()
+    private DfsReferral dfsReferral = null;  // For getDfsPath() and getServerWithDfs()
+
+    protected static Dfs dfs;
 
     NtlmPasswordAuthentication auth; // Cannot be null
     SmbTree tree = null;             // Initially null; may be !tree.treeConnected
@@ -658,45 +661,65 @@ public class SmbFile extends URLConnection implements SmbConstants {
         }
         return blank_resp;
     }
-    void send( ServerMessageBlock request,
-                    ServerMessageBlock response ) throws SmbException {
-        for( ;; ) {
-            connect0();
-            if( tree.inDfs ) {
-                DfsReferral dr = tree.session.transport.lookupReferral( unc );
-                if( dr != null ) {
-                    UniAddress addr;
-                    SmbTransport trans;
-
-                    try {
-                        addr = UniAddress.getByName( dr.server );
-                    } catch( UnknownHostException uhe ) {
-                        throw new SmbException( dr.server, uhe );
-                    }
+    void resolveDfs(ServerMessageBlock request) throws SmbException {
+        connect0();
+        String hostName = getServerWithDfs();
+        DfsReferral dr = dfs.resolve(
+                    hostName,
+                    tree.share,
+                    unc,
+                    auth);
+        if (dr != null) {
+            UniAddress addr;
+            SmbTransport trans;
 
-                    trans = SmbTransport.getSmbTransport( addr, url.getPort() );
-                    tree = trans.getSmbSession( auth ).getSmbTree( dr.share, null );
+            try {
+                addr = UniAddress.getByName( dr.server );
+            } catch( UnknownHostException uhe ) {
+                throw new SmbException( dr.server, uhe );
+            }
 
-                    if (log.level >= 3)
-                        log.println( dr );
-
-                    dfsReferral = dr;
-                    String dunc = dfsReferral.nodepath + unc.substring( dfsReferral.path.length() );
-                    unc = dunc;
-                    if (request.path.endsWith("\\") && dunc.endsWith("\\") == false)
-                        dunc += "\\";
-                    request.path = dunc;
-                }
+            trans = SmbTransport.getSmbTransport( addr, url.getPort() );
+            tree = trans.getSmbSession( auth ).getSmbTree( dr.share, null );
+
+            if (log.level >= 3)
+                log.println( dr );
+
+            dfsReferral = dr;
+            String dunc = unc.substring(dr.pathConsumed);
+            if (dunc.equals(""))
+                dunc = "\\";
+            unc = dunc;
+            if (request != null &&
+                        request.path != null &&
+                        request.path.endsWith("\\") &&
+                        dunc.endsWith("\\") == false) {
+                dunc += "\\";
+            }
+            if (request != null) {
+                request.path = dunc;
                 request.flags2 |= ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS;
-            } else {
-                request.flags2 &= ~ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS;
             }
+        } else if (tree.inDomainDfs &&
+                        !(request instanceof NtTransQuerySecurityDesc) &&
+                        !(request instanceof SmbComClose) &&
+                        !(request instanceof SmbComFindClose2)) {
+            throw new SmbException(NtStatus.NT_STATUS_NOT_FOUND, false);
+        } else {
+            if (request != null)
+                request.flags2 &= ~ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS;
+        }
+    }
+    void send( ServerMessageBlock request,
+                    ServerMessageBlock response ) throws SmbException {
+        for( ;; ) {
+            resolveDfs(request);
             try {
                 tree.send( request, response );
                 break;
-            } catch( DfsReferral dr ) {
-                if( dr.resolveHashes ) {
-                    throw dr;
+            } catch( DfsReferral dre ) {
+                if( dre.resolveHashes ) {
+                    throw dre;
                 }
                 request.reset();
             }
@@ -801,13 +824,21 @@ int addressIndex;
     }
     void doConnect() throws IOException {
         SmbTransport trans;
-        SmbSession ssn;
         UniAddress addr;
 
         addr = getAddress();
-        trans = SmbTransport.getSmbTransport(addr, url.getPort());
-        ssn = trans.getSmbSession(auth);
-        tree = ssn.getSmbTree(share, null);
+        if (tree != null) {
+            trans = tree.session.transport;
+        } else {
+            trans = SmbTransport.getSmbTransport(addr, url.getPort());
+            tree = trans.getSmbSession(auth).getSmbTree(share, null);
+        }
+
+        String hostName = getServerWithDfs();
+        tree.inDomainDfs = dfs.resolve(hostName, tree.share, null, auth) != null;
+        if (tree.inDomainDfs) {
+            tree.treeConnected = true;
+        }
 
         try {
             if( log.level >= 3 )
@@ -816,6 +847,7 @@ int addressIndex;
             tree.treeConnect(null, null);
         } catch (SmbAuthException sae) {
             NtlmPasswordAuthentication a;
+            SmbSession ssn;
 
             if (share == null) { // IPC$ - try "anonymous" credentials
                 ssn = trans.getSmbSession(NtlmPasswordAuthentication.NULL);
@@ -826,6 +858,10 @@ int addressIndex;
                 auth = a;
                 ssn = trans.getSmbSession(auth);
                 tree = ssn.getSmbTree(share, null);
+                tree.inDomainDfs = dfs.resolve(hostName, tree.share, null, auth) != null;
+                if (tree.inDomainDfs) {
+                    tree.treeConnected = true;
+                }
                 tree.treeConnect(null, null);
             } else {
                 if (log.level >= 1 && hasNextAddress())
@@ -891,7 +927,7 @@ if (this instanceof SmbNamedPipe) {
             isExists = true;
         } else {
             SmbComOpenAndXResponse response = new SmbComOpenAndXResponse();
-            send( new SmbComOpenAndX( unc, flags, access, null ), response );
+            send( new SmbComOpenAndX( unc, access, flags, null ), response );
             f = response.fid;
         }
 
@@ -1144,23 +1180,8 @@ if (this instanceof SmbNamedPipe) {
 
     String getServerWithDfs() {
         if (dfsReferral != null) {
-            /* Don't use dfsReferral.server because vers 1 referrals don't have it
-             */
-            char[] server = dfsReferral.node.toCharArray();
-            int start, end;
-
-            start = 0;
-            while (start < server.length && server[start] == '\\') {
-                start++;
-            }
-            end = start;
-            while (end < server.length && server[end] != '\\') {
-                end++;
-            }
-
-            return new String(server, start, end - start);
+            return dfsReferral.server;
         }
-
         return getServer();
     }
 /** 
@@ -1446,14 +1467,11 @@ if (this instanceof SmbNamedPipe) {
  */
 
     public String getDfsPath() throws SmbException {
-        connect0();
-        if( tree.inDfs ) {
-            exists();
-        }
+        resolveDfs(null);
         if( dfsReferral == null ) {
             return null;
         }
-        String path = "smb:/" + dfsReferral.node + unc;
+        String path = "smb:/" + dfsReferral.server + "/" + dfsReferral.share + unc;
         path = path.replace( '\\', '/' );
         if (isDirectory()) {
             path += '/';
@@ -1681,6 +1699,23 @@ if (this instanceof SmbNamedPipe) {
 
         map = new HashMap();
 
+        if (dfs.isTrustedDomain(getServer(), auth)) {
+            /* The server name is actually the name of a trusted
+             * domain. Add DFS roots to the list.
+             */
+            try {
+                entries = doDfsRootEnum();
+                for (int ei = 0; ei < entries.length; ei++) {
+                    e = entries[ei];
+                    if (map.containsKey(e) == false)
+                        map.put(e, e);
+                }
+            } catch (IOException ioe) {
+                if (log.level >= 4)
+                    ioe.printStackTrace(log);
+            }
+        }
+
         addr = getFirstAddress();
         while (addr != null) {
             try {
@@ -1697,6 +1732,7 @@ if (this instanceof SmbNamedPipe) {
                     if (map.containsKey(e) == false)
                         map.put(e, e);
                 }
+                break;
             } catch(IOException ioe) {
                 if (log.level >= 3)
                     ioe.printStackTrace(log);
@@ -1731,6 +1767,29 @@ if (this instanceof SmbNamedPipe) {
             }
         }
     }
+    FileEntry[] doDfsRootEnum() throws IOException {
+        MsrpcDfsRootEnum rpc;
+        DcerpcHandle handle = null;
+        FileEntry[] entries;
+
+        handle = DcerpcHandle.getHandle("ncacn_np:" +
+                    getAddress().getHostAddress() +
+                    "[\\PIPE\\netdfs]", auth);
+        try {
+            rpc = new MsrpcDfsRootEnum(getServer());
+            handle.sendrecv(rpc);
+            if (rpc.retval != 0)
+                throw new SmbException(rpc.retval, true);
+            return rpc.getEntries();
+        } finally {
+            try {
+                handle.close();
+            } catch(IOException ioe) {
+                if (log.level >= 4)
+                    ioe.printStackTrace(log);
+            }
+        }
+    }
     FileEntry[] doMsrpcShareEnum() throws IOException {
         MsrpcShareEnum rpc;
         DcerpcHandle handle;
@@ -1836,83 +1895,6 @@ if (this instanceof SmbNamedPipe) {
             resp.reset();
         } while(more);
     }
-    void doNetEnumX( ArrayList list,
-                boolean files,
-                String wildcard,
-                int searchAttributes,
-                SmbFilenameFilter fnf,
-                SmbFileFilter ff ) throws SmbException,
-                        UnknownHostException, MalformedURLException {
-        SmbComTransaction req;
-        SmbComTransactionResponse resp;
-        int listType = url.getHost().length() == 0 ? 0 : getType();
-        String p = url.getPath();
-
-        if( p.lastIndexOf( '/' ) != ( p.length() - 1 )) {
-            throw new SmbException( url.toString() + " directory must end with '/'" );
-        }
-
-        switch( listType ) {
-            case 0:
-                connect0();
-                req = new NetServerEnum2( tree.session.transport.server.oemDomainName,
-                        NetServerEnum2.SV_TYPE_DOMAIN_ENUM );
-                resp = new NetServerEnum2Response();
-                break;
-            case TYPE_WORKGROUP:
-                req = new NetServerEnum2( url.getHost(), NetServerEnum2.SV_TYPE_ALL );
-                resp = new NetServerEnum2Response();
-                break;
-            case TYPE_SERVER:
-                req = new NetShareEnum();
-                resp = new NetShareEnumResponse();
-                break;
-            default:
-                throw new SmbException( "The requested list operations is invalid: " + url.toString() );
-        }
-
-            boolean more;
-        do {
-            int n;
-
-            send( req, resp );
-
-            more = resp.status == SmbException.ERROR_MORE_DATA;
-
-            if( resp.status != SmbException.ERROR_SUCCESS &&
-                    resp.status != SmbException.ERROR_MORE_DATA ) {
-                throw new SmbException( resp.status, true );
-            }
-
-            n = more ? resp.numEntries - 1 : resp.numEntries;
-            for( int i = 0; i < n; i++ ) {
-                FileEntry e = resp.results[i];
-                String name = e.getName();
-                if( fnf != null && fnf.accept( this, name ) == false ) {
-                    continue;
-                }
-                if( name.length() > 0 ) {
-                    SmbFile f = new SmbFile( this, name,
-                                e.getType(),
-                                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 );
-            resp.reset();
-        } while( more );
-    }
     void doFindFirstNext( ArrayList list,
                 boolean files,
                 String wildcard,
@@ -2003,20 +1985,10 @@ if (this instanceof SmbNamedPipe) {
         if( getUncPath0().length() == 1 || dest.getUncPath0().length() == 1 ) {
             throw new SmbException( "Invalid operation for workgroups, servers, or shares" );
         }
-        connect0();
-        dest.connect0();
 
-        if( tree.inDfs ) { /* This ensures that each path is
-                * resolved independantly to deal with the case where files
-                * have the same base path but ultimately turn out to be
-                * on different servers because of DFS. It also eliminates
-                * manipulating the SMB path which is problematic because
-                * there are really two that would need to be prefixed
-                * with host and share as DFS requires.
-                */
-            exists();
-            dest.exists();
-        }
+        resolveDfs(null);
+        dest.resolveDfs(null);
+
         if (!tree.equals(dest.tree)) {
             throw new SmbException( "Invalid operation for workgroups, servers, or shares" );
         }
@@ -2249,7 +2221,6 @@ if (this instanceof SmbNamedPipe) {
         connect0();
         dest.connect0();
 
-        if( tree.inDfs ) {
                 /* At this point the maxBufferSize values are from the server
                  * exporting the volumes, not the one that we will actually
                  * end up performing IO with. If the server hosting the
@@ -2259,9 +2230,7 @@ if (this instanceof SmbNamedPipe) {
                  * establishing buffer size. These exists() calls facilitate
                  * that.
                  */
-            exists();
-            dest.exists();
-        }
+        resolveDfs(null);
 
         /* It is invalid for the source path to be a child of the destination
          * path or visa versa.
@@ -2312,10 +2281,7 @@ if (this instanceof SmbNamedPipe) {
  * @throws SmbException
  */
     public void delete() throws SmbException {
-        if( tree == null || tree.inDfs ) {
-            exists();      /* This is necessary to ensure we
-                            * pass a path adjusted for DFS */
-        }
+        exists();
         getUncPath0();
         delete( unc );
     }
@@ -2659,6 +2625,24 @@ if (this instanceof SmbNamedPipe) {
         return hash + canon.toUpperCase().hashCode();
     }
 
+    protected boolean pathNamesPossiblyEqual(String path1, String path2) {
+        int p1, p2, l1, l2;
+
+        // if unsure return this method returns true
+
+        p1 = path1.lastIndexOf('/');
+        p2 = path2.lastIndexOf('/');
+        l1 = path1.length() - p1;
+        l2 = path2.length() - p2;
+
+        // anything with dots voids comparison
+        if (l1 > 1 && path1.charAt(p1 + 1) == '.')
+            return true;
+        if (l2 > 1 && path2.charAt(p2 + 1) == '.')
+            return true;
+
+        return l1 == l2 && path1.regionMatches(true, p1, path2, p2, l1);
+    }
 /**
  * Tests to see if two <code>SmbFile</code> objects are equal. Two
  * SmbFile objects are equal when they reference the same SMB
@@ -2683,8 +2667,39 @@ if (this instanceof SmbNamedPipe) {
  */
 
     public boolean equals( Object obj ) {
+        if (obj instanceof SmbFile) {
+            SmbFile f = (SmbFile)obj;
+            boolean ret;
+
+            if (this == f)
+                return true;
+
+            /* If uncertain, pathNamesPossiblyEqual returns true.
+             * Comparing canonical paths is definitive.
+             */
+            if (pathNamesPossiblyEqual(url.getPath(), f.url.getPath())) {
+
+                getUncPath0();
+                f.getUncPath0();
+
+                if (canon.equalsIgnoreCase(f.canon)) {
+                    try {
+                        ret = getAddress().equals(f.getAddress());
+                    } catch( UnknownHostException uhe ) {
+                        ret = getServer().equalsIgnoreCase(f.getServer());
+                    }
+                    return ret;
+                }
+            }
+        }
+
+        return false;
+    }
+/*
+    public boolean equals( Object obj ) {
         return obj instanceof SmbFile && obj.hashCode() == hashCode();
     }
+*/
 
 /**
  * Returns the string representation of this SmbFile object. This will
@@ -2831,8 +2846,11 @@ if (this instanceof SmbNamedPipe) {
         DcerpcHandle handle;
         ACE[] aces;
 
-        rpc = new MsrpcShareGetInfo(url.getHost(), getShare());
-        handle = DcerpcHandle.getHandle("ncacn_np:" + url.getHost() + "[\\PIPE\\srvsvc]", auth);
+        resolveDfs(null);
+        String server = getServerWithDfs();
+
+        rpc = new MsrpcShareGetInfo(server, tree.share);
+        handle = DcerpcHandle.getHandle("ncacn_np:" + server + "[\\PIPE\\srvsvc]", auth);
 
         try {
             handle.sendrecv(rpc);
@@ -2868,4 +2886,5 @@ if (this instanceof SmbNamedPipe) {
     public ACE[] getSecurity() throws IOException {
         return getSecurity(false);
     }
+
 }
index 71f1399..0be7059 100644 (file)
@@ -175,7 +175,7 @@ do {
     }
 
     private int uid;
-    private Vector trees;
+    Vector trees;
     private boolean sessionSetup;
     // Transport parameters allows trans to be removed from CONNECTIONS
     private UniAddress address;
diff --git a/src/jcifs/smb/SmbSession.java.orig b/src/jcifs/smb/SmbSession.java.orig
deleted file mode 100644 (file)
index 1dca19a..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/* jcifs smb client library in Java
- * Copyright (C) 2000  "Michael B. Allen" <jcifs at samba dot org>
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-package jcifs.smb;
-
-import java.util.Vector;
-import java.util.Enumeration;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import jcifs.Config;
-import jcifs.UniAddress;
-import jcifs.netbios.NbtAddress;
-
-/**
- * The class represents a user's session established with an SMB/CIFS
- * server. This class is used internally to the jCIFS library however
- * applications may wish to authenticate aribrary user credentials
- * with the <tt>logon</tt> method. It is noteworthy that jCIFS does not
- * support DCE/RPC at this time and therefore does not use the NETLOGON
- * procedure. Instead, it simply performs a "tree connect" to IPC$ using
- * the supplied credentials. This is only a subset of the NETLOGON procedure
- * but is achives the same effect.
-
-Note that it is possible to change the resource against which clients
-are authenticated to be something other than <tt>IPC$</tt> using the
-<tt>jcifs.smb.client.logonShare</tt> property. This can be used to
-provide simple group based access control. For example, one could setup
-the NTLM HTTP Filter with the <tt>jcifs.smb.client.domainController</tt>
-init parameter set to the name of the server used for authentication. On
-that host, create a share called JCIFSAUTH and adjust the access control
-list for that share to permit only the clients that should have access to
-the target website. Finally, set the <tt>jcifs.smb.client.logonShare</tt>
-to JCIFSAUTH. This should restrict access to only those clients that have
-access to the JCIFSAUTH share. The access control on that share can be
-changed without changing init parameters or reinitializing the webapp.
- */
-
-public final class SmbSession {
-
-    private static final String LOGON_SHARE =
-                Config.getProperty( "jcifs.smb.client.logonShare", null );
-    private static final int LOOKUP_RESP_LIMIT =
-                Config.getInt( "jcifs.netbios.lookupRespLimit", 3 );
-    private static final String DOMAIN =
-                Config.getProperty("jcifs.smb.client.domain", null);
-    private static final String USERNAME =
-                Config.getProperty("jcifs.smb.client.username", null);
-    private static final int CACHE_POLICY =
-                Config.getInt( "jcifs.netbios.cachePolicy", 60 * 10 ) * 60; /* 10 hours */
-
-    static NbtAddress[] dc_list = null;
-    static long dc_list_expiration;
-    static int dc_list_counter;
-
-    private static NtlmChallenge interrogate( NbtAddress addr ) throws SmbException {
-        UniAddress dc = new UniAddress( addr );
-        SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 );
-        if (USERNAME == null) {
-            trans.connect();
-            if (SmbTransport.log.level >= 3)
-                SmbTransport.log.println(
-                    "Default credentials (jcifs.smb.client.username/password)" +
-                    " not specified. SMB signing may not work propertly." +
-                    "  Skipping DC interrogation." );
-        } else {
-            SmbSession ssn = trans.getSmbSession( NtlmPasswordAuthentication.DEFAULT );
-            ssn.getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
-        }
-        return new NtlmChallenge( trans.server.encryptionKey, dc );
-    }
-    public static NtlmChallenge getChallengeForDomain()
-                throws SmbException, UnknownHostException {
-        if( DOMAIN == null ) {
-            throw new SmbException( "A domain was not specified" );
-        }
-        synchronized (DOMAIN) {
-            long now = System.currentTimeMillis();
-int retry = 1;
-
-do {
-            if (dc_list_expiration < now) {
-                dc_list_expiration = now + CACHE_POLICY * 1000L;
-                NbtAddress[] list = NbtAddress.getAllByName( DOMAIN, 0x1C, null, null );
-                if (list != null && list.length > 0) {
-                    dc_list = list;
-                } else { /* keep using the old list */
-                    dc_list_expiration = now + 1000 * 60 * 15; /* 15 min */
-                    if (SmbTransport.log.level >= 2) {
-                        SmbTransport.log.println( "Failed to retrieve DC list from WINS" );
-                    }
-                }
-            }
-
-            int max = Math.min( dc_list.length, LOOKUP_RESP_LIMIT );
-            for (int j = 0; j < max; j++) {
-                int i = dc_list_counter++ % max;
-                if (dc_list[i] != null) {
-                    try {
-                        return interrogate( dc_list[i] );
-                    } catch (SmbException se) {
-                        if (SmbTransport.log.level >= 2) {
-                            SmbTransport.log.println( "Failed validate DC: " + dc_list[i] );
-                            if (SmbTransport.log.level > 2)
-                                se.printStackTrace( SmbTransport.log );
-                        }
-                    }
-                    dc_list[i] = null;
-                }
-            }
-
-/* No DCs found, for retieval of list by expiring it and retry.
- */
-            dc_list_expiration = 0;
-} while (retry-- > 0);
-
-            dc_list_expiration = now + 1000 * 60 * 15; /* 15 min */
-        }
-
-        throw new UnknownHostException(
-                "Failed to negotiate with a suitable domain controller for " + DOMAIN );
-    }
-
-    public static byte[] getChallenge( UniAddress dc )
-                throws SmbException, UnknownHostException {
-        return getChallenge(dc, 0);
-    }
-
-    public static byte[] getChallenge( UniAddress dc, int port )
-                throws SmbException, UnknownHostException {
-        SmbTransport trans = SmbTransport.getSmbTransport( dc, port );
-        trans.connect();
-        return trans.server.encryptionKey;
-    }
-/**
- * Authenticate arbitrary credentials represented by the
- * <tt>NtlmPasswordAuthentication</tt> object against the domain controller
- * specified by the <tt>UniAddress</tt> parameter. If the credentials are
- * not accepted, an <tt>SmbAuthException</tt> will be thrown. If an error
- * occurs an <tt>SmbException</tt> will be thrown. If the credentials are
- * valid, the method will return without throwing an exception. See the
- * last <a href="../../../faq.html">FAQ</a> question.
- *
- * See also the <tt>jcifs.smb.client.logonShare</tt> property.
- */
-    public static void logon( UniAddress dc,
-                        NtlmPasswordAuthentication auth ) throws SmbException {
-        logon(dc, 0, auth);
-    }
-
-    public static void logon( UniAddress dc, int port,
-                        NtlmPasswordAuthentication auth ) throws SmbException {
-        SmbTree tree = SmbTransport.getSmbTransport( dc, port ).getSmbSession( auth ).getSmbTree( LOGON_SHARE, null );
-        if( LOGON_SHARE == null ) {
-            tree.treeConnect( null, null );
-        } else {
-            Trans2FindFirst2 req = new Trans2FindFirst2( "\\", "*", SmbFile.ATTR_DIRECTORY );
-            Trans2FindFirst2Response resp = new Trans2FindFirst2Response();
-            tree.send( req, resp );
-        }
-    }
-
-    private int uid;
-    private Vector trees;
-    private boolean sessionSetup;
-    // Transport parameters allows trans to be removed from CONNECTIONS
-    private UniAddress address;
-    private int port, localPort;
-    private InetAddress localAddr;
-
-    SmbTransport transport = null;
-    NtlmPasswordAuthentication auth;
-    long expiration;
-
-    SmbSession( UniAddress address, int port,
-                InetAddress localAddr, int localPort,
-                NtlmPasswordAuthentication auth ) {
-        this.address = address;
-        this.port = port;
-        this.localAddr = localAddr;
-        this.localPort = localPort;
-        this.auth = auth;
-        trees = new Vector();
-    }
-
-    synchronized SmbTree getSmbTree( String share, String service ) {
-        SmbTree t;
-
-        if( share == null ) {
-            share = "IPC$";
-        }
-        for( Enumeration e = trees.elements(); e.hasMoreElements(); ) {
-            t = (SmbTree)e.nextElement();
-            if( t.matches( share, service )) {
-                return t;
-            }
-        }
-        t = new SmbTree( this, share, service );
-        trees.addElement( t );
-        return t;
-    }
-    boolean matches( NtlmPasswordAuthentication auth ) {
-        return this.auth == auth || this.auth.equals( auth );
-    }
-    synchronized SmbTransport transport() {
-        if( transport == null ) {
-            transport = SmbTransport.getSmbTransport( address, port, localAddr, localPort );
-        }
-        return transport;
-    }
-    void send( ServerMessageBlock request,
-                            ServerMessageBlock response ) throws SmbException {
-        if( response != null ) {
-            response.received = false;
-        }
-
-        synchronized(transport.setupDiscoLock) {
-            expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT;
-            sessionSetup( request, response );
-            if( response != null && response.received ) {
-                return;
-            }
-            request.uid = uid;
-            request.auth = auth;
-            transport.send( request, response );
-        }
-    }
-int x = 0;
-    void sessionSetup( ServerMessageBlock andx,
-                            ServerMessageBlock andxResponse ) throws SmbException {
-synchronized( transport() ) {
-        if( sessionSetup ) {
-            return;
-        }
-
-        transport.connect();
-
-        /*
-         * Session Setup And X Request / Response
-         */
-
-        if( transport.log.level >= 4 )
-            transport.log.println( "sessionSetup: accountName=" + auth.username + ",primaryDomain=" + auth.domain );
-
-        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 non-null or
-         * blank password initializes signing.
-         */
-        if (transport.isSignatureSetupRequired( auth )) {
-            if( auth.hashesExternal && NtlmPasswordAuthentication.DEFAULT_PASSWORD != NtlmPasswordAuthentication.BLANK ) {
-                /* preauthentication
-                 */
-                transport.getSmbSession( NtlmPasswordAuthentication.DEFAULT ).getSmbTree( LOGON_SHARE, null ).treeConnect( null, null );
-            } else {
-                request.digest = new SigningDigest( transport, auth );
-            }
-        }
-
-        request.auth = auth;
-        transport.send( request, response );
-
-        if( response.isLoggedInAsGuest &&
-                    "GUEST".equalsIgnoreCase( auth.username ) == false) {
-            throw new SmbAuthException( NtStatus.NT_STATUS_LOGON_FAILURE );
-        }
-
-        uid = response.uid;
-        sessionSetup = true;
-
-        if( request.digest != null ) {
-            /* success - install the signing digest */
-            transport.digest = request.digest;
-        }
-}
-    }
-    void logoff( boolean inError ) {
-synchronized( transport() ) {
-        if( sessionSetup == false ) {
-            return;
-        }
-
-        for( Enumeration e = trees.elements(); e.hasMoreElements(); ) {
-            SmbTree t = (SmbTree)e.nextElement();
-            t.treeDisconnect( inError );
-        }
-
-        if( !inError && transport.server.security != ServerMessageBlock.SECURITY_SHARE ) {
-
-            /*
-             * Logoff And X Request / Response
-             */
-
-            SmbComLogoffAndX request = new SmbComLogoffAndX( null );
-            request.uid = uid;
-            try {
-                transport.send( request, null );
-            } catch( SmbException se ) {
-            }
-        }
-
-        sessionSetup = false;
-}
-    }
-    public String toString() {
-        return "SmbSession[accountName=" + auth.username +
-                ",primaryDomain=" + auth.domain +
-                ",uid=" + uid +
-                ",sessionSetup=" + sessionSetup + "]";
-    }
-}
index ac71f25..b0c2e5d 100644 (file)
@@ -26,6 +26,14 @@ public class SmbShareInfo implements FileEntry {
     protected int type;
     protected String remark;
 
+    public SmbShareInfo() {
+    }
+    public SmbShareInfo(String netName, int type, String remark)
+    {
+        this.netName = netName;
+        this.type = type;
+        this.remark = remark;
+    }
     public String getName() {
         return netName;
     }
index 32ad4da..e394950 100644 (file)
@@ -27,12 +27,15 @@ import jcifs.*;
 import jcifs.netbios.*;
 import jcifs.util.*;
 import jcifs.util.transport.*;
+import jcifs.dcerpc.*;
+import jcifs.dcerpc.msrpc.*;
 
 public class SmbTransport extends Transport implements SmbConstants {
 
     static final byte[] BUF = new byte[0xFFFF];
     static final SmbComNegotiate NEGOTIATE_REQUEST = new SmbComNegotiate();
     static LogStream log = LogStream.getInstance();
+    static HashMap dfsRoots = null;
 
     static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
         return getSmbTransport( address, port, LADDR, LPORT );
@@ -509,9 +512,10 @@ public class SmbTransport extends Transport implements SmbConstants {
                 if( req.auth == null ) {
                     throw new SmbException( resp.errorCode, null );
                 }
-                DfsReferral dr = getDfsReferral( req.auth, req.path );
-                referrals.add( dr );
-                throw dr;
+
+                DfsReferral[] drs = getDfsReferrals(req.auth, req.path, 1);
+                SmbFile.dfs.insert(req.path, drs[0]);
+                throw drs[0];
             case 0x80000005:  /* STATUS_BUFFER_OVERFLOW */
                 break; /* normal for DCERPC named pipes */
             default:
@@ -623,61 +627,101 @@ public class SmbTransport extends Transport implements SmbConstants {
 
     /* DFS */
 
-    DfsReferral getDfsReferral( NtlmPasswordAuthentication auth,
-                String path ) throws SmbException {
-        String subpath, node, host;
-        DfsReferral dr = new DfsReferral();
-        int p, n, i, s;
-        UniAddress addr;
+    /* Split DFS path like \fs1.example.com\root5\link2\foo\bar.txt into at
+     * most 3 components (not including the first index which is always empty):
+     * result[0] = ""
+     * result[1] = "fs1.example.com"
+     * result[2] = "root5"
+     * result[3] = "link2\foo\bar.txt"
+     */
+    void dfsPathSplit(String path, String[] result)
+    {
+        int ri = 0, rlast = result.length - 1;
+        int i = 0, b = 0, len = path.length();
+
+        do {
+            if (ri == rlast) {
+                result[rlast] = path.substring(b);
+                return;
+            }
+            if (i == len || path.charAt(i) == '\\') {
+                result[ri++] = path.substring(b, i);
+                b = i + 1;
+            }
+        } while (i++ < len);
 
+        while (ri < result.length) {
+            result[ri++] = "";
+        }
+    }
+    DfsReferral[] getDfsReferrals(NtlmPasswordAuthentication auth,
+                String path,
+                int rn) throws SmbException {
         SmbTree ipc = getSmbSession( auth ).getSmbTree( "IPC$", null );
         Trans2GetDfsReferralResponse resp = new Trans2GetDfsReferralResponse();
         ipc.send( new Trans2GetDfsReferral( path ), resp );
 
-        subpath = path.substring( 0, resp.pathConsumed );
-        node = resp.referral.node;
-        if( subpath.charAt( 0 ) != '\\' ||
-                (i = subpath.indexOf( '\\', 1 )) < 2 ||
-                (p = subpath.indexOf( '\\', i + 1 )) < (i + 2) ||
-                node.charAt( 0 ) != '\\' ||
-                (s = node.indexOf( '\\', 1 )) < 2) {
-            throw new SmbException( "Invalid DFS path: " + path );
-        }
-        if ((n = node.indexOf( '\\', s + 1 )) == -1) {
-            n = node.length();
+        if (rn == 0 || resp.numReferrals < rn) {
+            rn = resp.numReferrals;
         }
 
-        dr.path = subpath.substring( p );
-        dr.node = node.substring( 0, n );
-        dr.nodepath = node.substring( n );
-        dr.server = node.substring( 1, s );
-        dr.share = node.substring( s + 1, n );
-        dr.resolveHashes = auth.hashesExternal;
+        DfsReferral[] drs = new DfsReferral[rn];
+        String[] arr = new String[4];
+        long expiration = System.currentTimeMillis() + Dfs.TTL * 1000;
+
+        for (int di = 0; di < drs.length; di++) {
+            DfsReferral dr = new DfsReferral();
                         /* NTLM HTTP Authentication must be re-negotiated
                          * with challenge from 'server' to access DFS vol. */
-        return dr;
+            dr.resolveHashes = auth.hashesExternal;
+            dr.ttl = resp.referrals[di].ttl;
+            dr.expiration = expiration;
+            if (path.equals("")) {
+                dr.server = resp.referrals[di].path.substring(1).toLowerCase();
+            } else {
+                dfsPathSplit(resp.referrals[di].node, arr);
+                dr.server = arr[1];
+                dr.share = arr[2];
+                dr.path = arr[3];
+            }
+            dr.pathConsumed = resp.pathConsumed;
+            drs[di] = dr;
+        }
+
+        return drs;
     }
-    DfsReferral lookupReferral( String unc ) {
-        synchronized( referrals ) {
-            DfsReferral dr;
-            ListIterator iter = referrals.listIterator();
-            int i, len;
+    FileEntry[] getDfsRoots(String domainName, NtlmPasswordAuthentication auth) throws IOException {
+        MsrpcDfsRootEnum rpc;
+        DcerpcHandle handle = null;
+
+        /* Procedure:
+         * Lookup a DC in the target domain
+         * Ask the DC for a referral for the domain (e.g. "\example.com")
+         * Do NetrDfsEnumEx on the server returned in the referral to
+         * get roots in target domain
+         */
 
-            while( iter.hasNext() ) {
-                dr = (DfsReferral)iter.next();
-                len = dr.path.length();
-                for( i = 0; i < len && i < unc.length(); i++ ) {
-                    if( dr.path.charAt( i ) != unc.charAt( i )) {
-                        break;
-                    }
-                }
-                if( i == len && (len == unc.length() || unc.charAt( len ) == '\\')) {
-                    return dr;
-                }
+        UniAddress dc = UniAddress.getByName(domainName);
+        SmbTransport trans = SmbTransport.getSmbTransport(dc, 0);
+        DfsReferral[] dr = trans.getDfsReferrals(auth, "\\" + domainName, 1);
+
+        handle = DcerpcHandle.getHandle("ncacn_np:" +
+                    UniAddress.getByName(dr[0].server).getHostAddress() +
+                    "[\\PIPE\\netdfs]", auth);
+        try {
+            rpc = new MsrpcDfsRootEnum(domainName);
+            handle.sendrecv(rpc);
+            if (rpc.retval != 0)
+                throw new SmbException(rpc.retval, true);
+            return rpc.getEntries();
+        } finally {
+            try {
+                handle.close();
+            } catch(IOException ioe) {
+                if (log.level >= 4)
+                    ioe.printStackTrace(log);
             }
         }
-
-        return null;
     }
 }
 
index 4319652..951bdcf 100644 (file)
@@ -29,11 +29,11 @@ class SmbTree {
     private static int tree_conn_counter;
 
     private int tid;
-    private String share;
 
+    String share;
     String service = "?????";
     SmbSession session;
-    boolean treeConnected, inDfs;
+    boolean treeConnected, inDfs, inDomainDfs;
     int tree_num;
 
     SmbTree( SmbSession session, String share, String service ) {
@@ -163,7 +163,7 @@ synchronized(transport) {
     }
     void treeDisconnect( boolean inError ) {
 synchronized( session.transport ) {
-        if (treeConnected && !inError) {
+        if (treeConnected && !inError && tid != 0) {
             try {
                 send( new SmbComTreeDisconnect(), null );
             } catch( SmbException se ) {
@@ -173,6 +173,8 @@ synchronized( session.transport ) {
             }
         }
         treeConnected = false;
+        inDfs = false;
+        inDomainDfs = false;
 }
     }
 
@@ -181,6 +183,7 @@ synchronized( session.transport ) {
             ",service=" + service +
             ",tid=" + tid +
             ",inDfs=" + inDfs +
+            ",inDomainDfs=" + inDomainDfs +
             ",treeConnected=" + treeConnected + "]";
     }
 }
index 7314c80..1976b73 100644 (file)
@@ -28,14 +28,14 @@ class Trans2GetDfsReferralResponse extends SmbComTransactionResponse {
         private int serverType;
         private int flags;
         private int proximity;
-        private int ttl;
         private int pathOffset;
         private int altPathOffset;
         private int nodeOffset;
-        private String path = null;
         private String altPath;
 
-        String node;
+        int ttl;
+        String path = null;
+        String node = null;
 
         int readWireFormat( byte[] buffer, int bufferIndex, int len ) {
             int start = bufferIndex;
@@ -64,7 +64,8 @@ if( version != 3 && version != 1 ) {
                 bufferIndex += 2;
 
                 path = readString( buffer, start + pathOffset, len, (flags2 & FLAGS2_UNICODE) != 0);
-                node = readString( buffer, start + nodeOffset, len, (flags2 & FLAGS2_UNICODE) != 0);
+                if (nodeOffset > 0)
+                    node = readString( buffer, start + nodeOffset, len, (flags2 & FLAGS2_UNICODE) != 0);
             } else if( version == 1 ) {
                 node = readString( buffer, bufferIndex, len, (flags2 & FLAGS2_UNICODE) != 0);
             }
@@ -86,7 +87,7 @@ if( version != 3 && version != 1 ) {
     int pathConsumed;
     int numReferrals;
     int flags;
-    Referral referral;
+    Referral[] referrals;
 
     Trans2GetDfsReferralResponse() {
         subCommand = SmbComTransaction.TRANS2_GET_DFS_REFERRAL;
@@ -124,12 +125,10 @@ if( version != 3 && version != 1 ) {
         flags = readInt2( buffer, bufferIndex );
         bufferIndex += 4;
 
-        referral = new Referral();
-        while( numReferrals-- > 0 ) { 
-            bufferIndex += referral.readWireFormat( buffer, bufferIndex, len );
-        }
-        if (referral.path != null && referral.path.charAt( pathConsumed - 1 ) == '\\' ) {
-            pathConsumed--;
+        referrals = new Referral[numReferrals];
+        for (int ri = 0; ri < numReferrals; ri++) {
+            referrals[ri] = new Referral();
+            bufferIndex += referrals[ri].readWireFormat( buffer, bufferIndex, len );
         }
 
         return bufferIndex - start;
@@ -137,7 +136,6 @@ if( version != 3 && version != 1 ) {
     public String toString() {
         return new String( "Trans2GetDfsReferralResponse[" +
             super.toString() + ",pathConsumed=" + pathConsumed +
-            ",numReferrals=" + numReferrals + ",flags=" + flags +
-            "," + referral + "]" );
+            ",numReferrals=" + numReferrals + ",flags=" + flags + "]" );
     }
 }