From: Felix Schumacher Date: Wed, 6 Jan 2010 13:50:44 +0000 (+0100) Subject: jcifs-1.3.13 from tgz X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=651e27420aa103a037874423a1b16d9ec3e24467;p=jcifs_without_docs.git jcifs-1.3.13 from tgz jcifs-1.3.13 Locking throughout the transport layer has been rewritten. This should fix the long standing deadlock that has been reported in the past. Doubled size of transient input buffer to accommodate SMB_COM_NEGOTIATE response security blob (as observed with OSX Snow Leopard). A signing issue reading data from an EMC server has been fixed. NTLMSSP logging has been improved. --- diff --git a/README.txt b/README.txt index 04d014e..92e79d4 100644 --- a/README.txt +++ b/README.txt @@ -1,3 +1,11 @@ +jcifs-1.3.13 + +Locking throughout the transport layer has been rewritten. This should +fix the long standing deadlock that has been reported in the past. Doubled +size of transient input buffer to accommodate SMB_COM_NEGOTIATE response +security blob (as observed with OSX Snow Leopard). A signing issue reading +data from an EMC server has been fixed. NTLMSSP logging has been improved. + Fri Aug 14 13:45:57 EDT 2009 jcifs-1.3.12 diff --git a/build.xml b/build.xml index 0fae674..ac701a2 100644 --- a/build.xml +++ b/build.xml @@ -1,7 +1,7 @@ - - + + diff --git a/examples/AclCrawler.class b/examples/AclCrawler.class new file mode 100644 index 0000000..c12c07a Binary files /dev/null and b/examples/AclCrawler.class differ diff --git a/examples/AllocInfo.class b/examples/AllocInfo.class new file mode 100644 index 0000000..d052675 Binary files /dev/null and b/examples/AllocInfo.class differ diff --git a/examples/Append.class b/examples/Append.class new file mode 100644 index 0000000..eadb65a Binary files /dev/null and b/examples/Append.class differ diff --git a/examples/AuthListFiles.class b/examples/AuthListFiles.class new file mode 100644 index 0000000..0f9f3bf Binary files /dev/null and b/examples/AuthListFiles.class differ diff --git a/examples/CallNamedPipe.class b/examples/CallNamedPipe.class new file mode 100644 index 0000000..1378730 Binary files /dev/null and b/examples/CallNamedPipe.class differ diff --git a/examples/CopyTo.class b/examples/CopyTo.class new file mode 100644 index 0000000..1eec536 Binary files /dev/null and b/examples/CopyTo.class differ diff --git a/examples/CountPerms.class b/examples/CountPerms.class new file mode 100644 index 0000000..6632e6e Binary files /dev/null and b/examples/CountPerms.class differ diff --git a/examples/CreateFile.class b/examples/CreateFile.class new file mode 100644 index 0000000..9ae7ab1 Binary files /dev/null and b/examples/CreateFile.class differ diff --git a/examples/Delete.class b/examples/Delete.class new file mode 100644 index 0000000..b52be49 Binary files /dev/null and b/examples/Delete.class differ diff --git a/examples/Equals.class b/examples/Equals.class new file mode 100644 index 0000000..d1ea38a Binary files /dev/null and b/examples/Equals.class differ diff --git a/examples/Exists.class b/examples/Exists.class new file mode 100644 index 0000000..9f03ca4 Binary files /dev/null and b/examples/Exists.class differ diff --git a/examples/FileInfo.class b/examples/FileInfo.class new file mode 100644 index 0000000..fbdcf11 Binary files /dev/null and b/examples/FileInfo.class differ diff --git a/examples/FileOps.class b/examples/FileOps.class new file mode 100644 index 0000000..9a0e176 Binary files /dev/null and b/examples/FileOps.class differ diff --git a/examples/FilterFiles$BigFileFilter.class b/examples/FilterFiles$BigFileFilter.class new file mode 100644 index 0000000..1cd1710 Binary files /dev/null and b/examples/FilterFiles$BigFileFilter.class differ diff --git a/examples/FilterFiles$ShortFilenameFilter.class b/examples/FilterFiles$ShortFilenameFilter.class new file mode 100644 index 0000000..0b43d22 Binary files /dev/null and b/examples/FilterFiles$ShortFilenameFilter.class differ diff --git a/examples/FilterFiles.class b/examples/FilterFiles.class new file mode 100644 index 0000000..e8f82a5 Binary files /dev/null and b/examples/FilterFiles.class differ diff --git a/examples/Format.class b/examples/Format.class new file mode 100644 index 0000000..998801f Binary files /dev/null and b/examples/Format.class differ diff --git a/examples/Get.class b/examples/Get.class new file mode 100644 index 0000000..8192c4a Binary files /dev/null and b/examples/Get.class differ diff --git a/examples/GetDate.class b/examples/GetDate.class new file mode 100644 index 0000000..8a82eaa Binary files /dev/null and b/examples/GetDate.class differ diff --git a/examples/GetDfsPath.class b/examples/GetDfsPath.class new file mode 100644 index 0000000..751b59a Binary files /dev/null and b/examples/GetDfsPath.class differ diff --git a/examples/GetGroupMemberSidsFromURL.class b/examples/GetGroupMemberSidsFromURL.class new file mode 100644 index 0000000..5334b1f Binary files /dev/null and b/examples/GetGroupMemberSidsFromURL.class differ diff --git a/examples/GetSecurity.class b/examples/GetSecurity.class new file mode 100644 index 0000000..0f1b2d2 Binary files /dev/null and b/examples/GetSecurity.class differ diff --git a/examples/GetShareSecurity.class b/examples/GetShareSecurity.class new file mode 100644 index 0000000..6d0f992 Binary files /dev/null and b/examples/GetShareSecurity.class differ diff --git a/examples/GetType.class b/examples/GetType.class new file mode 100644 index 0000000..1028177 Binary files /dev/null and b/examples/GetType.class differ diff --git a/examples/GetURL.class b/examples/GetURL.class new file mode 100644 index 0000000..e473c42 Binary files /dev/null and b/examples/GetURL.class differ diff --git a/examples/GrowWrite.class b/examples/GrowWrite.class new file mode 100644 index 0000000..2d0ecbb Binary files /dev/null and b/examples/GrowWrite.class differ diff --git a/examples/HttpURL.class b/examples/HttpURL.class new file mode 100644 index 0000000..55faf3c Binary files /dev/null and b/examples/HttpURL.class differ diff --git a/examples/Interleave$IThread.class b/examples/Interleave$IThread.class new file mode 100644 index 0000000..12d7d51 Binary files /dev/null and b/examples/Interleave$IThread.class differ diff --git a/examples/Interleave.class b/examples/Interleave.class new file mode 100644 index 0000000..4ea28d5 Binary files /dev/null and b/examples/Interleave.class differ diff --git a/examples/InterruptTest.class b/examples/InterruptTest.class new file mode 100644 index 0000000..65da543 Binary files /dev/null and b/examples/InterruptTest.class differ diff --git a/examples/IsDir.class b/examples/IsDir.class new file mode 100644 index 0000000..712a60e Binary files /dev/null and b/examples/IsDir.class differ diff --git a/examples/LargeListFiles.class b/examples/LargeListFiles.class new file mode 100644 index 0000000..83f6e76 Binary files /dev/null and b/examples/LargeListFiles.class differ diff --git a/examples/Length.class b/examples/Length.class new file mode 100644 index 0000000..b096ceb Binary files /dev/null and b/examples/Length.class differ diff --git a/examples/List.class b/examples/List.class new file mode 100644 index 0000000..2d2e7b0 Binary files /dev/null and b/examples/List.class differ diff --git a/examples/ListACL.class b/examples/ListACL.class new file mode 100644 index 0000000..6c591f9 Binary files /dev/null and b/examples/ListACL.class differ diff --git a/examples/ListFiles.class b/examples/ListFiles.class new file mode 100644 index 0000000..996f03a Binary files /dev/null and b/examples/ListFiles.class differ diff --git a/examples/ListTypes.class b/examples/ListTypes.class new file mode 100644 index 0000000..6da499c Binary files /dev/null and b/examples/ListTypes.class differ diff --git a/examples/Mkdir.class b/examples/Mkdir.class new file mode 100644 index 0000000..4c96536 Binary files /dev/null and b/examples/Mkdir.class differ diff --git a/examples/NodeStatus.class b/examples/NodeStatus.class new file mode 100644 index 0000000..12e8052 Binary files /dev/null and b/examples/NodeStatus.class differ diff --git a/examples/OpenExclusive.class b/examples/OpenExclusive.class new file mode 100644 index 0000000..1802220 Binary files /dev/null and b/examples/OpenExclusive.class differ diff --git a/examples/PeekNamedPipe$ReceiverThread.class b/examples/PeekNamedPipe$ReceiverThread.class new file mode 100644 index 0000000..642652c Binary files /dev/null and b/examples/PeekNamedPipe$ReceiverThread.class differ diff --git a/examples/PeekNamedPipe.class b/examples/PeekNamedPipe.class new file mode 100644 index 0000000..dcbf77f Binary files /dev/null and b/examples/PeekNamedPipe.class differ diff --git a/examples/PipeTalk$ReceiverThread.class b/examples/PipeTalk$ReceiverThread.class new file mode 100644 index 0000000..d05ca7a Binary files /dev/null and b/examples/PipeTalk$ReceiverThread.class differ diff --git a/examples/PipeTalk.class b/examples/PipeTalk.class new file mode 100644 index 0000000..d297503 Binary files /dev/null and b/examples/PipeTalk.class differ diff --git a/examples/Put.class b/examples/Put.class new file mode 100644 index 0000000..43b1e70 Binary files /dev/null and b/examples/Put.class differ diff --git a/examples/Query.class b/examples/Query.class new file mode 100644 index 0000000..0112790 Binary files /dev/null and b/examples/Query.class differ diff --git a/examples/RenameTo.class b/examples/RenameTo.class new file mode 100644 index 0000000..c169e35 Binary files /dev/null and b/examples/RenameTo.class differ diff --git a/examples/SetAttrs.class b/examples/SetAttrs.class new file mode 100644 index 0000000..d36bada Binary files /dev/null and b/examples/SetAttrs.class differ diff --git a/examples/SetTime.class b/examples/SetTime.class new file mode 100644 index 0000000..79b5e36 Binary files /dev/null and b/examples/SetTime.class differ diff --git a/examples/SidCacheTest.class b/examples/SidCacheTest.class new file mode 100644 index 0000000..fd2890b Binary files /dev/null and b/examples/SidCacheTest.class differ diff --git a/examples/SidCrawler.class b/examples/SidCrawler.class new file mode 100644 index 0000000..ba712c5 Binary files /dev/null and b/examples/SidCrawler.class differ diff --git a/examples/SlowRead.class b/examples/SlowRead.class new file mode 100644 index 0000000..8e87e10 Binary files /dev/null and b/examples/SlowRead.class differ diff --git a/examples/SlowWrite.class b/examples/SlowWrite.class new file mode 100644 index 0000000..84a1cff Binary files /dev/null and b/examples/SlowWrite.class differ diff --git a/examples/SmbCrawler.class b/examples/SmbCrawler.class new file mode 100644 index 0000000..efdb5e3 Binary files /dev/null and b/examples/SmbCrawler.class differ diff --git a/examples/SmbShell.class b/examples/SmbShell.class new file mode 100644 index 0000000..b9096fa Binary files /dev/null and b/examples/SmbShell.class differ diff --git a/examples/SmbTableFile.class b/examples/SmbTableFile.class new file mode 100644 index 0000000..c1bfe46 Binary files /dev/null and b/examples/SmbTableFile.class differ diff --git a/examples/SmbTableFileRecord.class b/examples/SmbTableFileRecord.class new file mode 100644 index 0000000..b5d68ff Binary files /dev/null and b/examples/SmbTableFileRecord.class differ diff --git a/examples/T2Crawler$CrawlerThread.class b/examples/T2Crawler$CrawlerThread.class new file mode 100644 index 0000000..0b40e5c Binary files /dev/null and b/examples/T2Crawler$CrawlerThread.class differ diff --git a/examples/T2Crawler$Semaphore.class b/examples/T2Crawler$Semaphore.class new file mode 100644 index 0000000..af3b771 Binary files /dev/null and b/examples/T2Crawler$Semaphore.class differ diff --git a/examples/T2Crawler.class b/examples/T2Crawler.class new file mode 100644 index 0000000..4176b41 Binary files /dev/null and b/examples/T2Crawler.class differ diff --git a/examples/TestRandomAccess$TestRecord.class b/examples/TestRandomAccess$TestRecord.class new file mode 100644 index 0000000..872eb31 Binary files /dev/null and b/examples/TestRandomAccess$TestRecord.class differ diff --git a/examples/TestRandomAccess.class b/examples/TestRandomAccess.class new file mode 100644 index 0000000..5fdf0df Binary files /dev/null and b/examples/TestRandomAccess.class differ diff --git a/examples/TestSmbURL.class b/examples/TestSmbURL.class new file mode 100644 index 0000000..d73dd32 Binary files /dev/null and b/examples/TestSmbURL.class differ diff --git a/examples/TestUnicode.class b/examples/TestUnicode.class new file mode 100644 index 0000000..92304e8 Binary files /dev/null and b/examples/TestUnicode.class differ diff --git a/examples/ThreadedNbtQuery$QThread.class b/examples/ThreadedNbtQuery$QThread.class new file mode 100644 index 0000000..1259b6d Binary files /dev/null and b/examples/ThreadedNbtQuery$QThread.class differ diff --git a/examples/ThreadedNbtQuery.class b/examples/ThreadedNbtQuery.class new file mode 100644 index 0000000..0d21e06 Binary files /dev/null and b/examples/ThreadedNbtQuery.class differ diff --git a/examples/ThreadedSmbCrawler$DirEntry.class b/examples/ThreadedSmbCrawler$DirEntry.class new file mode 100644 index 0000000..f849d93 Binary files /dev/null and b/examples/ThreadedSmbCrawler$DirEntry.class differ diff --git a/examples/ThreadedSmbCrawler$SmbCrawlerThread.class b/examples/ThreadedSmbCrawler$SmbCrawlerThread.class new file mode 100644 index 0000000..a95e988 Binary files /dev/null and b/examples/ThreadedSmbCrawler$SmbCrawlerThread.class differ diff --git a/examples/ThreadedSmbCrawler.class b/examples/ThreadedSmbCrawler.class new file mode 100644 index 0000000..e0747bf Binary files /dev/null and b/examples/ThreadedSmbCrawler.class differ diff --git a/examples/ThreadedUniQuery$QThread.class b/examples/ThreadedUniQuery$QThread.class new file mode 100644 index 0000000..02d02e0 Binary files /dev/null and b/examples/ThreadedUniQuery$QThread.class differ diff --git a/examples/ThreadedUniQuery.class b/examples/ThreadedUniQuery.class new file mode 100644 index 0000000..08632f7 Binary files /dev/null and b/examples/ThreadedUniQuery.class differ diff --git a/examples/Torture1.class b/examples/Torture1.class new file mode 100644 index 0000000..72d5f77 Binary files /dev/null and b/examples/Torture1.class differ diff --git a/examples/Torture2.class b/examples/Torture2.class new file mode 100644 index 0000000..e688b4f Binary files /dev/null and b/examples/Torture2.class differ diff --git a/examples/TortureTest5.class b/examples/TortureTest5.class new file mode 100644 index 0000000..cadf7c2 Binary files /dev/null and b/examples/TortureTest5.class differ diff --git a/examples/TransactNamedPipe.class b/examples/TransactNamedPipe.class new file mode 100644 index 0000000..faea615 Binary files /dev/null and b/examples/TransactNamedPipe.class differ diff --git a/examples/URLTest.class b/examples/URLTest.class new file mode 100644 index 0000000..5263435 Binary files /dev/null and b/examples/URLTest.class differ diff --git a/examples/VerifyGuest.class b/examples/VerifyGuest.class new file mode 100644 index 0000000..6a8ce08 Binary files /dev/null and b/examples/VerifyGuest.class differ diff --git a/examples/VerifyIO.class b/examples/VerifyIO.class new file mode 100644 index 0000000..1168477 Binary files /dev/null and b/examples/VerifyIO.class differ diff --git a/examples/VerifyReads.class b/examples/VerifyReads.class new file mode 100644 index 0000000..ff0d0a1 Binary files /dev/null and b/examples/VerifyReads.class differ diff --git a/examples/Worker.class b/examples/Worker.class new file mode 100644 index 0000000..25fa3b2 Binary files /dev/null and b/examples/Worker.class differ diff --git a/examples/runtests.sh b/examples/runtests.sh index d648054..c44872f 100644 --- a/examples/runtests.sh +++ b/examples/runtests.sh @@ -16,7 +16,7 @@ SERVER=w.net SHARE=root2 DIR=test -# smb://fs1.w.net/DFSStandaloneRoot/DFSStandaloneLink/test/ +# smb://fs4.w.net/DFSStandaloneRoot/DFSStandaloneLink/test/ # smb://dc1.w.net/root2/link2/test/ # smb://dc1.w.net/tmp/test/ # smb://dc3.x.net/tmp/test/ diff --git a/patches/SetAccessTime.patch b/patches/SetAccessTime.patch new file mode 100644 index 0000000..71bdb55 --- /dev/null +++ b/patches/SetAccessTime.patch @@ -0,0 +1,101 @@ +--- jcifs_1.3.12/src/jcifs/smb/SmbFile.java ++++ jcifs/src/jcifs/smb/SmbFile.java +@@ -2564,6 +2564,21 @@ + attrExpiration = 0; + } + ++ void setPathInformation( int attrs, long ctime, long atime, long mtime ) throws SmbException { ++ int f, dir; ++ ++ exists(); ++ dir = attributes & ATTR_DIRECTORY; ++ ++ f = open0( O_RDONLY, FILE_WRITE_ATTRIBUTES, ++ dir, dir != 0 ? 0x0001 : 0x0040 ); ++ send( new Trans2SetFileInformation( f, attrs | dir, ctime, atime, mtime ), ++ new Trans2SetFileInformationResponse() ); ++ close( f, 0L ); ++ ++ 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 +@@ -2581,6 +2596,22 @@ + setPathInformation( 0, time, 0L ); + } + /** ++ * Set the access 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 ++ * createTime() method. ++ *

++ * This method does not apply to workgroups, servers, or shares. ++ * ++ * @param time the create time as milliseconds since Jan 1, 1970 ++ */ ++ public void setAccessTime( long time ) throws SmbException { ++ if( getUncPath0().length() == 1 ) { ++ throw new SmbException( "Invalid operation for workgroups, servers, or shares" ); ++ } ++ ++ setPathInformation( 0, 0L, 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 + * lastModified(), getLastModified(), and getDate() methods. +--- jcifs_1.3.12/src/jcifs/smb/Trans2SetFileInformation.java ++++ jcifs/src/jcifs/smb/Trans2SetFileInformation.java +@@ -25,6 +25,7 @@ + private int fid; + private int attributes; + private long createTime, lastWriteTime; ++ private long accessTime; + + Trans2SetFileInformation( int fid, int attributes, long createTime, long lastWriteTime ) { + this.fid = fid; +@@ -38,6 +39,19 @@ + maxSetupCount = (byte)0x00; + } + ++ Trans2SetFileInformation( int fid, int attributes, long createTime, long accessTime, long lastWriteTime ) { ++ this.fid = fid; ++ this.attributes = attributes; ++ this.accessTime = accessTime; ++ this.createTime = createTime; ++ this.lastWriteTime = lastWriteTime; ++ command = SMB_COM_TRANSACTION2; ++ subCommand = TRANS2_SET_FILE_INFORMATION; ++ maxParameterCount = 6; ++ maxDataCount = 0; ++ maxSetupCount = (byte)0x00; ++ } ++ + int writeSetupWireFormat( byte[] dst, int dstIndex ) { + dst[dstIndex++] = subCommand; + dst[dstIndex++] = (byte)0x00; +@@ -58,13 +72,22 @@ + int writeDataWireFormat( byte[] dst, int dstIndex ) { + int start = dstIndex; + ++ // create time + writeTime( createTime, dst, dstIndex ); dstIndex += 8; +- writeInt8( 0L, dst, dstIndex ); dstIndex += 8; ++ ++ // access time ++ writeInt8( accessTime, dst, dstIndex ); dstIndex += 8; ++ ++ // last write time [modification] + writeTime( lastWriteTime, dst, dstIndex ); dstIndex += 8; ++ ++ // change time + writeInt8( 0L, dst, dstIndex ); dstIndex += 8; ++ + /* Samba 2.2.7 needs ATTR_NORMAL + */ + writeInt2( 0x80 | attributes, dst, dstIndex ); dstIndex += 2; ++ + /* 6 zeros observed with NT */ + writeInt8( 0L, dst, dstIndex ); dstIndex += 6; + diff --git a/src/jcifs/dcerpc/DcerpcHandle.java b/src/jcifs/dcerpc/DcerpcHandle.java index 72bd37b..279dd16 100644 --- a/src/jcifs/dcerpc/DcerpcHandle.java +++ b/src/jcifs/dcerpc/DcerpcHandle.java @@ -140,11 +140,7 @@ public abstract class DcerpcHandle implements DcerpcConstants { isDirect = msg instanceof DcerpcBind; - try { - stub = jcifs.smb.BufferCache.getBuffer(); - } catch (InterruptedException ie) { - throw new IOException(ie.getMessage()); - } + stub = jcifs.smb.BufferCache.getBuffer(); try { int off, tot, n; diff --git a/src/jcifs/ntlmssp/Type1Message.java b/src/jcifs/ntlmssp/Type1Message.java index 754575b..450fb2b 100644 --- a/src/jcifs/ntlmssp/Type1Message.java +++ b/src/jcifs/ntlmssp/Type1Message.java @@ -169,29 +169,9 @@ public class Type1Message extends NtlmMessage { public String toString() { String suppliedDomain = getSuppliedDomain(); String suppliedWorkstation = getSuppliedWorkstation(); - int flags = getFlags(); - StringBuffer buffer = new StringBuffer(); - if (suppliedDomain != null) { - buffer.append("suppliedDomain: ").append(suppliedDomain); - } - if (suppliedWorkstation != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("suppliedWorkstation: ").append(suppliedWorkstation); - } - if (flags != 0) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("flags: "); - buffer.append("0x"); - buffer.append(Integer.toHexString((flags >> 28) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 24) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 20) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 16) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 12) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 8) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 4) & 0x0f)); - buffer.append(Integer.toHexString(flags & 0x0f)); - } - return buffer.toString(); + return "Type1Message[suppliedDomain=" + (suppliedDomain == null ? "null" : suppliedDomain) + + ",suppliedWorkstation=" + (suppliedWorkstation == null ? "null" : suppliedWorkstation) + + ",flags=0x" + jcifs.util.Hexdump.toHexString(getFlags(), 8) + "]"; } /** diff --git a/src/jcifs/ntlmssp/Type2Message.java b/src/jcifs/ntlmssp/Type2Message.java index 355a0b3..26fe976 100644 --- a/src/jcifs/ntlmssp/Type2Message.java +++ b/src/jcifs/ntlmssp/Type2Message.java @@ -276,53 +276,12 @@ public class Type2Message extends NtlmMessage { byte[] challenge = getChallenge(); byte[] context = getContext(); byte[] targetInformation = getTargetInformation(); - int flags = getFlags(); - StringBuffer buffer = new StringBuffer(); - if (target != null) { - buffer.append("target: ").append(target); - } - if (challenge != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("challenge: "); - buffer.append("0x"); - for (int i = 0; i < challenge.length; i++) { - buffer.append(Integer.toHexString((challenge[i] >> 4) & 0x0f)); - buffer.append(Integer.toHexString(challenge[i] & 0x0f)); - } - } - if (context != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("context: "); - buffer.append("0x"); - for (int i = 0; i < context.length; i++) { - buffer.append(Integer.toHexString((context[i] >> 4) & 0x0f)); - buffer.append(Integer.toHexString(context[i] & 0x0f)); - } - } - if (targetInformation != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("targetInformation: "); - buffer.append("0x"); - for (int i = 0; i < targetInformation.length; i++) { - buffer.append(Integer.toHexString((targetInformation[i] >> 4) & - 0x0f)); - buffer.append(Integer.toHexString(targetInformation[i] & 0x0f)); - } - } - if (flags != 0) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("flags: "); - buffer.append("0x"); - buffer.append(Integer.toHexString((flags >> 28) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 24) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 20) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 16) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 12) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 8) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 4) & 0x0f)); - buffer.append(Integer.toHexString(flags & 0x0f)); - } - return buffer.toString(); + + return "Type2Message[target=" + target + + ",challenge=" + (challenge == null ? "null" : "<" + challenge.length + " bytes>") + + ",context=" + (context == null ? "null" : "<" + context.length + " bytes>") + + ",targetInformation=" + (targetInformation == null ? "null" : "<" + targetInformation.length + " bytes>") + + ",flags=0x" + jcifs.util.Hexdump.toHexString(getFlags(), 8) + "]"; } /** diff --git a/src/jcifs/ntlmssp/Type3Message.java b/src/jcifs/ntlmssp/Type3Message.java index 8bfe930..5f74054 100644 --- a/src/jcifs/ntlmssp/Type3Message.java +++ b/src/jcifs/ntlmssp/Type3Message.java @@ -489,60 +489,14 @@ public class Type3Message extends NtlmMessage { byte[] lmResponse = getLMResponse(); byte[] ntResponse = getNTResponse(); byte[] sessionKey = getSessionKey(); - int flags = getFlags(); - StringBuffer buffer = new StringBuffer(); - if (domain != null) { - buffer.append("domain: ").append(domain); - } - if (user != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("user: ").append(user); - } - if (workstation != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("workstation: ").append(workstation); - } - if (lmResponse != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("lmResponse: "); - buffer.append("0x"); - for (int i = 0; i < lmResponse.length; i++) { - buffer.append(Integer.toHexString((lmResponse[i] >> 4) & 0x0f)); - buffer.append(Integer.toHexString(lmResponse[i] & 0x0f)); - } - } - if (ntResponse != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("ntResponse: "); - buffer.append("0x"); - for (int i = 0; i < ntResponse.length; i++) { - buffer.append(Integer.toHexString((ntResponse[i] >> 4) & 0x0f)); - buffer.append(Integer.toHexString(ntResponse[i] & 0x0f)); - } - } - if (sessionKey != null) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("sessionKey: "); - buffer.append("0x"); - for (int i = 0; i < sessionKey.length; i++) { - buffer.append(Integer.toHexString((sessionKey[i] >> 4) & 0x0f)); - buffer.append(Integer.toHexString(sessionKey[i] & 0x0f)); - } - } - if (flags != 0) { - if (buffer.length() > 0) buffer.append("; "); - buffer.append("flags: "); - buffer.append("0x"); - buffer.append(Integer.toHexString((flags >> 28) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 24) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 20) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 16) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 12) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 8) & 0x0f)); - buffer.append(Integer.toHexString((flags >> 4) & 0x0f)); - buffer.append(Integer.toHexString(flags & 0x0f)); - } - return buffer.toString(); + + return "Type3Message[domain=" + domain + + ",user=" + user + + ",workstation=" + workstation + + ",lmResponse=" + (lmResponse == null ? "null" : "<" + lmResponse.length + " bytes>") + + ",ntResponse=" + (ntResponse == null ? "null" : "<" + ntResponse.length + " bytes>") + + ",sessionKey=" + (sessionKey == null ? "null" : "<" + sessionKey.length + " bytes>") + + ",flags=0x" + jcifs.util.Hexdump.toHexString(getFlags(), 8) + "]"; } /** diff --git a/src/jcifs/smb/BufferCache.jav b/src/jcifs/smb/BufferCache.jav new file mode 100644 index 0000000..1dea6bf --- /dev/null +++ b/src/jcifs/smb/BufferCache.jav @@ -0,0 +1,83 @@ +/* jcifs smb client library in Java + * Copyright (C) 2000 "Michael B. Allen" + * + * 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 jcifs.Config; + +public class BufferCache { + + private static final int MAX_BUFFERS = Config.getInt( "jcifs.smb.maxBuffers", 16 ); + + static Object[] cache = new Object[MAX_BUFFERS]; + private static int freeBuffers = 0; + + private static byte[] getBuffer0() { + byte[] buf; + + if (freeBuffers > 0) { + for (int i = 0; i < MAX_BUFFERS; i++) { + if( cache[i] != null ) { + buf = (byte[])cache[i]; + cache[i] = null; + freeBuffers--; + return buf; + } + } + } + + buf = new byte[SmbComTransaction.TRANSACTION_BUF_SIZE]; + + return buf; + } + + static void getBuffers( SmbComTransaction req, + SmbComTransactionResponse rsp ) throws InterruptedException { + synchronized( cache ) { + if (freeBuffers < 2) { + /* The first time this is called we always wait because freeBuffers + * will be 0. But after a few calls to releaseBuffer, threads will + * no longer wait. + */ + cache.wait(100); + } + req.txn_buf = getBuffer0(); + rsp.txn_buf = getBuffer0(); + } + } + static public byte[] getBuffer() throws InterruptedException { + synchronized( cache ) { + if (freeBuffers < 1) { + cache.wait(100); + } + return getBuffer0(); + } + } + static public void releaseBuffer( byte[] buf ) { + synchronized( cache ) { + for (int i = 0; i < MAX_BUFFERS; i++) { + if (cache[i] == null) { + cache[i] = buf; + freeBuffers++; + cache.notify(); + return; + } + } + } + } +} diff --git a/src/jcifs/smb/BufferCache.java b/src/jcifs/smb/BufferCache.java index 14fa4fa..dce2525 100644 --- a/src/jcifs/smb/BufferCache.java +++ b/src/jcifs/smb/BufferCache.java @@ -25,55 +25,43 @@ public class BufferCache { private static final int MAX_BUFFERS = Config.getInt( "jcifs.smb.maxBuffers", 16 ); static Object[] cache = new Object[MAX_BUFFERS]; - private static int numBuffers = 0; private static int freeBuffers = 0; - private static byte[] getBuffer0() { - byte[] buf; + static public byte[] getBuffer() { + synchronized( cache ) { + byte[] buf; - if (freeBuffers > 0) { - for (int i = 0; i < MAX_BUFFERS; i++) { - if( cache[i] != null ) { - buf = (byte[])cache[i]; - cache[i] = null; - freeBuffers--; - return buf; + if (freeBuffers > 0) { + for (int i = 0; i < MAX_BUFFERS; i++) { + if( cache[i] != null ) { + buf = (byte[])cache[i]; + cache[i] = null; + freeBuffers--; + return buf; + } } } - } - buf = new byte[SmbComTransaction.TRANSACTION_BUF_SIZE]; - numBuffers++; - - return buf; - } + buf = new byte[SmbComTransaction.TRANSACTION_BUF_SIZE]; - static void getBuffers( SmbComTransaction req, - SmbComTransactionResponse rsp ) throws InterruptedException { - synchronized( cache ) { - while ((freeBuffers + (MAX_BUFFERS - numBuffers)) < 2) { - cache.wait(); - } - req.txn_buf = getBuffer0(); - rsp.txn_buf = getBuffer0(); + return buf; } } - static public byte[] getBuffer() throws InterruptedException { + static void getBuffers( SmbComTransaction req, SmbComTransactionResponse rsp ) { synchronized( cache ) { - while ((freeBuffers + (MAX_BUFFERS - numBuffers)) < 1) { - cache.wait(); - } - return getBuffer0(); + req.txn_buf = getBuffer(); + rsp.txn_buf = getBuffer(); } } static public void releaseBuffer( byte[] buf ) { synchronized( cache ) { - for (int i = 0; i < MAX_BUFFERS; i++) { - if (cache[i] == null) { - cache[i] = buf; - freeBuffers++; - cache.notify(); - return; + if (freeBuffers < MAX_BUFFERS) { + for (int i = 0; i < MAX_BUFFERS; i++) { + if (cache[i] == null) { + cache[i] = buf; + freeBuffers++; + return; + } } } } diff --git a/src/jcifs/smb/NtlmContext.java b/src/jcifs/smb/NtlmContext.java index 9484dd6..84217a7 100644 --- a/src/jcifs/smb/NtlmContext.java +++ b/src/jcifs/smb/NtlmContext.java @@ -21,6 +21,8 @@ package jcifs.smb; import java.io.IOException; import java.security.*; import jcifs.ntlmssp.*; +import jcifs.util.LogStream; +import jcifs.util.Hexdump; /** For initiating NTLM authentication (including NTLMv2). If you want to add NTLMv2 authentication support to something this is what you want to use. See the code for details. Note that JCIFS does not implement the acceptor side of NTLM authentication. @@ -28,6 +30,7 @@ For initiating NTLM authentication (including NTLMv2). If you want to add NTLMv2 public class NtlmContext { + NtlmPasswordAuthentication auth; int ntlmsspFlags; String workstation; @@ -35,6 +38,7 @@ public class NtlmContext { byte[] serverChallenge = null; byte[] signingKey = null; int state = 1; + LogStream log; public NtlmContext(NtlmPasswordAuthentication auth, boolean doSigning) { this.auth = auth; @@ -48,6 +52,29 @@ public class NtlmContext { NtlmFlags.NTLMSSP_NEGOTIATE_KEY_EXCH; } this.workstation = Type1Message.getDefaultWorkstation(); + log = LogStream.getInstance(); + } + + public String toString() { + String ret = "NtlmContext[auth=" + auth + + ",ntlmsspFlags=0x" + Hexdump.toHexString(ntlmsspFlags, 8) + + ",workstation=" + workstation + + ",isEstablished=" + isEstablished + + ",state=" + state + + ",serverChallenge="; + if (serverChallenge == null) { + ret += "null"; + } else { + ret += Hexdump.toHexString(serverChallenge, 0, serverChallenge.length * 2); + } + ret += ",signingKey="; + if (signingKey == null) { + ret += "null"; + } else { + ret += Hexdump.toHexString(signingKey, 0, signingKey.length * 2); + } + ret += "]"; + return ret; } public boolean isEstablished() { @@ -67,12 +94,25 @@ public class NtlmContext { case 1: Type1Message msg1 = new Type1Message(ntlmsspFlags, auth.getDomain(), workstation); token = msg1.toByteArray(); + + if (log.level >= 4) { + log.println(msg1); + if (log.level >= 6) + Hexdump.hexdump(log, token, 0, token.length); + } + state++; break; case 2: try { Type2Message msg2 = new Type2Message(token); + if (log.level >= 4) { + log.println(msg2); + if (log.level >= 6) + Hexdump.hexdump(log, token, 0, token.length); + } + serverChallenge = msg2.getChallenge(); ntlmsspFlags &= msg2.getFlags(); @@ -84,6 +124,12 @@ public class NtlmContext { ntlmsspFlags); token = msg3.toByteArray(); + if (log.level >= 4) { + log.println(msg3); + if (log.level >= 6) + Hexdump.hexdump(log, token, 0, token.length); + } + if ((ntlmsspFlags & NtlmFlags.NTLMSSP_NEGOTIATE_SIGN) != 0) signingKey = msg3.getMasterKey(); diff --git a/src/jcifs/smb/SmbFile.java b/src/jcifs/smb/SmbFile.java index 8ff3a44..07fdf22 100644 --- a/src/jcifs/smb/SmbFile.java +++ b/src/jcifs/smb/SmbFile.java @@ -423,7 +423,7 @@ public class SmbFile extends URLConnection implements SmbConstants { protected static Dfs dfs; NtlmPasswordAuthentication auth; // Cannot be null - SmbTree tree = null; // Initially null; may be !tree.treeConnected + SmbTree tree = null; // Initially null String unc; // Initially null; set by getUncPath; never ends with '/' int fid; // Initially 0; set by open() int type; @@ -889,7 +889,7 @@ int addressIndex; String hostName = getServerWithDfs(); tree.inDomainDfs = dfs.resolve(hostName, tree.share, null, auth) != null; if (tree.inDomainDfs) { - tree.treeConnected = true; + tree.connectionState = 2; } try { @@ -912,7 +912,7 @@ int addressIndex; tree = ssn.getSmbTree(share, null); tree.inDomainDfs = dfs.resolve(hostName, tree.share, null, auth) != null; if (tree.inDomainDfs) { - tree.treeConnected = true; + tree.connectionState = 2; } tree.treeConnect(null, null); } else { @@ -950,7 +950,7 @@ int addressIndex; } } boolean isConnected() { - return tree != null && tree.treeConnected; + return tree != null && tree.connectionState == 2; } int open0( int flags, int access, int attrs, int options ) throws SmbException { int f; @@ -994,7 +994,7 @@ if (this instanceof SmbNamedPipe) { tree_num = tree.tree_num; } boolean isOpen() { - boolean ans = opened && isConnected() && tree_num == tree.tree_num; + boolean ans = opened && isConnected() && tree_num == tree.tree_num; return ans; } void close( int f, long lastWriteTime ) throws SmbException { diff --git a/src/jcifs/smb/SmbSession.java b/src/jcifs/smb/SmbSession.java index 1f48337..60646f3 100644 --- a/src/jcifs/smb/SmbSession.java +++ b/src/jcifs/smb/SmbSession.java @@ -70,48 +70,48 @@ public final class SmbSession { if( DOMAIN == null ) { throw new SmbException( "A domain was not specified" ); } - synchronized (DOMAIN) { +synchronized (DOMAIN) { long now = System.currentTimeMillis(); -int retry = 1; - -do { - if (dc_list_expiration < now) { - NbtAddress[] list = NbtAddress.getAllByName( DOMAIN, 0x1C, null, null ); - dc_list_expiration = now + CACHE_POLICY * 1000L; - 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 retry = 1; + + do { + if (dc_list_expiration < now) { + NbtAddress[] list = NbtAddress.getAllByName( DOMAIN, 0x1C, null, null ); + dc_list_expiration = now + CACHE_POLICY * 1000L; + 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 ); + 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; } - dc_list[i] = null; } - } -/* No DCs found, for retieval of list by expiring it and retry. - */ - dc_list_expiration = 0; -} while (retry-- > 0); + /* 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 ); @@ -158,9 +158,14 @@ do { } } - private int uid; + /* 0 - not connected + * 1 - connecting + * 2 - connected + * 3 - disconnecting + */ + int connectionState; + int uid; Vector trees; - private boolean sessionSetup; // Transport parameters allows trans to be removed from CONNECTIONS private UniAddress address; private int port, localPort; @@ -179,6 +184,7 @@ do { this.localPort = localPort; this.auth = auth; trees = new Vector(); + connectionState = 0; } synchronized SmbTree getSmbTree( String share, String service ) { @@ -208,31 +214,32 @@ do { } void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { +synchronized (transport()) { 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; - try { - transport.send( request, response ); - } catch (SmbException se) { - if (request instanceof SmbComTreeConnectAndX) { - logoff(true); - } - request.digest = null; - throw se; + expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT; + sessionSetup( request, response ); + if( response != null && response.received ) { + return; + } + request.uid = uid; + request.auth = auth; + try { + transport.send( request, response ); + } catch (SmbException se) { + if (request instanceof SmbComTreeConnectAndX) { + logoff(true); } + request.digest = null; + throw se; } +} } void sessionSetup( ServerMessageBlock andx, - ServerMessageBlock andxResponse ) throws SmbException { + ServerMessageBlock andxResponse ) throws SmbException { +synchronized (transport()) { NtlmContext nctx = null; SmbException ex = null; SmbComSessionSetupAndX request; @@ -240,166 +247,187 @@ do { byte[] token = new byte[0]; int state = 10; -synchronized( transport() ) { - if( sessionSetup ) { - return; + while (connectionState != 0) { + if (connectionState == 2 || connectionState == 3) // connected or disconnecting + return; + try { + transport.wait(); + } catch (InterruptedException ie) { + throw new SmbException(ie.getMessage(), ie); + } } + connectionState = 1; // trying ... - transport.connect(); - - /* - * Session Setup And X Request / Response - */ - - if( transport.log.level >= 4 ) - transport.log.println( "sessionSetup: accountName=" + auth.username + ",primaryDomain=" + auth.domain ); - - /* We explicitly set uid to 0 here to prevent a new - * SMB_COM_SESSION_SETUP_ANDX from having it's uid set to an - * old value when the session is re-established. Otherwise a - * "The parameter is incorrect" error can occur. - */ - uid = 0; - - do { - switch (state) { - case 10: /* NTLM */ - if (auth != NtlmPasswordAuthentication.ANONYMOUS && - transport.hasCapability(SmbConstants.CAP_EXTENDED_SECURITY)) { - state = 20; /* NTLMSSP */ - break; - } - - request = new SmbComSessionSetupAndX( this, andx, auth ); - response = new SmbComSessionSetupAndXResponse( andxResponse ); + try { + transport.connect(); - /* 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 { - byte[] signingKey = auth.getSigningKey(transport.server.encryptionKey); - request.digest = new SigningDigest(signingKey, false); + /* + * Session Setup And X Request / Response + */ + + if( transport.log.level >= 4 ) + transport.log.println( "sessionSetup: accountName=" + auth.username + ",primaryDomain=" + auth.domain ); + + /* We explicitly set uid to 0 here to prevent a new + * SMB_COM_SESSION_SETUP_ANDX from having it's uid set to an + * old value when the session is re-established. Otherwise a + * "The parameter is incorrect" error can occur. + */ + uid = 0; + + do { + switch (state) { + case 10: /* NTLM */ + if (auth != NtlmPasswordAuthentication.ANONYMOUS && + transport.hasCapability(SmbConstants.CAP_EXTENDED_SECURITY)) { + state = 20; /* NTLMSSP */ + break; } - } - - request.auth = auth; - - try { - transport.send( request, response ); - } catch (SmbAuthException sae) { - throw sae; - } catch (SmbException se) { - ex = se; - } - - if( response.isLoggedInAsGuest && - "GUEST".equalsIgnoreCase( auth.username ) == false && - transport.server.security != SmbConstants.SECURITY_SHARE) { - throw new SmbAuthException( NtStatus.NT_STATUS_LOGON_FAILURE ); - } - - if (ex != null) - throw ex; - - uid = response.uid; - - if( request.digest != null ) { - /* success - install the signing digest */ - transport.digest = request.digest; - } - - sessionSetup = true; - state = 0; - - break; - case 20: - if (nctx == null) { - boolean doSigning = (transport.flags2 & ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES) != 0; - nctx = new NtlmContext(auth, doSigning); - } - - if (nctx.isEstablished()) { - sessionSetup = true; - state = 0; - break; - } - - try { - token = nctx.initSecContext(token, 0, token.length); - } catch (SmbException se) { - /* We must close the transport or the server will be expecting a - * Type3Message. Otherwise, when we send a Type1Message it will return - * "Invalid parameter". + + request = new SmbComSessionSetupAndX( this, andx, auth ); + 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. */ - try { transport.disconnect(true); } catch (IOException ioe) {} - uid = 0; - throw se; - } - - if (token != null) { - request = new SmbComSessionSetupAndX(this, null, token); - response = new SmbComSessionSetupAndXResponse(null); - if (transport.isSignatureSetupRequired( auth )) { - byte[] signingKey = nctx.getSigningKey(); - if (signingKey != null) - request.digest = new SigningDigest(signingKey, true); + if( auth.hashesExternal && NtlmPasswordAuthentication.DEFAULT_PASSWORD != NtlmPasswordAuthentication.BLANK ) { + /* preauthentication + */ + transport.getSmbSession( NtlmPasswordAuthentication.DEFAULT ).getSmbTree( LOGON_SHARE, null ).treeConnect( null, null ); + } else { + byte[] signingKey = auth.getSigningKey(transport.server.encryptionKey); + request.digest = new SigningDigest(signingKey, false); + } } - - request.uid = uid; - uid = 0; - + + request.auth = auth; + try { transport.send( request, response ); } catch (SmbAuthException sae) { throw sae; } catch (SmbException se) { ex = se; - /* Apparently once a successfull NTLMSSP login occurs, the - * server will return "Access denied" even if a logoff is - * sent. Unfortunately calling disconnect() doesn't always - * actually shutdown the connection before other threads - * have committed themselves (e.g. InterruptTest example). - */ - try { transport.disconnect(true); } catch (Exception e) {} } - + if( response.isLoggedInAsGuest && - "GUEST".equalsIgnoreCase( auth.username ) == false) { + "GUEST".equalsIgnoreCase( auth.username ) == false && + transport.server.security != SmbConstants.SECURITY_SHARE) { throw new SmbAuthException( NtStatus.NT_STATUS_LOGON_FAILURE ); } - + if (ex != null) throw ex; - + uid = response.uid; - - if (request.digest != null) { + + if( request.digest != null ) { /* success - install the signing digest */ transport.digest = request.digest; } + + connectionState = 2; - token = response.blob; - } + state = 0; + + break; + case 20: + if (nctx == null) { + boolean doSigning = (transport.flags2 & ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES) != 0; + nctx = new NtlmContext(auth, doSigning); + } + + if (SmbTransport.log.level >= 4) + SmbTransport.log.println(nctx); + + if (nctx.isEstablished()) { - break; - default: - throw new SmbException("Unexpected session setup state: " + state); - } - } while (state != 0); + connectionState = 2; + + state = 0; + break; + } + + try { + token = nctx.initSecContext(token, 0, token.length); + } catch (SmbException se) { + /* We must close the transport or the server will be expecting a + * Type3Message. Otherwise, when we send a Type1Message it will return + * "Invalid parameter". + */ + try { transport.disconnect(true); } catch (IOException ioe) {} + uid = 0; + throw se; + } + + if (token != null) { + request = new SmbComSessionSetupAndX(this, null, token); + response = new SmbComSessionSetupAndXResponse(null); + + if (transport.isSignatureSetupRequired( auth )) { + byte[] signingKey = nctx.getSigningKey(); + if (signingKey != null) + request.digest = new SigningDigest(signingKey, true); + } + + request.uid = uid; + uid = 0; + + try { + transport.send( request, response ); + } catch (SmbAuthException sae) { + throw sae; + } catch (SmbException se) { + ex = se; + /* Apparently once a successfull NTLMSSP login occurs, the + * server will return "Access denied" even if a logoff is + * sent. Unfortunately calling disconnect() doesn't always + * actually shutdown the connection before other threads + * have committed themselves (e.g. InterruptTest example). + */ + try { transport.disconnect(true); } catch (Exception e) {} + } + + if( response.isLoggedInAsGuest && + "GUEST".equalsIgnoreCase( auth.username ) == false) { + throw new SmbAuthException( NtStatus.NT_STATUS_LOGON_FAILURE ); + } + + if (ex != null) + throw ex; + + uid = response.uid; + + if (request.digest != null) { + /* success - install the signing digest */ + transport.digest = request.digest; + } + + token = response.blob; + } + + break; + default: + throw new SmbException("Unexpected session setup state: " + state); + } + } while (state != 0); + } catch (SmbException se) { + logoff(true); + connectionState = 0; + throw se; + } finally { + transport.notifyAll(); + } } } void logoff( boolean inError ) { -synchronized( transport() ) { - if( sessionSetup == false ) { +synchronized (transport()) { + + if (connectionState != 2) // not-connected return; - } + connectionState = 3; // disconnecting for( Enumeration e = trees.elements(); e.hasMoreElements(); ) { SmbTree t = (SmbTree)e.nextElement(); @@ -410,7 +438,7 @@ synchronized( transport() ) { /* * Logoff And X Request / Response */ - + SmbComLogoffAndX request = new SmbComLogoffAndX( null ); request.uid = uid; try { @@ -420,13 +448,14 @@ synchronized( transport() ) { uid = 0; } - sessionSetup = false; + connectionState = 0; + transport.notifyAll(); } } public String toString() { return "SmbSession[accountName=" + auth.username + ",primaryDomain=" + auth.domain + ",uid=" + uid + - ",sessionSetup=" + sessionSetup + "]"; + ",connectionState=" + connectionState + "]"; } } diff --git a/src/jcifs/smb/SmbTransport.java b/src/jcifs/smb/SmbTransport.java index 342ac47..42c0982 100644 --- a/src/jcifs/smb/SmbTransport.java +++ b/src/jcifs/smb/SmbTransport.java @@ -92,7 +92,7 @@ public class SmbTransport extends Transport implements SmbConstants { int port, mid; OutputStream out; InputStream in; - byte[] sbuf = new byte[255]; /* small local buffer */ + byte[] sbuf = new byte[512]; /* small local buffer */ SmbComBlankResponse key = new SmbComBlankResponse(); long sessionExpiration = System.currentTimeMillis() + SO_TIMEOUT; LinkedList referrals = new LinkedList(); @@ -470,10 +470,13 @@ public class SmbTransport extends Transport implements SmbConstants { /* WordCount thru dataOffset always 27 */ readn( in, BUF, 4 + off, 27 ); off += 27; resp.decode( BUF, 4 ); - if (r.dataLength > 0) { - readn( in, BUF, 4 + off, r.dataOffset - off); /* pad */ + /* EMC can send pad w/o data */ + int pad = r.dataOffset - off; + if (r.byteCount > 0 && pad > 0 && pad < 4) + readn( in, BUF, 4 + off, pad); + + if (r.dataLength > 0) readn( in, r.b, r.off, r.dataLength ); /* read direct */ - } } else { readn( in, BUF, 4 + 32, size - 32 ); resp.decode( BUF, 4 ); @@ -586,7 +589,7 @@ public class SmbTransport extends Transport implements SmbConstants { makeKey( req ); } - synchronized (response_map) { + synchronized (this) { response.received = false; resp.isReceived = false; try { @@ -607,7 +610,7 @@ public class SmbTransport extends Transport implements SmbConstants { long timeout = RESPONSE_TIMEOUT; resp.expiration = System.currentTimeMillis() + timeout; while( resp.hasMoreElements() ) { - response_map.wait( timeout ); + wait( timeout ); timeout = resp.expiration - System.currentTimeMillis(); if (timeout <= 0) { throw new TransportException( this + @@ -635,8 +638,6 @@ public class SmbTransport extends Transport implements SmbConstants { } } catch( SmbException se ) { throw se; - } catch( InterruptedException ie ) { - throw new SmbException( ie.getMessage(), ie ); } catch( IOException ioe ) { throw new SmbException( ioe.getMessage(), ioe ); } diff --git a/src/jcifs/smb/SmbTree.java b/src/jcifs/smb/SmbTree.java index 7ecabb5..3a65248 100644 --- a/src/jcifs/smb/SmbTree.java +++ b/src/jcifs/smb/SmbTree.java @@ -28,14 +28,20 @@ class SmbTree { private static int tree_conn_counter; - private int tid; + /* 0 - not connected + * 1 - connecting + * 2 - connected + * 3 - disconnecting + */ + int connectionState; + int tid; String share; String service = "?????"; String service0; SmbSession session; - boolean treeConnected, inDfs, inDomainDfs; - int tree_num; + boolean inDfs, inDomainDfs; + int tree_num; // used by SmbFile.isOpen SmbTree( SmbSession session, String share, String service ) { this.session = session; @@ -44,6 +50,7 @@ class SmbTree { this.service = service; } this.service0 = this.service; + this.connectionState = 0; } boolean matches( String share, String service ) { @@ -60,6 +67,7 @@ class SmbTree { } void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { +synchronized (session.transport()) { if( response != null ) { response.received = false; } @@ -120,57 +128,74 @@ class SmbTree { } throw se; } +} } void treeConnect( ServerMessageBlock andx, ServerMessageBlock andxResponse ) throws SmbException { - String unc; - SmbTransport transport = session.transport(); -synchronized(transport.setupDiscoLock) { -synchronized(transport) { +synchronized (session.transport()) { + String unc; - if (treeConnected) { - return; + while (connectionState != 0) { + if (connectionState == 2 || connectionState == 3) // connected or disconnecting + return; + try { + session.transport.wait(); + } catch (InterruptedException ie) { + throw new SmbException(ie.getMessage(), ie); + } } + connectionState = 1; // trying ... - /* The hostname to use in the path is only known for - * sure if the NetBIOS session has been successfully - * established. - */ - - session.transport.connect(); - - unc = "\\\\" + session.transport.tconHostName + '\\' + share; - - /* IBM iSeries doesn't like specifying a service. Always reset - * the service to whatever was determined in the constructor. - */ - service = service0; - - /* - * Tree Connect And X Request / Response - */ - - if( session.transport.log.level >= 4 ) - session.transport.log.println( "treeConnect: unc=" + unc + ",service=" + service ); - - SmbComTreeConnectAndXResponse response = - new SmbComTreeConnectAndXResponse( andxResponse ); - SmbComTreeConnectAndX request = - new SmbComTreeConnectAndX( session, unc, service, andx ); - session.send( request, response ); - - tid = response.tid; - service = response.service; - inDfs = response.shareIsInDfs; - treeConnected = true; - tree_num = tree_conn_counter++; -} + try { + /* The hostname to use in the path is only known for + * sure if the NetBIOS session has been successfully + * established. + */ + + session.transport.connect(); + + unc = "\\\\" + session.transport.tconHostName + '\\' + share; + + /* IBM iSeries doesn't like specifying a service. Always reset + * the service to whatever was determined in the constructor. + */ + service = service0; + + /* + * Tree Connect And X Request / Response + */ + + if( session.transport.log.level >= 4 ) + session.transport.log.println( "treeConnect: unc=" + unc + ",service=" + service ); + + SmbComTreeConnectAndXResponse response = + new SmbComTreeConnectAndXResponse( andxResponse ); + SmbComTreeConnectAndX request = + new SmbComTreeConnectAndX( session, unc, service, andx ); + session.send( request, response ); + + tid = response.tid; + service = response.service; + inDfs = response.shareIsInDfs; + tree_num = tree_conn_counter++; + + connectionState = 2; // connected + } catch (SmbException se) { + treeDisconnect(true); + connectionState = 0; + throw se; + } } } void treeDisconnect( boolean inError ) { -synchronized( session.transport ) { - if (treeConnected && !inError && tid != 0) { +synchronized (session.transport()) { + + if (connectionState != 2) // not-connected + return; + connectionState = 3; // disconnecting + + if (!inError && tid != 0) { try { send( new SmbComTreeDisconnect(), null ); } catch( SmbException se ) { @@ -179,9 +204,12 @@ synchronized( session.transport ) { } } } - treeConnected = false; inDfs = false; inDomainDfs = false; + + connectionState = 0; + + session.transport.notifyAll(); } } @@ -191,6 +219,6 @@ synchronized( session.transport ) { ",tid=" + tid + ",inDfs=" + inDfs + ",inDomainDfs=" + inDomainDfs + - ",treeConnected=" + treeConnected + "]"; + ",connectionState=" + connectionState + "]"; } } diff --git a/src/jcifs/smb/TestLocking.java b/src/jcifs/smb/TestLocking.java new file mode 100644 index 0000000..ca2c02b --- /dev/null +++ b/src/jcifs/smb/TestLocking.java @@ -0,0 +1,124 @@ +package jcifs.smb; + +import java.io.InputStream; +import java.io.IOException; + +public class TestLocking implements Runnable +{ + + int numThreads = 1; + int numIter = 1; + long delay = 100; + String url = null; + int numComplete = 0; + long ltime = 0L; + + public void run() + { + try { + SmbFile f = new SmbFile(url); + SmbFile d = new SmbFile(f.getParent()); + byte[] buf = new byte[1024]; + + for (int ii = 0; ii < numIter; ii++) { + + synchronized (this) { + ltime = System.currentTimeMillis(); + wait(); + } + + try { + double r = Math.random(); + if (r < 0.333) { + f.exists(); +// System.out.print('e'); + } else if (r < 0.667) { + d.listFiles(); +// System.out.print('l'); + } else if (r < 1.0) { + InputStream in = f.getInputStream(); + while (in.read(buf) > 0) { +// System.out.print('r'); + } + in.close(); + } + } catch (IOException ioe) { + System.err.println(ioe.getMessage()); +//ioe.printStackTrace(System.err); + } + + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + numComplete++; + } + } + + public static void main(String[] args) throws Exception + { + if (args.length < 1) { + System.err.println("usage: TestLocking [-t ] [-i ] [-d ] url"); + System.exit(1); + } + + TestLocking t = new TestLocking(); + t.ltime = System.currentTimeMillis(); + + for (int ai = 0; ai < args.length; ai++) { + if (args[ai].equals("-t")) { + ai++; + t.numThreads = Integer.parseInt(args[ai]); + } else if (args[ai].equals("-i")) { + ai++; + t.numIter = Integer.parseInt(args[ai]); + } else if (args[ai].equals("-d")) { + ai++; + t.delay = Long.parseLong(args[ai]); + } else { + t.url = args[ai]; + } + } + + Thread[] threads = new Thread[t.numThreads]; + int ti; + + for (ti = 0; ti < t.numThreads; ti++) { + threads[ti] = new Thread(t); + System.out.print(threads[ti].getName()); + threads[ti].start(); + } + + while (t.numComplete < t.numThreads) { + long delay; + + do { + delay = 2L; + + synchronized (t) { + long expire = t.ltime + t.delay; + long ctime = System.currentTimeMillis(); + + if (expire > ctime) + delay = expire - ctime; + } + +if (delay > 2) +System.out.println("delay=" + delay); + Thread.sleep(delay); + } while (delay > 2); + + synchronized (t) { + t.notifyAll(); + } +//System.out.println("numComplete=" + t.numComplete + ",numThreads=" + t.numThreads); + } + + for (ti = 0; ti < t.numThreads; ti++) { + threads[ti].join(); + System.out.print(threads[ti].getName()); + } + + System.out.println(); + } +} diff --git a/src/jcifs/util/transport/Transport.java b/src/jcifs/util/transport/Transport.java index e244384..56eec39 100644 --- a/src/jcifs/util/transport/Transport.java +++ b/src/jcifs/util/transport/Transport.java @@ -57,12 +57,9 @@ public abstract class Transport implements Runnable { protected abstract void doRecv( Response response ) throws IOException; protected abstract void doSkip() throws IOException; - public Object setupDiscoLock = new Object(); - - public void sendrecv( Request request, + public synchronized void sendrecv( Request request, Response response, long timeout ) throws IOException { - synchronized (response_map) { makeKey( request ); response.isReceived = false; try { @@ -70,7 +67,7 @@ public abstract class Transport implements Runnable { doSend( request ); response.expiration = System.currentTimeMillis() + timeout; while (!response.isReceived) { - response_map.wait( timeout ); + wait( timeout ); timeout = response.expiration - System.currentTimeMillis(); if (timeout <= 0) { throw new TransportException( name + @@ -92,7 +89,6 @@ public abstract class Transport implements Runnable { } finally { response_map.remove( request ); } - } } private void loop() { while( thread == Thread.currentThread() ) { @@ -100,7 +96,7 @@ public abstract class Transport implements Runnable { Request key = peekKey(); if (key == null) throw new IOException( "end of stream" ); - synchronized (response_map) { + synchronized (this) { Response response = (Response)response_map.get( key ); if (response == null) { if (log.level >= 4) @@ -109,7 +105,7 @@ public abstract class Transport implements Runnable { } else { doRecv( response ); response.isReceived = true; - response_map.notifyAll(); + notifyAll(); } } } catch( Exception ex ) { @@ -201,31 +197,27 @@ public abstract class Transport implements Runnable { } } } - public void disconnect( boolean hard ) throws IOException { - synchronized(setupDiscoLock) { - synchronized(this) { - switch (state) { - case 0: /* not connected - just return */ - return; - case 2: - hard = true; - case 3: /* connected - go ahead and disconnect */ - if (response_map.size() != 0 && !hard) { - break; /* outstanding requests */ - } - doDisconnect( hard ); - case 4: /* in error - reset the transport */ - thread = null; - state = 0; - break; - default: - if (log.level >= 1) - log.println("Invalid state: " + state); - thread = null; - state = 0; - break; + public synchronized void disconnect( boolean hard ) throws IOException { + switch (state) { + case 0: /* not connected - just return */ + return; + case 2: + hard = true; + case 3: /* connected - go ahead and disconnect */ + if (response_map.size() != 0 && !hard) { + break; /* outstanding requests */ } - } + doDisconnect( hard ); + case 4: /* in error - reset the transport */ + thread = null; + state = 0; + break; + default: + if (log.level >= 1) + log.println("Invalid state: " + state); + thread = null; + state = 0; + break; } } public void run() {