From c503e2bc823f4be754c862c292d76ffb0227db82 Mon Sep 17 00:00:00 2001 From: Felix Schumacher Date: Wed, 6 Aug 2008 16:05:09 +0200 Subject: [PATCH] jcifs-0-7.3 from tgz Wed Feb 12 01:23:02 EST 2003 A security issue regarding the SmbSession.logon() method used by NTLM HTTP Authentication has been fixed and a modification has been made to trigger MSIE to redisplay the Network Password dialog repeatedly until correct credentials are supplied. The change was made in the core jcifs.smb package however so test this in your dev environments. Wed Feb 5 00:41:32 EST 2003 The jcifs-0.7.0 and 0.7.1 releases will incorrectly throw an ArrayIndexOutOfBounds exception if a write of 1501 to 1504 is performed. This release fixes that bug. You may also set jcifs.smb.client.snd_buf_size = 1300 as a temporary work-around. It is also now possible to specify a "ShareAccess" with SmbFileOutputStream and SmbFile to restrict other processes from accessing files jCIFS opens. Also, SmbFileOutputStream now supports writing files larger than 4GB. Wed Jan 15 22:34:14 EST 2003 jcifs-0.7.1 released Three bugs have been fixed regarding filenames with '#' signs in them, the getInputStream(), getLastModified(), getDate(), and getContentLength() methods of the URLConnection implementation, and isExists() incorrectly returning false. Thu Jan 9 00:06:23 EST 2003 jcifs-0.7.0 released This is the 0.7.0 release of jCIFS, the Java SMB client. There is new functionality specifically targeting Web applications as well as some critical SMB URL fixes and feature improvements: o The new jcifs.http package is very handy when building Web applications that need to integrate with MS corporate intranets. Adding a hyperlink to a document on a network drive is easy with Network Explorer (pictured right) and will transparently negotiate credentials with MSIE to browse SMB resources (really, no password dialog necessary). This package also boasts an NTLM HTTP Authentication servlet Filter for authenticating MSIE clients. These are useful features because many of the tasks surrounding user management now fall back to computer support and HR. It is not necessary to add and remove users as they join and leave the company. Perhaps most important from the user's perspective; they do not need to enter a username or password if their workstation is a member of an NTLM domain. The password hashes generated when they logged on to their workstation will be negotiated during the initial request for a session, passed through jCIFS, and validated against a PDC or BDC. This also makes the user's domain, username, and password available for managing session information, profiles, preferences, etc. o The functionality used to authenticate and manage arbitrary creadentials has been exposed in the SmbSession and NtlmPasswordAuthentication classes. This permits NTLM password authentication to be integrated into applications without requiring Microsoft components or JNI. o With the introduction of the jcifs.encoding property the client is now truely internationalized. It has been used successfully on OS/390 with native EBCDIC character encoding. See the Sun JRE documentation for a list of supported encodings. o The URL issues remaining in the 0.6 series have been fixed in 0.7 by converting all SMB URL handling internally to use the java.net.URL class (Note: directories must now have a trailing slash and Java 1.3 is required). Also a deadlock in the name service code was identified and fixed (repaired in 0.6.8 as well). o A copyTo() method has been added to SmbFile that is very fast at copying large directories across hosts. o There have been numerous other changes including the mkdirs() and getType() methods, plain text password support (disabled by default), the available() method and close() fix for Named Pipes, reading files larger than 4 GB, the NtlmAuthenticator class, and more. All documentation has been completely reviewed and updated. --- CHANGES.txt | 792 +++++++++++ README.txt | 467 +++---- build.sh | 3 +- build.xml | 37 +- examples/AllocInfo.java | 11 + examples/Append.java | 21 + examples/AuthDialog.java | 64 - examples/AuthListFiles.java | 57 + examples/Break.java | 29 + examples/CallNamedPipe.java | 18 - examples/CifsTime.java | 18 - examples/CopyTo.java | 12 + examples/CopyTo5.java | 34 + examples/CrawlerBench.java | 116 -- examples/CreateFile.java | 18 - examples/Delete.java | 32 +- examples/Exists.java | 18 - examples/FileOps.java | 30 +- examples/Format.java | 562 ++++++++ examples/Get.java | 24 +- examples/GetDate.java | 18 - examples/GetType.java | 54 + examples/GetURL.java | 20 +- examples/GrowWrite.java | 30 + examples/Interleave.java | 18 - examples/IsDir.java | 21 +- examples/Length.java | 18 - examples/List.java | 30 +- examples/ListFiles.java | 22 + examples/ListTypes.java | 44 + examples/LogTest.java | 18 - examples/LogonTest.java | 17 + examples/Mkdir.java | 26 +- examples/NodeStatus.java | 11 + examples/NtlmHttpAuthExample.java | 32 + examples/OpenExclusive.java | 20 + examples/PeekNamedPipe.java | 64 + examples/PipeTalk.java | 18 - examples/Put.java | 20 +- examples/Query.java | 18 - examples/README.txt | 2 - examples/RenameTo.java | 18 - examples/SlowRead.java | 18 - examples/SlowWrite.java | 18 - examples/SmbCrawler.java | 27 +- examples/SmbShell.java | 121 +- examples/T2Crawler.java | 128 ++ examples/TestFile.java | 34 - examples/TestSmbFile.java | 50 - examples/TestSmbURL.java | 164 +++ examples/TestUnicode.java | 60 + examples/ThreadedNbtQuery.java | 38 + examples/ThreadedSmbCrawler.java | 65 +- examples/ThreadedUniQuery.java | 50 + examples/Torture1.java | 102 ++ examples/Torture2.java | 92 ++ examples/TortureTest3.java | 86 -- examples/TortureTest4.java | 88 -- examples/TortureTest5.java | 22 +- examples/TransactNamedPipe.java | 18 - examples/URLTest.java | 31 + examples/VerifyIO.java | 76 + examples/VerifyReads.java | 78 ++ examples/data | 17 + examples/jcifs.prp | 15 +- examples/ntlm.prp | 38 + examples/pipes/callnp.c | 2 +- examples/pipes/createf.c | 2 +- examples/pipes/createnp.c | 2 +- examples/torture.prp | 9 + examples/torture2.prp | 7 + examples/tt4.prp | 51 - examples/zzz.java | 44 - src/jcifs/Config.java | 52 +- src/jcifs/UniAddress.java | 136 +- src/jcifs/http/NetworkExplorer.java | 443 ++++++ src/jcifs/http/NtlmHttpFilter.java | 125 ++ .../NtlmHttpServletRequest.java} | 29 +- src/jcifs/http/NtlmServlet.java | 112 ++ src/jcifs/http/NtlmSsp.java | 131 ++ src/jcifs/http/ne.css | 68 + src/jcifs/netbios/Lmhosts.java | 2 +- src/jcifs/netbios/Log.java | 2 +- src/jcifs/netbios/Name.java | 74 +- src/jcifs/netbios/NameQueryRequest.java | 2 +- src/jcifs/netbios/NameQueryResponse.java | 2 +- src/jcifs/netbios/NameServiceClient.java | 11 +- src/jcifs/netbios/NameServicePacket.java | 2 +- src/jcifs/netbios/NbtAddress.java | 87 +- src/jcifs/netbios/NbtException.java | 2 +- src/jcifs/netbios/NbtSocket.java | 2 +- src/jcifs/netbios/NodeStatusRequest.java | 4 +- src/jcifs/netbios/NodeStatusResponse.java | 100 +- src/jcifs/netbios/SessionRequestPacket.java | 2 +- .../netbios/SessionRetargetResponsePacket.java | 2 +- src/jcifs/netbios/SessionServicePacket.java | 2 +- src/jcifs/netbios/SocketInputStream.java | 2 +- src/jcifs/netbios/SocketOutputStream.java | 6 +- .../{util/AuthHandler.java => smb/AllocInfo.java} | 10 +- src/jcifs/smb/AndXServerMessageBlock.java | 2 +- src/jcifs/smb/BufferCache.java | 2 +- src/jcifs/smb/Handler.java | 83 +- src/jcifs/smb/Info.java | 2 +- src/jcifs/smb/Log.java | 2 +- src/jcifs/smb/NetServerEnum2.java | 19 +- src/jcifs/smb/NetServerEnum2Response.java | 10 +- src/jcifs/smb/NetShareEnum.java | 19 +- src/jcifs/smb/NetShareEnumResponse.java | 10 +- src/jcifs/smb/NtlmAuthenticator.java | 77 ++ src/jcifs/smb/NtlmPasswordAuthentication.java | 271 ++++ src/jcifs/smb/ServerMessageBlock.java | 114 +- src/jcifs/smb/SmbAuthException.java | 9 +- src/jcifs/smb/SmbComBlankResponse.java | 2 +- src/jcifs/smb/SmbComCheckDirectory.jav | 2 +- src/jcifs/smb/SmbComClose.java | 13 +- src/jcifs/smb/SmbComCopy.jav | 68 - src/jcifs/smb/SmbComCopyResponse.jav | 52 - src/jcifs/smb/SmbComCreateDirectory.java | 2 +- src/jcifs/smb/SmbComDelete.java | 2 +- src/jcifs/smb/SmbComDeleteDirectory.java | 2 +- src/jcifs/smb/SmbComEcho.jav | 2 +- src/jcifs/smb/SmbComEchoResponse.jav | 2 +- src/jcifs/smb/SmbComFindClose2.java | 2 +- src/jcifs/smb/SmbComLogoffAndX.java | 2 +- src/jcifs/smb/SmbComMove.jav | 2 +- src/jcifs/smb/SmbComMoveResponse.jav | 2 +- src/jcifs/smb/SmbComNTCreateAndX.java | 12 +- src/jcifs/smb/SmbComNTCreateAndXResponse.java | 2 +- src/jcifs/smb/SmbComNegotiate.java | 14 +- src/jcifs/smb/SmbComNegotiateResponse.java | 49 +- src/jcifs/smb/SmbComOpenAndX.java | 2 +- src/jcifs/smb/SmbComOpenAndXResponse.java | 2 +- src/jcifs/smb/SmbComQueryInformation.java | 2 +- src/jcifs/smb/SmbComQueryInformationResponse.java | 2 +- src/jcifs/smb/SmbComReadAndX.java | 20 +- src/jcifs/smb/SmbComReadAndXResponse.java | 8 +- src/jcifs/smb/SmbComRename.java | 2 +- src/jcifs/smb/SmbComSessionSetupAndX.java | 34 +- src/jcifs/smb/SmbComSessionSetupAndXResponse.java | 31 +- src/jcifs/smb/SmbComTransaction.java | 3 +- src/jcifs/smb/SmbComTransactionResponse.java | 16 +- src/jcifs/smb/SmbComTreeConnectAndX.java | 42 +- src/jcifs/smb/SmbComTreeConnectAndXResponse.java | 9 +- src/jcifs/smb/SmbComTreeDisconnect.java | 2 +- src/jcifs/smb/SmbComWriteAndX.java | 45 +- src/jcifs/smb/SmbComWriteAndXResponse.java | 2 +- src/jcifs/smb/SmbException.java | 73 +- src/jcifs/smb/SmbFile.java | 1461 +++++++++++++++----- src/jcifs/smb/SmbFileInputStream.java | 50 +- src/jcifs/smb/SmbFileOutputStream.java | 38 +- src/jcifs/smb/SmbNamedPipe.java | 22 +- src/jcifs/smb/SmbSession.java | 139 +- src/jcifs/smb/SmbTransport.java | 164 ++- src/jcifs/smb/SmbTree.java | 63 +- src/jcifs/smb/SmbURL.java | 219 --- src/jcifs/smb/SmbURLConnection.java | 132 -- src/jcifs/smb/Trans2FindFirst2.java | 2 +- src/jcifs/smb/Trans2FindFirst2Response.java | 68 +- src/jcifs/smb/Trans2FindNext2.java | 2 +- ...formation.jav => Trans2QueryFSInformation.java} | 6 +- src/jcifs/smb/Trans2QueryFSInformationResponse.jav | 96 -- .../smb/Trans2QueryFSInformationResponse.java | 136 ++ src/jcifs/smb/Trans2QueryPathInformation.java | 2 +- .../smb/Trans2QueryPathInformationResponse.java | 2 +- src/jcifs/smb/TransCallNamedPipe.java | 2 +- src/jcifs/smb/TransCallNamedPipeResponse.java | 2 +- src/jcifs/smb/TransPeekNamedPipe.java | 63 + src/jcifs/smb/TransPeekNamedPipeResponse.java | 59 + src/jcifs/smb/TransTransactNamedPipe.java | 2 +- src/jcifs/smb/TransTransactNamedPipeResponse.java | 2 +- src/jcifs/smb/TransWaitNamedPipe.java | 2 +- src/jcifs/smb/TransWaitNamedPipeResponse.java | 2 +- src/jcifs/smb/TransactNamedPipeInputStream.java | 18 +- src/jcifs/smb/TransactNamedPipeOutputStream.java | 11 +- src/jcifs/util/Base64.java | 549 ++++++++ src/jcifs/util/Config.java | 2 +- src/jcifs/util/Log.java | 72 +- src/jcifs/util/LogWriter.java | 14 +- src/jcifs/util/MimeMap.java | 123 ++ src/jcifs/util/PropertiesTree.java | 10 +- src/jcifs/util/URLDecoder.jav | 81 ++ src/jcifs/util/mime.map | 94 ++ 182 files changed, 7757 insertions(+), 2965 deletions(-) create mode 100644 CHANGES.txt create mode 100644 examples/AllocInfo.java create mode 100644 examples/Append.java delete mode 100644 examples/AuthDialog.java create mode 100644 examples/AuthListFiles.java create mode 100644 examples/Break.java create mode 100644 examples/CopyTo.java create mode 100644 examples/CopyTo5.java delete mode 100644 examples/CrawlerBench.java create mode 100644 examples/Format.java create mode 100644 examples/GetType.java create mode 100644 examples/GrowWrite.java create mode 100644 examples/ListFiles.java create mode 100644 examples/ListTypes.java create mode 100644 examples/LogonTest.java create mode 100644 examples/NodeStatus.java create mode 100644 examples/NtlmHttpAuthExample.java create mode 100644 examples/OpenExclusive.java create mode 100644 examples/PeekNamedPipe.java delete mode 100644 examples/README.txt create mode 100644 examples/T2Crawler.java delete mode 100644 examples/TestFile.java delete mode 100644 examples/TestSmbFile.java create mode 100644 examples/TestSmbURL.java create mode 100644 examples/TestUnicode.java create mode 100644 examples/ThreadedNbtQuery.java create mode 100644 examples/ThreadedUniQuery.java create mode 100644 examples/Torture1.java create mode 100644 examples/Torture2.java delete mode 100644 examples/TortureTest3.java delete mode 100644 examples/TortureTest4.java create mode 100644 examples/URLTest.java create mode 100644 examples/VerifyIO.java create mode 100644 examples/VerifyReads.java create mode 100644 examples/data create mode 100644 examples/ntlm.prp create mode 100644 examples/torture.prp create mode 100644 examples/torture2.prp delete mode 100644 examples/tt4.prp delete mode 100644 examples/zzz.java create mode 100644 src/jcifs/http/NetworkExplorer.java create mode 100644 src/jcifs/http/NtlmHttpFilter.java rename src/jcifs/{util/AuthInfo.java => http/NtlmHttpServletRequest.java} (55%) create mode 100644 src/jcifs/http/NtlmServlet.java create mode 100644 src/jcifs/http/NtlmSsp.java create mode 100644 src/jcifs/http/ne.css rename src/jcifs/{util/AuthHandler.java => smb/AllocInfo.java} (82%) create mode 100644 src/jcifs/smb/NtlmAuthenticator.java create mode 100644 src/jcifs/smb/NtlmPasswordAuthentication.java delete mode 100644 src/jcifs/smb/SmbComCopy.jav delete mode 100644 src/jcifs/smb/SmbComCopyResponse.jav delete mode 100644 src/jcifs/smb/SmbURL.java delete mode 100644 src/jcifs/smb/SmbURLConnection.java rename src/jcifs/smb/{Trans2QueryFSInformation.jav => Trans2QueryFSInformation.java} (92%) delete mode 100644 src/jcifs/smb/Trans2QueryFSInformationResponse.jav create mode 100644 src/jcifs/smb/Trans2QueryFSInformationResponse.java create mode 100644 src/jcifs/smb/TransPeekNamedPipe.java create mode 100644 src/jcifs/smb/TransPeekNamedPipeResponse.java create mode 100644 src/jcifs/util/Base64.java create mode 100644 src/jcifs/util/MimeMap.java create mode 100644 src/jcifs/util/URLDecoder.jav create mode 100644 src/jcifs/util/mime.map diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..8d50af1 --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,792 @@ +Wed Feb 12 01:23:02 EST 2003 + +From the beginning jCIFS identified SmbSessions uniquely by +domain\username. This meant that once a session was established it could be +shared by another requestor even if they supplied an incorrect password. +This was done for reasons that strangely enough had to do with SMB +chaining. However with the introduction of the http package it is now +common to use jCIFS to authenticate web clients from a central jCIFS +instance. This introduces a security flaw because there would be a brief +window of opportunity after a user logs in during which an impostor could +log in as that user with a simple change to their MSIE security settings. +This problem has been fixed. Another related issue has also been fixed. If +the NtlmHttpFilter or NetworkExplorer servlet is supplied with bad +credentials the behavior was to throw an SmbAuthException up through the +container. Instead these classes will respond with the standard +Authentication: NTLM response triggering the password dialog to be +displayed until correct credentials are displayed. + + +Wed Feb 5 00:41:32 EST 2003 + +There was a bug introduced in jcifs-0.7.0 when the default +jcifs.smb.client.snd_buf_size was changed to 5000 from 1300. Writes of size +1501 to 1504 will trigger an ArrayIndexOutOfBounds exception. Two feature +enhancements have also been added. SmbFileOutputStream will now support +file offsets larger than 4GB. Second, the FILE_NO_SHARE, FILE_SHARE_READ, +FILE_SHARE_WRITE, and FILE_SHARE_DELETE constants have been exposed in +SmbFile. They may be used to construct a shareAccess parameter for use with +SmbFileOutputStream and SmbFile to control whether or not other processes +(or other jCIFS threads) can read, write, and/or delete the file while +jCIFS has it open. The default is (FILE_SHARE_READ | FILE_SHARE_WRITE | +FILE_SHARE_DELETE) which will permit other processes to have full access. +See examples/OpenExclusive and the SmbFileOutputStream API documentation. + +Wed Jan 15 22:34:14 EST 2003 + +jcifs-0.7.1 released + +Previously the '#' character was being interpreted by the URL parser as the +delimeter to the '#ref' component of a URL. This character will no longer +be treated as a delimeter permitting files with '#'s to be addressed with +SMB URLs. The getContentLength(), getDate(), getLastModified(), and +getInputStream() method were dropped when converting SmbFile to extend +URLConnection. They have been restored. Files returned by listFile() were +initialized in a state such that isExists() would return false (at least +until the attrExpirationPeriod expired). This has been corrected. + +Wed Jan 8 23:46:47 EST 2003 + +jcifs-0.7.0 released + +The default jcifs.smb.client.snd_buf_size has been changed from 1300 to +5000 and a bug regarding the resolveOrder mechanism was fixed. + +Mon Dec 30 20:18:54 EST 2002 + +jcifs-0.7.0b12 released + +A static Handler instance is now passed to URL constructors internally to +avoid provoking the deficient jcifs.protocol.pkgs Handler detection that is +causing the "unknown protocol: smb" exception with some application +servers. URL decoding has been enabled. Previously there was no clean way +to represent an '@' in a password in an SMB URL. Any character in the user +info component of the URL can be protected with a hex code escape like +'%40' for '@'. The calling name in the NetBIOS session establishment +message was incorrectly type 0x20. This has been changed to 0x00. A bug has +been fixed regarding the use of plain text passwords with Unicode (obscure +combination). A patch to the NTLM HTTP Filter has been applied to work +around a Weblogic 6.1 requrement. + +Fri Dec 20 15:59:50 EST 2002 + +jcifs-0.7.0b11 released + +A debugging statement was left uncommented in jcifs/UniAddress:173. When +listing 'smb://' or 'smb://workgroup/' URLs the following would be printed +to System.out: + + sem.count=2,q1x.ans=null,q20.ans=null + +Fri Dec 13 00:31:01 EST 2002 + +jcifs-0.7.0b10 released + +Please read the FAQ. The first and last questions are new. Some minor +changes have been made to jcifs.Config try and assist with the "unknown +protocol: smb" exceptions. Major kudos to Eric Glass for his help with +decipering the exact source of those errors. Hopefully users will read the +FAQ before posting this question over and over. An obscure deadlock could +be provoked by yanking the link while doing IO on a server. Thanks to +Matthew Tippett for reporting that. In the course of fixing it I also +re-fixed the name service deadlock discovered in 0.7.0b7 :~) Somehow that +change was lost and I think I knew it at the time but could remember what +the complete fix was. I'll have to release a 0.6.8 too because it's got it +too. It can easily be provoked by using examples/ThreadedSmbCrawler with +"smb://" and 10 threads on a big WAN. The jcifs.encoding property was not +being read correctly. + +Fri Nov 22 00:41:33 EST 2002 + +jcifs-0.7.0b9 released + +Java 1.3 is required. I thought the java.net.URL.set() variant that we +require was from 1.2 but not so. Oops. No turning back now. The 0.6.7 +client is pretty mature minus the 3 URL bugs. Use that with Java 1.1 and +up. + +Thanks to Chad for finding that calling getType() on a share returned in a +list from listFiles() was returning TYPE_FILESYSTEM. This has been fixed. + +And thanks to Uwe for finding that calling close() on NamedPipe input and +output streams had no effect. I believe this has been fixed but I have +limited testing capability. + +The NtlmAuthenticator has been reinplemented. Just call +NtlmAuthenticator.setDefault( this ) where this extends the abstact +NtlmAuthenticator class and implements the getNtlmPasswordAuthentication +method (like java.net.Authenticator) and your NtlmAuthenticator will be +called apon to return alternate credentials. + +The SmbShell example has been repaired completely and extends +NtlmAuthenticator which means when you cd around the WAN and hit a share +you're creds can't get through it will ask you: + + $ java -Djcifs.properties=../miallen.prp SmbShell smb://storage15/docs/ + docs/> cd smb://admin1-n/admin$/ + Access denied for smb://admin1-n/admin$/ + username: mydom\miallen + password: fretos + admin$/> + +Wed Nov 13 00:35:13 EST 2002 + +jcifs-0.7.0b8 released + +I forgot to mention that as of jcifs-0.7.0b4 jcifs now requires Java 2. +Recently there was confusion over this so we have added a check for Java 2 +in the static initializer of jcifs.Config. If the version string +startsWith( "1.1." ) an error message will be printed to System.err. The +getUncPath method was not including the share name. The ANY_HOSTS_NAME +member of NbtAddress was incorrectly using spaces rather than '\0' nulls. +Suprisingly this only affected nbtstat of Win98. A null pointer exception +was being generated by UniAddress. I was decrementing the semaphore too +agressively. + +I have not restored the Authenticator functionality. It requires a hook in +SmbTransport so I will wait for a little more stability (next release). + +Mon Nov 4 02:11:05 EST 2002 + +jcifs-0.7.0b7 released + +A deadlock was found and properly fixed in the name service code (stable +series is also affected; update to 0.6.7). Some URL handling was still not +quite right after the big java.net.URL conversion. Creating an SmbFile with +smb://workgroup/ + server/share/path/ would create +smb://workgroup/server/share/path/ which is illegal. This has been fixed +and will now correctly create smb://server/share/path/. + +Sun Oct 27 18:37:34 EST 2002 + +jcifs-0.7.0b6 released + +o Very pervasive character encoding changes have been made so that an + encoding (see new jcifs.encoding property) can be changed. This should, + for example, enable the client to operate in the EBCDIC OS/390 + environment. + +o The client is supposed to connect to IPC$ using anonymous credentials + (sometimes referred to as "null" credentials") if the supplied + credentials fail. The was broken in the 0.7 series however it has now + been repaired. + +o A concurrency issue in copyTo was identified an fixed. This was most + reproducible when issuing many simple requests (SMB_COM_CREATE_DIRECTORY, + SMB_COM_DELETE_DIRECTORY) in rapid succession (like when copying deep + trees) and could result in "Access Denied" SmbAuthExceptions. + +o Minor jcifs.http package cleanups + +Tue Oct 22 03:01:13 EDT 2002 + +jcifs-0.7.0b5 released + +Some issues with the NTLM HTTP Authentication Filter have been repaired. An +abstract NtlmServlet has been added to the jcifs.http package for pre-2.3 +servlet containers to use. The NTLM HTTP Authentication documentation has +been updated. The API documentation has been slightly updated. + +Wed Oct 16 23:10:20 EDT 2002 + +jcifs-0.7.0b4 released + + ! -= I M P O R T A N T =- ! + +URLs for directories now require a trailing '/'. This will break +existing code. To assit you the getName() method will return a name +with a trailing '/' if the SmbFile is a directory. Take care because +these illegal URLs will in some cases work. But if you try to list the +contents of a directory for example you will get an Exception: + +jcifs.smb.SmbException: smb://server/share/dir directory must end with '/' + at jcifs.smb.SmbFile.listFiles(SmbFile.java:1191) + at jcifs.smb.SmbFile.listFiles(SmbFile.java:1157) + ... + +There are three additional changes (at least) regarding SMB URLs: + + 1) Canonicalization does not exceed the host component. For example: + + smb://host/share/foo/ + ../.././../../foo/ --> smb://host/foo/ + + whereas perviously you would get smb://foo/. + + 2) For constructors that accept a second parameter, that parameter + can no longer be null. + + 3) Composing a URL with smb://workgroup/ and server/ used to be smart + enough to reduce the URL to just smb://server/. This is no longer + true. Doing this will yield smb://workgroup/server/ which is illegal. + +The trailing '/' requirement is because the java.net.URL class is now +used internally for all URL handling and it (and the RFCs) requires it. I +have updated the obvious places in the API documentation but there are +undoubtedly lingering examples and documentation that need to be updated. + +The reason we have converted to the java.net.URL class for URL +handling internally is because a) the few remaining bugs were +pervasive SMB URL bugs and b) the existing java.net.URL Handler was +serverly flawed. Committing whole-heartedly to java.net.URL solved both +problems. Quite well too actually. The whole thing is quite a bit more +elegant. SmbFile now extends URLConnection. + +The jcifs.http.NtlmHttpFilter and jcifs.http.NetworkExplorer classes +should work quite well at this point. The Filter is now stateless so it +should net generate NullPointerExceptions like some Tomcat users were +experiencing. The NetworkExplorer servlet will now use the negotiated +credentials to access SMB resources. You cannot use the NetworkExporer +servlet and NtlmHttpFilter at the same time (meaning the Filter cannot +be used to protect the servlet). + +NtlmAuthenticator has been zapped for the time being. It will be repaired +in another beta. + +Sun Aug 25 05:19:00 EDT 2002 + +jcifs-0.7.0b3 released + +Network Explorer was hoplessly broken. Countless bugs were fixed +(including removing a hardcoded BASEREF of my workstation, oops!). In +fact I factored out the BASEREF entirely. Link HREFs are much simpler +as a result. The style sheet has been extracted from the source and +loaded from jcifs/http/ne.css in the jar as a resource like the mime.map +which means it can easily be edited to taste. Default mime type is now +text/html unless there's an extension that's not in jcifs/util/mime.map +in which case it's application/octet-stream but you can always easily +add extensions to the map. + +I have improved the NTLM HTTP Authentication/Network Explorer +documentation significantly (Thanks to Jason for the important +links). This should really be just a drop'n-go process now for most users. + +I stumbled on a potentially serious but in the inners of SMB transport; +Uniaddress' were not matching resulting in reduntant SmbTransport +objects. Not sure if that ever impacted users though. + +Graceful-reconnect was fixed after being broken with the introduction +of NtlmPasswordAuthentication. Had to reorganize some credential +handling. The matching routine uses logical comparison of +NtlmPasswordAuthentication objects rather than comparing hashes. +That made fixing graceful-reconnect as easy as just setting the +NtlmPasswordAuthentication hashes to null so that they would be +recalculated with the new challange. + +mkdirs() has been implemented. + +Implemented setting LastModified time in SMB_COM_CLOSE for copyTo (it +will preserve modified time) but sadly it does not work with NT. Only +Samba and Win98 identified to work so far. + +Implemented Named Pipes available(). Natrually this only applies to file +IO style named pipes. Hasn't seen thourough testing however. + +Wed Aug 21 04:35:05 EDT 2002 + +jcifs-0.7.0b2 released + +Thanks to instructions from skeetz, the NTLM HTTP Authentication interface +has been greatly simplified. It is now only necessary to drop in the jar +and add a filter-mapping. + +An obvious application for jCIFS is a Network Neighborhood/Windows Explorer +type application. With the addition of the jcifs.http package this is easy. +I have added a "Network Explorer" file browser servlet to the jcifs.http +package. + +For much improved instructions regarding NTLM HTTP Authentication and the +jcifs.http.NetworkExplorer servlet see: + + http://jcifs.samba.org/src/docs/ntlmhttpauth.html + +To actually use credentials negotiated during the NTLM HTTP Authentication +it was necessary to add SmbFile constructors that accept +NtlmPasswordAuthentication objects which can be obtained from an +HttpSession like: + + NtlmHttpSession ntlm = (NtlmHttpSession)req.getSession().getAttribute( "NtlmHttpSession" ); + NtlmPasswordAuthentication auth = ntlm.getNtlmPasswordAuthentication(); + SmbFile f = new SmbFile( "smb://server/share/path", auth ); + +The internal datatype used to maintain file offsets in the +SmbFileInputStream class is not a long which in Java is 64 bits. I have not +received confirmation that files >4GB can be transfered but that's the +intention. + +Thu Aug 8 04:05:28 EDT 2002 + +jcifs-0.7.0b released + +This beta introduces some new functionality rather than refactoring and +general cleanup which was the focus of the 0.6 series. There's more to come +but here's what has made it in so far: + +o jcifs.smb.client.codepage property specifies codepage of 8 bit strings. +This should resolve the issue reported by Dmitry Khlonin who says +codepage=Cp866 is common on Russian LANs. This does not imply running with +useUnicode=false however. Some commands like the ones that enumerate shares +and workgroups will return 8 bit encoded strings regardless of wheather or +not Unicode is negotiated. If workgroups, servers, and shares do not appear +correctly try setting this property. If you *are* using useUnicode=false +setting the codepage property may also have an effect if the JRE is not +running an a locale compatible with the target machine. This link appears +to have a good list of valid identifiers. + + http://java.sun.com/j2se/1.3/docs/guide/intl/encoding.doc.html + +o Added SmbFile.getType() which will return one of + + SmbFile.TYPE_WORKGROUP + SmbFile.TYPE_SERVER + SmbFile.TYPE_SHARE + SmbFile.TYPE_NAMED_PIPE + SmbFile.TYPE_PRINTER + SmbFile.TYPE_FILESYSTEM + +isWorkgroup() is now deprecated. + +o Added a "lookup" table to jcifs.netbios.NbtAddress like the one in +java.net.InetAddress to prevent redundant queries from reaching the wire. + +o Plain text passwords have been implemented but must be enabled with +jcifs.smb.client.enablePlainTextPasswords=true. This is false by default +and will generate a "Plain text passwords are disabled" RuntimeException +exception if you try to use it. + +o The SmbFile.length() method now returns the capacity of the disk if +getType() is TYPE_SHARE. + +o Added an SmbFile.freeDiskSpace() method has that reports the amount of +free disk space in bytes on a disk exported by a share (the SmbFile need +not refer to a share however it may not refer to a workgroup or server). + +o Added SmbFile.copyTo method. This method can copy directories accross +hosts however at the momement it does not mirror file attributes. See this +message for a little more discussion about copyTo: + + http://lists.samba.org/pipermail/jcifs/2002-August/002357.html + +o Replaced jcifs.util.AuthHandler and jcifs.util.AuthInfo with +jcifs.smb.NtlmAuthenticator and jcifs.smb.NtlmPasswordAuthentication to be +consistent with java.net package Authenticator and PasswordAuthentication. +Underlying behaviour remains the same. This has not been tested thuroughly. + +Wed May 29 21:51:36 EDT 2002 + +jcifs-0.6.5 released + +Thanks to Tony for running FileOps.java against Netware. Apparently Netware +does not like the word alignment pad in SMB_COM_WRITE_ANDX. Just commenting +out that part of the serialization *appears* to work fine with other +servers as well but keep your eyes open. In the process of testing things, +I also found that the fix for read() not returning -1 in the 0.6.2 release +causes reads to return -1 prematurely if the buffer is a particular size +and a multiple of the files size etc. Unfortunately Word files and other +OLE Compound Documents are often multiples of 512 so this is quite possible +if you use a buffer size like 8192. I've created a new example called +VerifyIO.java that will identify and therefore prevent these problems in +the future. + +Sat May 18 15:59:33 EDT 2002 + +jcifs-0.6.4 released + +The recurDesired and Broadcast flags where on in Node Status +Request. Apparently XP doesn't respond to this. Should have never +had them on anyway. This should fix getAllByAddress problems with XP +(probably Win2K too). Listing on shares should send a UNC path like '\*' +but jCIFS was incorrectly sending '\\*'. This confused Netware 5.0. This +has also been fixed. + +Fri May 3 04:44:14 EDT 2002 + +jcifs-0.6.3 released + +Finally the SMB URL has been fixed. It required only small changes but of +course the effect should be dramatic; no more URL encoding and decoding +of paths. As discussed on the jCIFS mailing list it is now necessary to +URL encode passords. For example, instead of: + + smb://miallen:p@ss@server/share/path/to/file.doc + +it's: + + smb://miallen:p%40ss@server/share/path/to/file.doc + +Actually I URL decode the entire authority section so you might also do: + + smb://domain%2bmiallen:p%40ss@server/share/path/to/file.doc + +I added a fix for an ArrayIndexOutOfBounds Exception with passwords +longer than 14 characters. Thanks, MJZ. I removed all references to +e-mail address. I think the harvesters are getting out of hand. + +Thu Mar 21 21:30:45 EST 2002 + +jcifs-0.6.2 released + +It was discovered that the SmbFileInputStream.read() methods would +not return -1 when EOF was reached (returned 0 instead which is good +enough for most code) and that writing to a named pipe with clients that +support NT SMBs would trigger an "Invalid operation for IPC service" +exception. Both issues have been fixed. + +Thu Feb 21 03:02:23 EST 2002 + +jcifs-0.6.1 released + +If a file is retrived using the SmbFileInputStream class, the file's size +is precisely a multiple of 4096 and the byte[] b and int len parameters +used in a read() operation are both larger than 4096, the read( byte[] +b ) and read( byte[] b, int off, int len ) methods will return -1. The <= +condition in the middle of read( b, off, len ) has been changed to just <. + +Wed Feb 20 02:42:20 EST 2002 + +jcifs-0.6.0 released + +This long and winding beta cycle is finally at an end. There have been +no problems reported for some time now. This release is simply 0.6b9 +renamed with some improvements to the docuementation. + +Now how about that RPC layer ... + +Wed Feb 6 02:34:52 EST 2002 + +jcifs-0.6b9 released + +The jcifs.util.ThreadInterruptor has been removed. It was a feable attempt +to try and interrupt threads stalled within new Socket() because the +destination host is not responding to the initial SYN packet. These calls +eventually timeout (3 min 15 sec on Linux). I think most Java network +clients do the same in this situation. Some logic has been added to +prevent certain erronous operations such as listFiles() on IPC$. There +have also been two fixes regarding proper URL enocoding and a getName +issue. I have caught a few "Timeout waiting for response from server" +errors with the use of AuthHandler that I have added a fix for but I +an unable to reproduce the problem now. The todo has been updated as +well as the documentation. The 0.6.0 release is very close, we're just +working on API documentation at this point. + +Sat Jan 12 16:34:11 EST 2002 + +jcifs-0.6b8 released + +Fixed a problem with deleteing derectories on Win98 and Novell. Also, +fixed erronous result of calling exists() on a directories created +immediately before (attributes needed to be artificially expired). + +Fri Jan 11 03:16:49 EST 2002 + +jcifs-0.6b7 released + +The introduction of listFiles at the last minute created an issue +with caching file attributes and enumerating workgroups and hosts of a +workgroup. There was a compilation problem with URLDecoder and a possible +null pointer exception in the gracefull reconnect code. Generally the +last beta was a flop. I strongly advise that you erase it and use this +release. I have high hopes for it. The good news is listFiles has turned +out to be quite a screemer on regular directories. I can list every file +on my NT machine with T2Crawler in 10.095 seconds (yes, over the network). + +Mon Jan 7 01:24:54 EST 2002 + +jcifs-0.6b6 released + +There have been a few issues discovered and fixed: + +o The listFiles() methods will no longer throw MalformedURLException or +UnknownHostException - These where there because the SmbFile constructors +throw them. However they should never be thrown within these methods +because the URLs are constructed internally (i.e. they should not be +"malformed") and the host should not be different from the host used +to create the file listFiles() is being invoked on (i.e. the hostname +should be cached or valid). + +o Gracefull reconnect and internal state consistencey - Previously, +jCIFS was not very smart about how to handle socket failure on the +server. If for example, the server was restarted, jCIFS would gernerate +exceptions and generally fall over in a heap. We have revisited the +code that invalidates transports, their sessions, and the sessions +trees and found that the code was somewhat deficient. If for example +an error occured and the transport instructed it's sessions to "logoff" +they might try to send a message to the server indicating so. Of course, +this message too might fail resulting in an inconsistent state. There +was one report of invlid UID exceptions. This is likely the cause of +that problem and should not happen again. We have added a boolean inError +parameter to the tryClose, logoff, and treeDisconnect methods that if +called with inError = true ensure that the state of all sessions and trees +associates with a transport are reset forceing jCIFS to reestablish new +sessions and tree connects. All of this happends under the hood of course. + +o Improve SMB header discovery - The detection of the first for "magic" +bytes of the SMB header (0xFF 'S' 'M' 'B') has been greatly improved. Some +servers leave garbage bytes at the end of messages which jCIFS is +sensitive about. This should solve the problem reported with NetWare 5. + +o Ensure safe URLDecoding of SMB URL - It was discovered that an SmbFile +derived from another SmbFile created with URL encoded characters might +generate an error. This was because the first SmbFile would decode the +URL and then pass the now invalid characters on to the second file. This +as been fixed by only decoding the string used to reprsent the files +path internally and thus not pass it to derived SmbFiles. + +o Improved choice of authentication credentials to IPC$ - We recently +found some strange situations where AuthExceptions would be thrown +were that probably should not have. For example, if you connect to a +Win98 share using normal credentials and then try to perform an IPC$ +operation (e.g. list shares) Win98 would not take the "null" login +credentials and return Access denied. If you connect to IPC$ with "null" +logon creadentials *first* then everything is fine. So we have made the +choice of credentials for connecting to IPC$ a little smarter. If normal +credentials have been supplied jCIFS will try those and if that fails +it tries the "null" creadentials. + +o Ensure share names are submitted in CAPS - Win98 (again *sigh*) +will reject share names that are not capitalized. Shares will now be +presented to servers in all CAPS. I guess this was broken during the +revamping, it worked in 0.5. Again, this happends under the hood; no +user action necessary. + +Wed Dec 19 04:42:28 EST 2001 + +jcifs-0.6b5 released + +I realize we're in the middle of a beta cycle but the listFiles +methods really need to go in. I didn't realize that the FilenameFilter +interface is to pass each file to an the accept(File dir, String name) +method. This is would require retrieving all the files from the server. I +will implement this but I for now I have created a listFiles( String +wildcard ) method instead. This is much more efficent because the CIFS +protocol provides for a wildcard expression to be passed to the server +and return only the entries that match. For a large directory is really +is far superior to the default java.io.FilenameFilter interface. + +Rob et al. You might as well stick with 6b4 for a while. The listFiles is +the way to go for you ultimately but they need a little growing time and +my preliminary benchmarks do not show a real performance improvement. I'll +leave 0.6b4 up for a while. + +Sat Dec 15 17:20:59 EST 2001 + +jcifs-0.6b4 released + +A bug that caused exists() (and methods that call it) to return erronious +results has been fixed. There have also been numerous other smaller bug +fixes mostly regarding the behavior of SmbFile methods. This release +should be fairly stable. I have updated and tested all example programs +and added a few new tests. I have noticed a problem with certain SMB +URLs that I'm not sure how to fix yet but they are unusal cases. + +PS: The depth argument of the T2Crawler does not work. It causes threads +to exit prematurely. It will likely never be fixed. + +Wed Nov 28 04:39:40 EST 2001 + +jcifs-0.6b3 released + +More refactoring. I found a pretty serious Object sink. I fixed the +deadlock in beta 2. I'm also trying out a new buffer strategy. There +are only two 64K buffers (plus the BufferCache for transactions) for +all transports now. Looks like a nice speed boost from that two. Eww, +this is getting embarassing :~) + +TIP: + +Try the T2Crawler.java with: + +soTimeout=3 +resolveOrder=WINS + +Also, you may have noticed that the crawler example will stall on some +hosts. This is because they don't respond to SYN packets. This has +been fixed. + + +Wed Nov 21 03:37:28 EST 2001 + +jcifs-0.6b2 released + +Previously jCIFS could not list hosts of a workgroup/domain if that +workgroup/domain's master browser was on a different network segment. This +has been fixed. The client can now enumerate hosts of an entire WAN. There +have also been two trivial bug fixes. I'm seeing some strange behaviour +from the ThreadedSmbCrawler test. One particularly slow host seems to +cause it to stall (although on a small network it flies). + +Fri Nov 16 04:07:05 EST 2001 + +jcifs-0.6b released + +This is the first beta of 0.6. + +There have been significant changes under the hood. The primitives such +as packet encoding/decoding and transport have proven very sturdy however +the top level glue and logic driving the client really needed an overhaul +in hindsight. The client is much smarter now whereas previously jCIFS was +quite chatty and used some messages abusively (NodeStatusRequest). Some +other cleanups that took into account allocation of buffers and +large numbers of objects have resulted in measureable performance +improvements. All of this should be transparent to the user however my +confidence in the stabilty of 0.5.1 no longer applies. It will take some +time to confirm everything works as advertised. I am confident however +that any bugs will only require minor adjustments to fix. Of course the +name resolution bug that triggered this crusade has been fixed. + +There are some API changes. Most methods of SmbFile throw the now public +SmbException. Natrually, this will require changes to existing code. For +example, if your code was: + +if( r.delete() ) { + System.out.println( "delete successfull" ); +} else { + System.out.println( "error!" ); +} + +you might replace this with: + +try { + f.delete(); + System.out.println( "delete successfull" ); +} catch( SmbException se ) { + System.out.println( "error: " + se.getMessage() ); +} + +There are quite a few different messages that can be provoked such as: + +The file is being used by another process +The device is not ready +All pipe instances are busy +... + +not all of which have text messages (and which ones do have messages are +in only English at the moment). You can test and make dicisions based on +the errorClass and errorCode of an SmbException. All SmbExceptions are +thrown through these methods unless an object implementing the AuthHandler +interface has been called with the static SmbFile.setAuthHanler method. If +an AuthHandler has been specified the following authentication related +SmbExceptions: + +Access denied +Bad password +The client does not have the necessary access rights for the + requested function +The user account has expired +The user is not allowed to access this server from this client +The user is not permitted to access the server at this time +The password of the user has expired + +will not be thrown by SmbFile methods but rather passed in the AuthInfo +object to the AuthHandler's authenticate() method along with the username, +password, domain, and target URL if one of these SmbExceptions occurs. See +http://lists.samba.org/pipermail/jcifs/2001-October/001553.html for a +related discussion. I believe this is a powerfull feature in itself. This +provides for sophisticated error handling and consistent error messages +(the messages are the same as those reported by Windows clients). There +is also an oppurunity to introduce a ResourceBundle of text messages +here. I beleive it will work quite well and in practice I do not believe +code will be cluttered with try/catch. + +The NbtAddress class was designed to handle NetBIOS name queries +similarly to the common InetAddress class. Unfortunately a lapse in +judgment integrated DNS queries into this class in jcifs-0.5 (thus the +name service bug). The solution is to remove this DNS code and provide +a wrapper class that handles both DNS queries as well as NetBIOS queries +mainly delegating the work to InetAddress and NbtAddress. This class is +UniAddress. Here is how each of these classes should be used: + +o InetAddress - Lookup a DNS name +o NbtAddress - Lookup a NetBIOS name or perform NetBIOS specific + queries (NodeStatus with getAllByAddress) +o UniAddress - Don't know or care what type of name it is, try to + find the name with both DNS and NetBIOS queries if necessary. Query + behavior is governed by the jcifs.resolveOrder property. + +So generally the UniAddress class should be used if you wish to interface +with name services directly (normally not necessary when working with +the jcifs.smb package). + +In summary the classes that have been added or made public are: + +jcifs.UniAddress +jcifs.util.AuthHandler +jcifs.util.AuthInfo +jcifs.smb.SmbException + +Mon Aug 27 00:29:02 EDT 2001 + +jcifs-0.5.1 + +Chris did some great testing at the CIFS Conference Interoperability +Lab and found three minor bugs. They are described in detail here: + +http://lists.samba.org/pipermail/jcifs/2001-August/001428 + +These packages will now work with Java 1.1 as well as Java 2. + +Sun Jul 29 04:01:18 EDT 2001 + +jcifs-0.5 + +This is the final release of the 0.5 series. It is the most stable and +complete product the jCIFS team has to offer. There are no known bugs. A bug +in the renameTo operation (would not always return false when it should have) +has been fixed, API documentation improvements have been made, and a +entry to the FAQ has been added. + +Fri Jul 13 18:54:37 EDT 2001 + +jcifs-0.5b2 + +Thanks to Rob for realizing that attempting to read the same file from +different processes/threads yielded an "The file is being used by another +process" exception. We had the share flags and access masks wrong. A +Log.CRITICAL_EXCEPTIONS mask has been added for logging messages to the +console. If: + + Log.setMask( Log.CRITICAL_EXCEPTIONS ); + +is set, the "Access denied", "Bad password", and "The device is not +ready" sorts of exceptions will NOT be printed. The default is still +Log.EXCEPTIONS which encompasses both Log.CRITICAL_EXCEPTIONS and regular +Log.EXCEPTIONS so existing code will not be affected. + +Thu Jun 28 21:04:15 EDT 2001 + +jcifs-0.5b + +This is the beta release of jcifs-0.5. The 0.5 series has already been +through a stable release and there are no know bugs so we are confident +that it will perform well. New features since jcifs-0.4 include: + +o SmbFile.list() Bug Fix - The jcifs-0.4 package had a serious bug that + caused a TRANS2_FIND_FIRST2/NEXT2 endless loop. It has been properly + fixed. This should be the first *complete* stable release. +o Share, Server, and Workroup Enumeration - jCIFS can now list the shares + on a server, servers of a workgroup, and workgroups on a network. +o CallNamedPipe, TransactNamedPipe, and CreateFile Named Pipe API (Paul) +o Complete SMB Filesharing URL Scheme IETF Draft Support - The smb:// + URL scheme has been fully implemented. (Chris) +o Transactions and RAP API +o Transactions - Full multi-part Transaction requests(used by Transact + Named Pipes) +o Daylight Savings Bug Fix - jCIFS was not properly correcting for + daylight savings. (Urban) +o Full SmbComNTCreateAndX Support - We now look just like NT 4 instead + of Winblows 95 :~) +o Unicode Alignment Bug Fix - Unicode alignment was generally not + correct and caused many problems in early 0.5dev releases. +o SmbFile Method Behaviors - Fixed canRead() and re-thought and soul + searched over the meaning of each of these methods and their behavior + in the smb://, smb://name, and Named Pipe contexts. These methods + should start to get pretty stable at this point. +o Clean, No Wait Exiting - Examples and other programs would wait 15 + seconds before exiting. This has been fixed by making the Transport + thread setDaemon( true ). Same for the NameServiceClient Thread. +o Full Tuneable Batching +o NetBIOS Scope Fix +o New getServer, getShare, isWorkgroup Methods +o SmbShell and SmbCrawler Utilities + +Thanks deserved for this release to Chris, Steve, Paul, The DJ, Urban, +James, Thierry, savaJe Technologies, and Josef. diff --git a/README.txt b/README.txt index f26743d..17beab8 100644 --- a/README.txt +++ b/README.txt @@ -1,348 +1,241 @@ -Fri Nov 16 04:07:05 EST 2001 - -jcifs-0.6b released - -This is the first beta of 0.6. - -There have been significant changes under the hood. The primitives such -as packet encoding/decoding and transport have proven very sturdy however -the top level glue and logic driving the client really needed an overhaul -in hindsight. The client is much smarter now whereas previously jCIFS was -quite chatty and used some messages abusively (NodeStatusRequest). Some -other cleanups that took into account allocation of buffers and -large numbers of objects have resulted in measureable performance -improvements. All of this should be transparent to the user however my -confidence in the stabilty of 0.5.1 no longer applies. It will take some -time to confirm everything works as advertised. I am confident however -that any bugs will only require minor adjustments to fix. Of course the -name resolution bug that triggered this crusade has been fixed. - -There are some API changes. Most methods of SmbFile throw the now public -SmbException. Natrually, this will require changes to existing code. For -example, if your code was: - -if( r.delete() ) { - System.out.println( "delete successfull" ); -} else { - System.out.println( "error!" ); -} - -you might replace this with: - -try { - f.delete(); - System.out.println( "delete successfull" ); -} catch( SmbException se ) { - System.out.println( "error: " + se.getMessage() ); -} - -There are quite a few different messages that can be provoked such as: - -The file is being used by another process -The device is not ready -All pipe instances are busy -... - -not all of which have text messages (and which ones do have messages are -in only English at the moment). You can test and make dicisions based on -the errorClass and errorCode of an SmbException. All SmbExceptions are -thrown through these methods unless an object implementing the AuthHandler -interface has been called with the static SmbFile.setAuthHanler method. If -an AuthHandler has been specified the following authentication related -SmbExceptions: - -Access denied -Bad password -The client does not have the necessary access rights for the - requested function -The user account has expired -The user is not allowed to access this server from this client -The user is not permitted to access the server at this time -The password of the user has expired - -will not be thrown by SmbFile methods but rather passed in the AuthInfo -object to the AuthHandler's authenticate() method along with the username, -password, domain, and target URL if one of these SmbExceptions occurs. See -http://lists.samba.org/pipermail/jcifs/2001-October/001553.html for a -related discussion. I believe this is a powerfull feature in itself. This -provides for sophisticated error handling and consistent error messages -(the messages are the same as those reported by Windows clients). There -is also an oppurunity to introduce a ResourceBundle of text messages -here. I beleive it will work quite well and in practice I do not believe -code will be cluttered with try/catch. - -The NbtAddress class was designed to handle NetBIOS name queries -similarly to the common InetAddress class. Unfortunately a lapse in -judgment integrated DNS queries into this class in jcifs-0.5 (thus the -name service bug). The solution is to remove this DNS code and provide -a wrapper class that handles both DNS queries as well as NetBIOS queries -mainly delegating the work to InetAddress and NbtAddress. This class is -UniAddress. Here is how each of these classes should be used: - -o InetAddress - Lookup a DNS name -o NbtAddress - Lookup a NetBIOS name or perform NetBIOS specific - queries (NodeStatus with getAllByAddress) -o UniAddress - Don't know or care what type of name it is, try to - find the name with both DNS and NetBIOS queries if necessary. Query - behavior is governed by the jcifs.resolveOrder property. - -So generally the UniAddress class should be used if you wish to interface -with name services directly (normally not necessary when working with -the jcifs.smb package). - -In summary the classes that have been added or made public are: - -jcifs.UniAddress -jcifs.util.AuthHandler -jcifs.util.AuthInfo -jcifs.smb.SmbException - -Mon Aug 27 00:29:02 EDT 2001 - -jcifs-0.5.1 - -Chris did some great testing at the CIFS Conference Interoperability -Lab and found three minor bugs. They are described in detail here: - -http://lists.samba.org/pipermail/jcifs/2001-August/001428 - -These packages will now work with Java 1.1 as well as Java 2. - -Sun Jul 29 04:01:18 EDT 2001 - -jcifs-0.5 - -This is the final release of the 0.5 series. It is the most stable and -complete product the jCIFS team has to offer. There are no known bugs. A bug -in the renameTo operation (would not always return false when it should have) -has been fixed, API documentation improvements have been made, and a -entry to the FAQ has been added. - -Fri Jul 13 18:54:37 EDT 2001 - -jcifs-0.5b2 - -Thanks to Rob for realizing that attempting to read the same file from -different processes/threads yielded an "The file is being used by another -process" exception. We had the share flags and access masks wrong. A -Log.CRITICAL_EXCEPTIONS mask has been added for logging messages to the -console. If: - - Log.setMask( Log.CRITICAL_EXCEPTIONS ); - -is set, the "Access denied", "Bad password", and "The device is not -ready" sorts of exceptions will NOT be printed. The default is still -Log.EXCEPTIONS which encompasses both Log.CRITICAL_EXCEPTIONS and regular -Log.EXCEPTIONS so existing code will not be affected. - -Thu Jun 28 21:04:15 EDT 2001 - -jcifs-0.5b - -This is the beta release of jcifs-0.5. The 0.5 series has already been -through a stable release and there are no know bugs so we are confident -that it will perform well. New features since jcifs-0.4 include: - -o SmbFile.list() Bug Fix - The jcifs-0.4 package had a serious bug that - caused a TRANS2_FIND_FIRST2/NEXT2 endless loop. It has been properly - fixed. This should be the first *complete* stable release. -o Share, Server, and Workroup Enumeration - jCIFS can now list the shares - on a server, servers of a workgroup, and workgroups on a network. -o CallNamedPipe, TransactNamedPipe, and CreateFile Named Pipe API (Paul) -o Complete SMB Filesharing URL Scheme IETF Draft Support - The smb:// - URL scheme has been fully implemented. (Chris) -o Transactions and RAP API -o Transactions - Full multi-part Transaction requests(used by Transact - Named Pipes) -o Daylight Savings Bug Fix - jCIFS was not properly correcting for - daylight savings. (Urban) -o Full SmbComNTCreateAndX Support - We now look just like NT 4 instead - of Winblows 95 :~) -o Unicode Alignment Bug Fix - Unicode alignment was generally not - correct and caused many problems in early 0.5dev releases. -o SmbFile Method Behaviors - Fixed canRead() and re-thought and soul - searched over the meaning of each of these methods and their behavior - in the smb://, smb://name, and Named Pipe contexts. These methods - should start to get pretty stable at this point. -o Clean, No Wait Exiting - Examples and other programs would wait 15 - seconds before exiting. This has been fixed by making the Transport - thread setDaemon( true ). Same for the NameServiceClient Thread. -o Full Tuneable Batching -o NetBIOS Scope Fix -o New getServer, getShare, isWorkgroup Methods -o SmbShell and SmbCrawler Utilities - -Thanks deserved for this release to Chris, Steve, Paul, The DJ, Urban, -James, Thierry, savaJe Technologies, and Josef. - -FILES: - - jcifs-0.5b.tgz jar and javadoc only for UNIX - jcifs-0.5b.zip jar and javadoc only for WINDOWS - jcifs-0.5b.jar jar file only - -NOTE: The source code is included in the above packages. If -you would like to actually build jCIFS the ANT jar files are packaged -separately: - - ant.tgz ant jar files - ant.zip ditto - -Just unpack one of the above in the jcifs_0.5b directory, set JAVA_HOME in -build.{sh,bat} to bootstrap Ant, and run $ ./build.sh smb or > build smb. - -IMPORTANT: - -The jcifs.netbios.ns.nameserver has been changed to jcifs.netbios.wins -and the jcifs.util.Config class should now be referenced as -jcifs.Config. Programs written for jcifs-0.4 will not run without making -these two changes at least. - -The jCIFS project uses the 'Ant' build tool available here: - - http://jakarta.apache.org/ant/ - -If you have *any* trouble please let us know on the mailing list by -sending mail to jcifs@samba.org or to myself at mballen@erols.com. - -Enjoy, -Michael B. Allen +Wed Feb 12 01:23:02 EST 2003 + +A security issue regarding the SmbSession.logon() method used by NTLM HTTP +Authentication has been fixed and a modification has been made to trigger +MSIE to redisplay the Network Password dialog repeatedly until correct +credentials are supplied. The change was made in the core jcifs.smb package +however so test this in your dev environments. + +Wed Feb 5 00:41:32 EST 2003 + +The jcifs-0.7.0 and 0.7.1 releases will incorrectly throw an +ArrayIndexOutOfBounds exception if a write of 1501 to 1504 is performed. +This release fixes that bug. You may also set jcifs.smb.client.snd_buf_size += 1300 as a temporary work-around. It is also now possible to specify a +"ShareAccess" with SmbFileOutputStream and SmbFile to restrict other +processes from accessing files jCIFS opens. Also, SmbFileOutputStream now +supports writing files larger than 4GB. + +Wed Jan 15 22:34:14 EST 2003 + +jcifs-0.7.1 released + +Three bugs have been fixed regarding filenames with '#' signs in them, the +getInputStream(), getLastModified(), getDate(), and getContentLength() +methods of the URLConnection implementation, and isExists() incorrectly +returning false. + +Thu Jan 9 00:06:23 EST 2003 + +jcifs-0.7.0 released + +This is the 0.7.0 release of jCIFS, the Java SMB client. There is new +functionality specifically targeting Web applications as well as some +critical SMB URL fixes and feature improvements: + +o The new jcifs.http package is very handy when building Web applications + that need to integrate with MS corporate intranets. Adding a hyperlink to + a document on a network drive is easy with Network Explorer (pictured + right) and will transparently negotiate credentials with MSIE to browse + SMB resources (really, no password dialog necessary). This package also + boasts an NTLM HTTP Authentication servlet Filter for authenticating MSIE + clients. These are useful features because many of the tasks surrounding + user management now fall back to computer support and HR. It is not + necessary to add and remove users as they join and leave the company. + Perhaps most important from the user's perspective; they do not need to + enter a username or password if their workstation is a member of an NTLM + domain. The password hashes generated when they logged on to their + workstation will be negotiated during the initial request for a session, + passed through jCIFS, and validated against a PDC or BDC. This also makes + the user's domain, username, and password available for managing session + information, profiles, preferences, etc. + +o The functionality used to authenticate and manage arbitrary creadentials + has been exposed in the SmbSession and NtlmPasswordAuthentication + classes. This permits NTLM password authentication to be integrated into + applications without requiring Microsoft components or JNI. + +o With the introduction of the jcifs.encoding property the client is now + truely internationalized. It has been used successfully on OS/390 with + native EBCDIC character encoding. See the Sun JRE documentation for a + list of supported encodings. + +o The URL issues remaining in the 0.6 series have been fixed in 0.7 by + converting all SMB URL handling internally to use the java.net.URL class + (Note: directories must now have a trailing slash and Java 1.3 is + required). Also a deadlock in the name service code was identified and + fixed (repaired in 0.6.8 as well). + +o A copyTo() method has been added to SmbFile that is very fast at copying + large directories across hosts. + +o There have been numerous other changes including the mkdirs() and + getType() methods, plain text password support (disabled by default), the + available() method and close() fix for Named Pipes, reading files larger + than 4 GB, the NtlmAuthenticator class, and more. + +All documentation has been completely reviewed and updated. --8<-- - JCIFS + jCIFS Common Internet File System Client in 100% Java http://jcifs.samba.org -This is the JCIFS SMB client library written in Java. In short it -will enable Java applications to remotely access shared directories -on SMB file servers(i.e. a Microsoft Windows "share"). It is a fairly -religious implementation of the CIFS specification supporting Unicode, -batching, multiplexing, encrypted authentication, transactions, named -pipes, share/server/workgroup enumeration, and more. It is licensed -under LGPL which means commercial organizations can legitimately use it -with their propertietary code(you just can't modify the library itself -without reciprocation). +This is the jCIFS SMB client library written in Java. In short, it will +enable Java applications to remotely access shared directories on SMB file +servers(i.e. a Microsoft Windows "share"). It is a fairly religious +implementation of the CIFS specification supporting Unicode, batching, +multiplexing, encrypted authentication, transactions, named pipes, +domain/workgroup/server/share/directory/file enumeration, RAPs and more. It +is licensed under LGPL which means commercial organizations can +legitimately use it with their propertietary code (you just can't modify +the library itself without providing the source for those changes to it's +users, see the LGPL for details). REQUIREMENTS: -Java 1.1 or above - http://java.sun.com/products/ +Java 1.3 or above - http://java.sun.com/products/ -INSTALLATION +INSTALLATION: -Just add the jar file to you classpath as you would with any other -jar. More specifically: +Just add the jar file to you classpath as you would with any other jar. +More specifically: UNIX: -1) Go to http://jcifs.samba.org and download jcifs-0.5b.tgz -2) Put it someplace reasonable and extract it with: +Go to http://jcifs.samba.org and download the latest jar. If you download +the tgz archive you also get the source code and javadoc API documentation +(see critical properties discussed on the Overview page). Put it someplace +reasonable and extract it. For example: - $ gunzip jcifs-0.5b.tgz - $ tar -xvf jcifs-0.5b.tar + $ gunzip jcifs-0.7.0.tgz + $ tar -xvf jcifs-0.7.0.tar -3) Add the jar to your classpath. There are two ways to do this. One is to +Add the jar to your classpath. There are two ways to do this. One is to explicitly set it on the command line when you run your application like: - $ java -cp path/to/jcifs-0.4b.jar MyApplication + $ java -cp myjars/jcifs-0.7.0.jar MyApplication -or perhaps export it in your .profile/.bash_profile like: +but a more robust solution is to export it in your ~/.profile or +~/.bash_profile like: - CLASSPATH=$CLASSPATH:/home/miallen/path/to/jcifs-0.5b.jar + CLASSPATH=$CLASSPATH:/home/produser/myapp/myjars/jcifs-0.7.0.jar export CLASSPATH WINDOWS: -1) Go to http://jcifs.samba.org and download jcifs-0.5b.zip -2) Extract it with winzip and put the files someplace reasonable. -3) Add the jar to your classpath. There are two ways to do this. One is to +Go to http://jcifs.samba.org and download the latest jar. If you download +the zip archive you also get the source code and javadoc API documentation +(see critical properties discussed on the Overview page). Put it someplace +reasonable and extract it with something like Winzip. + +Add the jar to your classpath. There are two ways to do this. One is to explicitly set it on the command line when you run your application like: - C:\jcifs> java -cp jcifs-0.4b.jar MyApplication + C:\> java -cp myjars\jcifs-0.7.0.jar MyApplication -The other way is to alter your system environment but I'm not confident -I can tell you accurately how to do that. +but a more robust solution would be to change your system environment but +I'm not confident I can tell you accurately how to do that. -It is also common that the CLASSPATH be specified in a shell script or -batch file. See build.{sh,bat} as a hint. +It is also common that the CLASSPATH be specified in a shell script or +batch file. See the build.bat batch file that runs the Ant build tool as an +example. -RUNNING JCIFS: +USING JCIFS: -In general the public API is extremely simple. The jcifs.smb.SmbFile, -jcifs.smb.SmbFileInputStream, and jcifs.smb.SmbFileOutputStream -classes are analogous to the java.io.File, java.io.FileInputStream, -and java.io.FileOutputStream classes so if you know how to use those it -should be quite obvious how to use JCIFS provided you set any necessary -properties(such as wins) and understand the smb:// URL syntax. +In general the public API is extremely simple. The jcifs.smb.SmbFile, +jcifs.smb.SmbFileInputStream, and jcifs.smb.SmbFileOutputStream classes are +analogous to the java.io.File, java.io.FileInputStream, and +java.io.FileOutputStream classes so if you know how to use those it should +be obvious how to use jCIFS provided you set any necessary properties(such +as WINS) and understand the smb:// URL syntax. -Here's an example to retrieve a file: +Here's an example to retrieve a file: import jcifs.smb.*; jcifs.Config.setProperty( "wins", "192.168.1.230" ); SmbFileInputStream in = new SmbFileInputStream( "smb://username:password@host/c/My Documents/report.txt" ); - byte[] b = new byte[65535]; + byte[] b = new byte[8192]; int n; while(( n = in.read( b )) > 0 ) { System.out.write( b, 0, n ); } -You can also write, rename, list contents of a directory, enumerate -shares, communicate with Win32 Named Pipe Servers, ...etc. +You can also write, rename, list contents of a directory, enumerate shares, +communicate with Win32 Named Pipe Servers, ...etc. -The protocol handler for java.net.URL is also in place which means you -retrieve files using the URL class as you would with other protocols. For -example: +The protocol handler for java.net.URL is also in place which means you +retrieve files using the URL class as you would with other protocols. For +example: - Class.forName( "jcifs.Config" ); //ensure protocol handler is loaded - URL url = new URL( "smb://user:pass@host/share/dir/file.txt" ); + jcifs.Config.registerSmbURLHandler(); //ensure protocol handler is loaded + URL url = new URL( "smb://user:pass@host/share/dir/file.doc" ); InputStream in = url.openStream(); -This will also work with whatever else uses the URL class internally. For -example if you use RMI you can serve class files from an SMB share and -use the codebase property: +There are many example programs in the jcifs_0.7.0/examples/ directory. To +execute the Put example you might do: + + $ java -cp examples:jcifs-0.7.0.jar -Djcifs.properties=jcifs.prp \ + Put smb://usr:pass@host/share/dir/file.doc + ########## + 582K transfered + +This will also work with whatever else uses the URL class internally. For +example if you use RMI you can serve class files from an SMB share and use +the codebase property: -Djava.rmi.server.codebase=smb://mymachine/c/download/myapp.jar -To execute the Put example you might do: +See the extensive API documentation included in the distribution. -$ java -cp examples:jcifs-0.4b.jar Put smb://usr:pass@host/share/file.zip -########## -582K transfered +BUILDING JCIFS FROM SOURCE: -API documentation is included. +If you wish to modify and/or build the jCIFS source simply download the +ant.tgz or ant.zip available at http://jcifs.samba.org and extract it in +the jcifs_0.7.0 directory. Edit the build.sh or build.bat file to +appropriately reflect the location of the JDK on your system and bootstrap +the Ant build tool. Now type: + + $ ./build.sh + +You will be presented with a list of target arguments. The build file is a +standard Ant build.xml config. You may also integrate the package into your +existing Ant installation or get the latest version of Ant here: + + http://jakarta.apache.org/ant/ WHAT IS SMB AND CIFS? -Server Message Block (SMB) is an application layer networking protocol -for file and print sharing. It is the de-facto networking protocol for -Microsoft Windows platforms. The Common Internet File System (CIFS) -is the more generic name for all that encompasses the protocol and its -many layers. Collectively this is the networking protocol used when you -"Map Network Drive...", issue "net use * \\server\share" commands, use -smbclient on UNIX, smbfs on Linux, Sharity, OS2, server vendors such as -Network Appliance, EMC, and others. +Server Message Block (SMB) is an application layer networking protocol for +file and print sharing. It is the de-facto networking protocol for +Microsoft Windows platforms. The Common Internet File System (CIFS) is the +more generic name for all that encompasses the protocol and its many +layers. Collectively this is the networking protocol used when you "Map +Network Drive...", issue "net use * \\server\share" commands, use smbclient +on UNIX, smbfs on Linux, Sharity, OS2, server vendors such as Network +Appliance, EMC, and Novell NetWare. WHY DO YOU NEED JCIFS? -This client is 100% Java and will work the same in a variety of -environments from Palm Pilots and applets to any UNIX that supports -Java. Naturally you can choose to run your applications on a platform -that supports mapping or mounting remote volumes into the local -filesystem but this assumes you know what shares you are accessing in -advance and what platform your application is running on(do you use -/mnt/pnt or H:\dir). Such an approach is not portable, unstable due to -unnecessary dependencies, and can be difficult to manage. JCIFS offers -Java applications that require access to SMB file services portability -and therefore the added stability that the UNIX environment can -provide. The JCIFS infrastructure is also highly extensible. If there -is a demand it will include a great deal of additional functionality -not available through a filesystem API such as printing, RPC, NT file -change notification, etc. +This client is 100% Java and will work the same in a variety of +environments from Palm Pilots and applets to any UNIX that supports Java. +Naturally you can choose to run your applications on a platform that +supports mapping or mounting remote volumes into the local filesystem but +this assumes you know what shares you are accessing in advance and what +platform your application is running on(do you use /mnt/pnt or H:\dir). The +latency involed makes this approach unsatisfactory for certain applications +(e.g. Web Gateway). Using locally mapped filesystems is also not portable, +unstable due to unnecessary dependencies, and more difficult to manage. The +JCIFS infrastructure is also highly extensible. If there is a demand it +will include a great deal of additional functionality not available through +a filesystem API such as printing, RPC, NT file change notification, etc. ACKNOWLEDGEMENTS -Special thanks to the Samba organization and Christopher R. Hertel for -starting the JCIFS project. +Special thanks to the Samba organization and Christopher R. Hertel for +starting the JCIFS project. + diff --git a/build.sh b/build.sh index 556c1f6..1924c4a 100644 --- a/build.sh +++ b/build.sh @@ -1,6 +1,7 @@ #!/bin/sh JAVA_HOME=/usr/local/java -CLASSPATH=ant/ant.jar:ant/jaxp.jar:ant/parser.jar:${JAVA_HOME}/lib/tools.jar +CLASSPATH=ant/ant.jar:ant/jaxp.jar:ant/parser.jar:${JAVA_HOME}/lib/tools.jar:/usr/local/lib/servlet.jar +#CLASSPATH=ant/ant.jar:ant/jaxp.jar:ant/parser.jar:/usr/local/resin/lib/jsdk23.jar:. $JAVA_HOME/bin/java -classpath $CLASSPATH org.apache.tools.ant.Main -buildfile build.xml $@ diff --git a/build.xml b/build.xml index 17c6fcc..c16e817 100644 --- a/build.xml +++ b/build.xml @@ -17,6 +17,13 @@ + + + + - + + + + + - + + + - + - - - + + + - + - + - - + + diff --git a/examples/AllocInfo.java b/examples/AllocInfo.java new file mode 100644 index 0000000..842f764 --- /dev/null +++ b/examples/AllocInfo.java @@ -0,0 +1,11 @@ +import jcifs.smb.SmbFile; + +public class AllocInfo { + + public static void main( String argv[] ) throws Exception { + + SmbFile f = new SmbFile( argv[0] ); + System.out.println( f.getDiskFreeSpace() ); + } +} + diff --git a/examples/Append.java b/examples/Append.java new file mode 100644 index 0000000..7d073c9 --- /dev/null +++ b/examples/Append.java @@ -0,0 +1,21 @@ +import jcifs.smb.SmbFile; +import jcifs.smb.SmbFileOutputStream; + +public class Append { + + public static void main( String argv[] ) throws Exception { + + SmbFile f = new SmbFile( argv[0] ); + SmbFileOutputStream out = new SmbFileOutputStream( f, true ); + + byte[] msg; + int i = 0; + while( i++ < 10 ) { + msg = new String( "this is msg #" + i ).getBytes(); + out.write( msg ); + Thread.sleep( 17000 ); + } + + out.close(); + } +} diff --git a/examples/AuthDialog.java b/examples/AuthDialog.java deleted file mode 100644 index 0587cff..0000000 --- a/examples/AuthDialog.java +++ /dev/null @@ -1,64 +0,0 @@ -import java.awt.*; -import java.awt.event.*; - -public class AuthDialog extends Dialog implements ActionListener { - - Panel labels, fields, top, middle, buttons; - TextField username, password; - Button ok, cancel; - - public AuthDialog() { - super( new Frame(), "Authentication", true ); - setSize( 200, 165 ); - setLocation( 400, 300 ); - - top = new Panel(); - middle = new Panel(); - labels = new Panel( new GridLayout( 2, 1 )); - fields = new Panel( new GridLayout( 2, 1 )); - buttons = new Panel( new GridLayout( 1, 2 )); - - username = new TextField( 15 ); - password = new TextField( 15 ); - - fields.add( username ); - fields.add( password ); - - labels.add( new Label( "Username:" )); - labels.add( new Label( "Password:" )); - - middle.add( labels, BorderLayout.WEST ); - middle.add( fields, BorderLayout.CENTER ); - - top.add( new TextArea( "The client does not have the necessary access rights for the requested function", 3, 30, TextArea.SCROLLBARS_NONE ), BorderLayout.CENTER ); - top.add( middle, BorderLayout.SOUTH ); - - ok = new Button( "Ok" ); - cancel = new Button( "Cancel" ); - password.setEchoChar( '*' ); - ok.addActionListener( this ); - cancel.addActionListener( this ); - buttons.add( ok ); - buttons.add( cancel ); - - add( top, BorderLayout.CENTER ); - add( buttons, BorderLayout.SOUTH ); - - addWindowListener( new CloseWindow() ); - } - - public void actionPerformed( ActionEvent ae ) { - setVisible( false ); - } - - class CloseWindow extends WindowAdapter { - public void windowClosing( WindowEvent e ) { - setVisible( false ); - } - } - - public static void main( String[] argv ) { - AuthDialog authDialog = new AuthDialog(); - authDialog.setVisible( true ); - } -} diff --git a/examples/AuthListFiles.java b/examples/AuthListFiles.java new file mode 100644 index 0000000..918716f --- /dev/null +++ b/examples/AuthListFiles.java @@ -0,0 +1,57 @@ +import jcifs.netbios.NbtAddress; +import jcifs.util.*; +import jcifs.smb.*; +import jcifs.util.Log; +import java.util.Date; + +public class AuthListFiles implements AuthHandler { + + public static String readLine() throws Exception { + int c; + StringBuffer sb = new StringBuffer(); + while(( c = System.in.read() ) != '\n' ) { + if( c == -1 ) return ""; + sb.append( (char)c ); + } + return sb.toString().trim(); + } + + public AuthListFiles( String[] argv ) throws Exception { + SmbFile.setAuthHandler( this ); + + SmbFile file = new SmbFile( argv[0] ); + + SmbFile[] files = file.listFiles(); + + for( int i = 0; i < files.length; i++ ) { + System.out.print( " " + files[i].getName() ); + } + } + + public boolean authenticate( AuthInfo authInfo ) { + System.out.println( authInfo.exception.getMessage() + " for " + authInfo.target ); + System.out.print( "username: " ); + int i; + try { + String user = readLine(); + if((i = user.indexOf( '\\' )) != -1 ) { + authInfo.domain = user.substring( 0, i ); + authInfo.username = user.substring( i + 1 ); + } else { + authInfo.username = user; + } + System.out.print( "password: " ); + authInfo.password = readLine(); + if( authInfo.password.length() > 0 ) { + return true; + } + } catch( Exception e ) { + } + return false; + } + + + public static void main( String[] argv ) throws Exception { + new AuthListFiles( argv ); + } +} diff --git a/examples/Break.java b/examples/Break.java new file mode 100644 index 0000000..f0ed65e --- /dev/null +++ b/examples/Break.java @@ -0,0 +1,29 @@ +import jcifs.netbios.NbtAddress; +import jcifs.util.*; +import jcifs.smb.*; +import jcifs.util.Log; +import java.util.Date; + +public class Break implements AuthHandler { + + public Break( String[] argv ) throws Exception { + SmbFile.setAuthHandler( this ); + System.out.println( "listed " + (new SmbFile( argv[0] ).listFiles()).length + " files" ); + } + + public boolean authenticate( AuthInfo authInfo ) { + authInfo.domain = "mydom"; + authInfo.username = "miallen"; + authInfo.password = "wwcWww"; + System.out.println( authInfo.exception.getMessage() + ", trying new credentials" ); + return true; + } + + + public static void main( String[] argv ) throws Exception { + for( int i = 0; i < 10; i++ ) { + new Break( argv ); + Thread.sleep( 4000 ); + } + } +} diff --git a/examples/CallNamedPipe.java b/examples/CallNamedPipe.java index a8e584d..1d97ae2 100644 --- a/examples/CallNamedPipe.java +++ b/examples/CallNamedPipe.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbNamedPipe; import java.io.InputStream; import java.io.OutputStream; diff --git a/examples/CifsTime.java b/examples/CifsTime.java index 7869752..7755f12 100644 --- a/examples/CifsTime.java +++ b/examples/CifsTime.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import java.util.Date; import java.util.TimeZone; diff --git a/examples/CopyTo.java b/examples/CopyTo.java new file mode 100644 index 0000000..a4fdc42 --- /dev/null +++ b/examples/CopyTo.java @@ -0,0 +1,12 @@ +import jcifs.smb.SmbFile; + +public class CopyTo { + + public static void main( String argv[] ) throws Exception { + + SmbFile from = new SmbFile( argv[0] ); + SmbFile to = new SmbFile( argv[1] ); + from.copyTo( to ); + } +} + diff --git a/examples/CopyTo5.java b/examples/CopyTo5.java new file mode 100644 index 0000000..cd4f635 --- /dev/null +++ b/examples/CopyTo5.java @@ -0,0 +1,34 @@ +import jcifs.smb.SmbFile; + +public class CopyTo5 { + + public static void main( String argv[] ) throws Exception { + if( argv.length < 7 ) { + System.err.println( "CopyTo " ); + System.exit( 1 ); + } + SmbFile srcdir = new SmbFile( argv[0] ); + SmbFile dstdir = new SmbFile( argv[1] ); + + SmbFile sf1 = new SmbFile( srcdir, argv[2] ); + SmbFile df1 = new SmbFile( dstdir, argv[2] ); + sf1.copyTo( df1 ); + + SmbFile sf2 = new SmbFile( srcdir, argv[3] ); + SmbFile df2 = new SmbFile( dstdir, argv[3] ); + sf2.copyTo( df2 ); + + SmbFile sf3 = new SmbFile( srcdir, argv[4] ); + SmbFile df3 = new SmbFile( dstdir, argv[4] ); + sf3.copyTo( df3 ); + + SmbFile sf4 = new SmbFile( srcdir, argv[5] ); + SmbFile df4 = new SmbFile( dstdir, argv[5] ); + sf4.copyTo( df4 ); + + SmbFile sf5 = new SmbFile( srcdir, argv[6] ); + SmbFile df5 = new SmbFile( dstdir, argv[6] ); + sf5.copyTo( df5 ); + } +} + diff --git a/examples/CrawlerBench.java b/examples/CrawlerBench.java deleted file mode 100644 index 12e60bb..0000000 --- a/examples/CrawlerBench.java +++ /dev/null @@ -1,116 +0,0 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -import jcifs.smb.SmbFile; -import jcifs.util.Log; -import java.util.LinkedList; -import java.util.ListIterator; -import java.net.MalformedURLException; -import java.io.*; - -public class CrawlerBench { - - static long time; - - class DirEntry { - SmbFile dir; - int depth; - - DirEntry( SmbFile dir, int depth ) { - this.dir = dir; - this.depth = depth; - } - } - - class SmbCrawlerThread extends Thread { - - StringBuffer sb = new StringBuffer(); - - SmbCrawlerThread() { - } - - public void run() { - try { - Thread.sleep( 5000 ); - } catch( Exception e ) { - } - while( true ) { - try { - DirEntry e; - - synchronized( dirList ) { - while( dirList.isEmpty() ) { - dirList.wait( 500 ); - } - e = (DirEntry)dirList.remove( 0 ); - } - - if( e.depth == 0 ) { - continue; - } - - String[] l = e.dir.list(); - - int n = maxDepth - e.depth; - - for(int i = 0; l != null && i < l.length; i++ ) { - try { - sb.setLength( 0 ); - for( int k = 0; k < n; k++ ) { - // sb.append( " " ); - } - SmbFile d = new SmbFile( e.dir, l[i] ); - // System.out.println( sb.append( d )); - if( d.isDirectory() ) { - synchronized( dirList ) { - dirList.add( new DirEntry( d, e.depth - 1 )); - dirList.notify(); - } - } - } catch( IOException ioe ) { - } - } - } catch( Exception x ) { - } - } - } - } - - LinkedList dirList; - int maxDepth; - - CrawlerBench( String dir, int maxDepth, int numThreads ) throws Exception { - this.maxDepth = maxDepth; - dirList = new LinkedList(); - dirList.add( new DirEntry( new SmbFile( dir ), maxDepth )); - for( int i = 0; i < numThreads; i++ ) { - (new SmbCrawlerThread()).start(); - } - } - - public static void main(String[] argv) throws Exception { - if( argv.length < 3 ) { - System.out.println( "usage: CrawlerBench dir depth numThreads" ); - return; - } - System.out.print( "Hit Enter when ready." ); - System.in.read(); - - new CrawlerBench( argv[0], Integer.parseInt( argv[1] ), Integer.parseInt( argv[2] )); - } -} diff --git a/examples/CreateFile.java b/examples/CreateFile.java index 1dfc624..a1394e4 100644 --- a/examples/CreateFile.java +++ b/examples/CreateFile.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFileOutputStream; public class CreateFile { diff --git a/examples/Delete.java b/examples/Delete.java index 8aea63e..8124539 100644 --- a/examples/Delete.java +++ b/examples/Delete.java @@ -1,41 +1,11 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFile; import jcifs.smb.SmbException; public class Delete { public static void main( String argv[] ) throws Exception { - - long t0 = System.currentTimeMillis(); - SmbFile f = new SmbFile( argv[0] ); - try { - if( f.delete() ) { - System.out.println( f.getCanonicalPath() + " deleted " + ( System.currentTimeMillis() - t0 ) + "ms" ); - } else { - System.out.println( "Could not find " + f.getCanonicalPath() ); - } - } catch( SmbException se ) { - System.out.println( se.getMessage() ); - se.printStackTrace(); - } + f.delete(); } } diff --git a/examples/Exists.java b/examples/Exists.java index d6ddf61..009e210 100644 --- a/examples/Exists.java +++ b/examples/Exists.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFile; public class Exists { diff --git a/examples/FileOps.java b/examples/FileOps.java index bb64368..b582892 100644 --- a/examples/FileOps.java +++ b/examples/FileOps.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - /* Test the following file operations: * * canRead @@ -63,7 +45,7 @@ public class FileOps { } SmbFile s = new SmbFile( argv[0] ); - SmbFile d = new SmbFile( s, "JcifsTestOpsDir" ); + SmbFile d = new SmbFile( s, "JcifsTestOpsDir/" ); // delete - Delete the directory if it exists @@ -116,9 +98,9 @@ public class FileOps { 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( "fail - could not create file " + d + "foo.txt: " + ioe.getMessage() ); } - System.out.println( "okay - created file " + d + "/foo.txt" ); + System.out.println( "okay - created file " + d + "foo.txt" ); // canRead - Test to see if the new file can be read @@ -261,7 +243,7 @@ public class FileOps { System.out.println( "fail - length " + f + " is wrong: " + f.length() ); } - SmbFile r = new SmbFile( d.getParent(), "JcifsDeleteMe" ); + SmbFile r = new SmbFile( d.getParent(), "JcifsDeleteMe/" ); // Must delete any left over directory from a previous run @@ -285,9 +267,9 @@ public class FileOps { try { r.delete(); - System.out.println( "okay - delete " + d + " successfull" ); + System.out.println( "okay - delete " + r + " successfull" ); } catch( SmbException se ) { - System.out.println( "fail - delete " + d + " failed: " + se.getMessage() ); + System.out.println( "fail - delete " + r + " failed: " + se.getMessage() ); } } } diff --git a/examples/Format.java b/examples/Format.java new file mode 100644 index 0000000..941f726 --- /dev/null +++ b/examples/Format.java @@ -0,0 +1,562 @@ +/* + * Cay S. Horstmann & Gary Cornell, Core Java + * Published By Sun Microsystems Press/Prentice-Hall + * Copyright (C) 1997 Sun Microsystems Inc. + * All Rights Reserved. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for NON-COMMERCIAL purposes + * and without fee is hereby granted provided that this + * copyright notice appears in all copies. + * + * THE AUTHORS AND PUBLISHER MAKE NO REPRESENTATIONS OR + * WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE, EITHER + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE AUTHORS + * AND PUBLISHER SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED + * BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING + * THIS SOFTWARE OR ITS DERIVATIVES. + */ + +/** + * A class for formatting numbers that follows printf conventions. + * Also implements C-like atoi and atof functions + * @version 1.04 13 Sep 1998 + * @author Cay Horstmann + */ + +import java.io.*; + +public class Format + +{ /** + * Formats the number following printf conventions. + * Main limitation: Can only handle one format parameter at a time + * Use multiple Format objects to format more than one number + * @param s the format string following printf conventions + * The string has a prefix, a format code and a suffix. The prefix and suffix + * become part of the formatted output. The format code directs the + * formatting of the (single) parameter to be formatted. The code has the + * following structure + *
    + *
  • a % (required) + *
  • a modifier (optional) + *
    + *
    +
    forces display of + for positive numbers + *
    0
    show leading zeroes + *
    -
    align left in the field + *
    space
    prepend a space in front of positive numbers + *
    #
    use "alternate" format. Add 0 or 0x for octal or hexadecimal numbers. Don't suppress trailing zeroes in general floating point format. + *
    + *
  • an integer denoting field width (optional) + *
  • a period followed by an integer denoting precision (optional) + *
  • a format descriptor (required) + *
    + *
    f
    floating point number in fixed format + *
    e, E
    floating point number in exponential notation (scientific format). The E format results in an uppercase E for the exponent (1.14130E+003), the e format in a lowercase e. + *
    g, G
    floating point number in general format (fixed format for small numbers, exponential format for large numbers). Trailing zeroes are suppressed. The G format results in an uppercase E for the exponent (if any), the g format in a lowercase e. + *
    d, i
    integer in decimal + *
    x
    integer in hexadecimal + *
    o
    integer in octal + *
    s
    string + *
    c
    character + *
    + *
+ * @exception IllegalArgumentException if bad format + */ + + public Format(String s) + { width = 0; + precision = -1; + pre = ""; + post = ""; + leading_zeroes = false; + show_plus = false; + alternate = false; + show_space = false; + left_align = false; + fmt = ' '; + + int state = 0; + int length = s.length(); + int parse_state = 0; + // 0 = prefix, 1 = flags, 2 = width, 3 = precision, + // 4 = format, 5 = end + int i = 0; + + while (parse_state == 0) + { if (i >= length) parse_state = 5; + else if (s.charAt(i) == '%') + { if (i < length - 1) + { if (s.charAt(i + 1) == '%') + { pre = pre + '%'; + i++; + } + else + parse_state = 1; + } + else throw new java.lang.IllegalArgumentException(); + } + else + pre = pre + s.charAt(i); + i++; + } + while (parse_state == 1) + { if (i >= length) parse_state = 5; + else if (s.charAt(i) == ' ') show_space = true; + else if (s.charAt(i) == '-') left_align = true; + else if (s.charAt(i) == '+') show_plus = true; + else if (s.charAt(i) == '0') leading_zeroes = true; + else if (s.charAt(i) == '#') alternate = true; + else { parse_state = 2; i--; } + i++; + } + while (parse_state == 2) + { if (i >= length) parse_state = 5; + else if ('0' <= s.charAt(i) && s.charAt(i) <= '9') + { width = width * 10 + s.charAt(i) - '0'; + i++; + } + else if (s.charAt(i) == '.') + { parse_state = 3; + precision = 0; + i++; + } + else + parse_state = 4; + } + while (parse_state == 3) + { if (i >= length) parse_state = 5; + else if ('0' <= s.charAt(i) && s.charAt(i) <= '9') + { precision = precision * 10 + s.charAt(i) - '0'; + i++; + } + else + parse_state = 4; + } + if (parse_state == 4) + { if (i >= length) parse_state = 5; + else fmt = s.charAt(i); + i++; + } + if (i < length) + post = s.substring(i, length); + } + + /** + * prints a formatted number following printf conventions + * @param s a PrintStream + * @param fmt the format string + * @param x the double to print + */ + + public static void print(java.io.PrintStream s, String fmt, double x) + { s.print(new Format(fmt).form(x)); + } + + /** + * prints a formatted number following printf conventions + * @param s a PrintStream + * @param fmt the format string + * @param x the long to print + */ + public static void print(java.io.PrintStream s, String fmt, long x) + { s.print(new Format(fmt).form(x)); + } + + /** + * prints a formatted number following printf conventions + * @param s a PrintStream + * @param fmt the format string + * @param x the character to + */ + + public static void print(java.io.PrintStream s, String fmt, char x) + { s.print(new Format(fmt).form(x)); + } + + /** + * prints a formatted number following printf conventions + * @param s a PrintStream, fmt the format string + * @param x a string that represents the digits to print + */ + + public static void print(java.io.PrintStream s, String fmt, String x) + { s.print(new Format(fmt).form(x)); + } + + /** + * Converts a string of digits (decimal, octal or hex) to an integer + * @param s a string + * @return the numeric value of the prefix of s representing a base 10 integer + */ + + public static int atoi(String s) + { return (int)atol(s); + } + + /** + * Converts a string of digits (decimal, octal or hex) to a long integer + * @param s a string + * @return the numeric value of the prefix of s representing a base 10 integer + */ + + public static long atol(String s) + { int i = 0; + + while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++; + if (i < s.length() && s.charAt(i) == '0') + { if (i + 1 < s.length() && (s.charAt(i + 1) == 'x' || s.charAt(i + 1) == 'X')) + return parseLong(s.substring(i + 2), 16); + else return parseLong(s, 8); + } + else return parseLong(s, 10); + } + + private static long parseLong(String s, int base) + { int i = 0; + int sign = 1; + long r = 0; + + while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++; + if (i < s.length() && s.charAt(i) == '-') { sign = -1; i++; } + else if (i < s.length() && s.charAt(i) == '+') { i++; } + while (i < s.length()) + { char ch = s.charAt(i); + if ('0' <= ch && ch < '0' + base) + r = r * base + ch - '0'; + else if ('A' <= ch && ch < 'A' + base - 10) + r = r * base + ch - 'A' + 10 ; + else if ('a' <= ch && ch < 'a' + base - 10) + r = r * base + ch - 'a' + 10 ; + else + return r * sign; + i++; + } + return r * sign; + } + + /** + * Converts a string of digits to an double + * @param s a string + */ + + public static double atof(String s) + { int i = 0; + int sign = 1; + double r = 0; // integer part + double f = 0; // fractional part + double p = 1; // exponent of fractional part + int state = 0; // 0 = int part, 1 = frac part + + while (i < s.length() && Character.isWhitespace(s.charAt(i))) i++; + if (i < s.length() && s.charAt(i) == '-') { sign = -1; i++; } + else if (i < s.length() && s.charAt(i) == '+') { i++; } + while (i < s.length()) + { char ch = s.charAt(i); + if ('0' <= ch && ch <= '9') + { if (state == 0) + r = r * 10 + ch - '0'; + else if (state == 1) + { p = p / 10; + r = r + p * (ch - '0'); + } + } + else if (ch == '.') + { if (state == 0) state = 1; + else return sign * r; + } + else if (ch == 'e' || ch == 'E') + { long e = (int)parseLong(s.substring(i + 1), 10); + return sign * r * Math.pow(10, e); + } + else return sign * r; + i++; + } + return sign * r; + } + + /** + * Formats a double into a string (like sprintf in C) + * @param x the number to format + * @return the formatted string + * @exception IllegalArgumentException if bad argument + */ + + public String form(double x) + { String r; + if (precision < 0) precision = 6; + int s = 1; + if (x < 0) { x = -x; s = -1; } + if (fmt == 'f') + r = fixed_format(x); + else if (fmt == 'e' || fmt == 'E' || fmt == 'g' || fmt == 'G') + r = exp_format(x); + else throw new java.lang.IllegalArgumentException(); + + return pad(sign(s, r)); + } + + /** + * Formats a long integer into a string (like sprintf in C) + * @param x the number to format + * @return the formatted string + */ + + public String form(long x) + { String r; + int s = 0; + if (fmt == 'd' || fmt == 'i') + { if (x < 0) + { r = ("" + x).substring(1); + s = -1; + } + else + { r = "" + x; + s = 1; + } + } + else if (fmt == 'o') + r = convert(x, 3, 7, "01234567"); + else if (fmt == 'x') + r = convert(x, 4, 15, "0123456789abcdef"); + else if (fmt == 'X') + r = convert(x, 4, 15, "0123456789ABCDEF"); + else throw new java.lang.IllegalArgumentException(); + + return pad(sign(s, r)); + } + + /** + * Formats a character into a string (like sprintf in C) + * @param x the value to format + * @return the formatted string + */ + + public String form(char c) + { if (fmt != 'c') + throw new java.lang.IllegalArgumentException(); + + String r = "" + c; + return pad(r); + } + + /** + * Formats a string into a larger string (like sprintf in C) + * @param x the value to format + * @return the formatted string + */ + + public String form(String s) + { if (fmt != 's') + throw new java.lang.IllegalArgumentException(); + if (precision >= 0 && precision < s.length()) + s = s.substring(0, precision); + return pad(s); + } + + + /** + * a test stub for the format class + */ + + public static void main(String[] a) + { double x = 1.23456789012; + double y = 123; + double z = 1.2345e30; + double w = 1.02; + double u = 1.234e-5; + int d = 0xCAFE; + Format.print(System.out, "x = |%f|\n", x); + Format.print(System.out, "u = |%20f|\n", u); + Format.print(System.out, "x = |% .5f|\n", x); + Format.print(System.out, "w = |%20.5f|\n", w); + Format.print(System.out, "x = |%020.5f|\n", x); + Format.print(System.out, "x = |%+20.5f|\n", x); + Format.print(System.out, "x = |%+020.5f|\n", x); + Format.print(System.out, "x = |% 020.5f|\n", x); + Format.print(System.out, "y = |%#+20.5f|\n", y); + Format.print(System.out, "y = |%-+20.5f|\n", y); + Format.print(System.out, "z = |%20.5f|\n", z); + + Format.print(System.out, "x = |%e|\n", x); + Format.print(System.out, "u = |%20e|\n", u); + Format.print(System.out, "x = |% .5e|\n", x); + Format.print(System.out, "w = |%20.5e|\n", w); + Format.print(System.out, "x = |%020.5e|\n", x); + Format.print(System.out, "x = |%+20.5e|\n", x); + Format.print(System.out, "x = |%+020.5e|\n", x); + Format.print(System.out, "x = |% 020.5e|\n", x); + Format.print(System.out, "y = |%#+20.5e|\n", y); + Format.print(System.out, "y = |%-+20.5e|\n", y); + + Format.print(System.out, "x = |%g|\n", x); + Format.print(System.out, "z = |%g|\n", z); + Format.print(System.out, "w = |%g|\n", w); + Format.print(System.out, "u = |%g|\n", u); + Format.print(System.out, "y = |%.2g|\n", y); + Format.print(System.out, "y = |%#.2g|\n", y); + + Format.print(System.out, "d = |%d|\n", d); + Format.print(System.out, "d = |%20d|\n", d); + Format.print(System.out, "d = |%020d|\n", d); + Format.print(System.out, "d = |%+20d|\n", d); + Format.print(System.out, "d = |% 020d|\n", d); + Format.print(System.out, "d = |%-20d|\n", d); + Format.print(System.out, "d = |%20.8d|\n", d); + Format.print(System.out, "d = |%x|\n", d); + Format.print(System.out, "d = |%20X|\n", d); + Format.print(System.out, "d = |%#20x|\n", d); + Format.print(System.out, "d = |%020X|\n", d); + Format.print(System.out, "d = |%20.8x|\n", d); + Format.print(System.out, "d = |%o|\n", d); + Format.print(System.out, "d = |%020o|\n", d); + Format.print(System.out, "d = |%#20o|\n", d); + Format.print(System.out, "d = |%#020o|\n", d); + Format.print(System.out, "d = |%20.12o|\n", d); + + Format.print(System.out, "s = |%-20s|\n", "Hello"); + Format.print(System.out, "s = |%-20c|\n", '!'); + + // regression test to confirm fix of reported bugs + + Format.print(System.out, "|%i|\n", Long.MIN_VALUE); + + Format.print(System.out, "|%6.2e|\n", 0.0); + Format.print(System.out, "|%6.2g|\n", 0.0); + + Format.print(System.out, "|%6.2f|\n", 9.99); + Format.print(System.out, "|%6.2f|\n", 9.999); + + Format.print(System.out, "|%6.0f|\n", 9.999); + } + + private static String repeat(char c, int n) + { if (n <= 0) return ""; + StringBuffer s = new StringBuffer(n); + for (int i = 0; i < n; i++) s.append(c); + return s.toString(); + } + + private static String convert(long x, int n, int m, String d) + { if (x == 0) return "0"; + String r = ""; + while (x != 0) + { r = d.charAt((int)(x & m)) + r; + x = x >>> n; + } + return r; + } + + private String pad(String r) + { String p = repeat(' ', width - r.length()); + if (left_align) return pre + r + p + post; + else return pre + p + r + post; + } + + private String sign(int s, String r) + { String p = ""; + if (s < 0) p = "-"; + else if (s > 0) + { if (show_plus) p = "+"; + else if (show_space) p = " "; + } + else + { if (fmt == 'o' && alternate && r.length() > 0 && r.charAt(0) != '0') p = "0"; + else if (fmt == 'x' && alternate) p = "0x"; + else if (fmt == 'X' && alternate) p = "0X"; + } + int w = 0; + if (leading_zeroes) + w = width; + else if ((fmt == 'd' || fmt == 'i' || fmt == 'x' || fmt == 'X' || fmt == 'o') + && precision > 0) w = precision; + + return p + repeat('0', w - p.length() - r.length()) + r; + } + + private String fixed_format(double d) + { boolean removeTrailing + = (fmt == 'G' || fmt == 'g') && !alternate; + // remove trailing zeroes and decimal point + + if (d > 0x7FFFFFFFFFFFFFFFL) return exp_format(d); + if (precision == 0) + return (long)(d + 0.5) + (removeTrailing ? "" : "."); + + long whole = (long)d; + double fr = d - whole; // fractional part + if (fr >= 1 || fr < 0) return exp_format(d); + + double factor = 1; + String leading_zeroes = ""; + for (int i = 1; i <= precision && factor <= 0x7FFFFFFFFFFFFFFFL; i++) + { factor *= 10; + leading_zeroes = leading_zeroes + "0"; + } + long l = (long) (factor * fr + 0.5); + if (l >= factor) { l = 0; whole++; } // CSH 10-25-97 + + String z = leading_zeroes + l; + z = "." + z.substring(z.length() - precision, z.length()); + + if (removeTrailing) + { int t = z.length() - 1; + while (t >= 0 && z.charAt(t) == '0') t--; + if (t >= 0 && z.charAt(t) == '.') t--; + z = z.substring(0, t + 1); + } + + return whole + z; + } + + private String exp_format(double d) + { String f = ""; + int e = 0; + double dd = d; + double factor = 1; + if (d != 0) + { while (dd > 10) { e++; factor /= 10; dd = dd / 10; } + while (dd < 1) { e--; factor *= 10; dd = dd * 10; } + } + if ((fmt == 'g' || fmt == 'G') && e >= -4 && e < precision) + return fixed_format(d); + + d = d * factor; + f = f + fixed_format(d); + + if (fmt == 'e' || fmt == 'g') + f = f + "e"; + else + f = f + "E"; + + String p = "000"; + if (e >= 0) + { f = f + "+"; + p = p + e; + } + else + { f = f + "-"; + p = p + (-e); + } + + return f + p.substring(p.length() - 3, p.length()); + } + + private int width; + private int precision; + private String pre; + private String post; + private boolean leading_zeroes; + private boolean show_plus; + private boolean alternate; + private boolean show_space; + private boolean left_align; + private char fmt; // one of cdeEfgGiosxXos +} + + + + + diff --git a/examples/Get.java b/examples/Get.java index 0b18b30..0ed1621 100644 --- a/examples/Get.java +++ b/examples/Get.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFile; import jcifs.smb.SmbFileInputStream; import java.io.FileOutputStream; @@ -30,17 +12,13 @@ public class Get { long t0 = System.currentTimeMillis(); - byte[] b = new byte[65535]; + byte[] b = new byte[8192]; int n, tot = 0; long t1 = t0; - long t2; while(( n = in.read( b )) > 0 ) { out.write( b, 0, n ); tot += n; System.out.print( '#' ); - t2 = System.currentTimeMillis(); - System.out.print( t2 - t1 + "" ); - t1 = t2; } long t = System.currentTimeMillis() - t0; diff --git a/examples/GetDate.java b/examples/GetDate.java index 9ccbc9b..edcb26a 100644 --- a/examples/GetDate.java +++ b/examples/GetDate.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import java.util.Date; import jcifs.smb.SmbFile; import java.text.SimpleDateFormat; diff --git a/examples/GetType.java b/examples/GetType.java new file mode 100644 index 0000000..b3619c1 --- /dev/null +++ b/examples/GetType.java @@ -0,0 +1,54 @@ +import jcifs.netbios.NbtAddress; +import jcifs.smb.SmbFile; +import jcifs.util.Log; +import java.util.Date; + +public class GetType { + + static final String[] types = { "TYPE_FILESYSTEM", "TYPE_WORKGROUP", + "TYPE_SERVER", "TYPE_SHARE", "TYPE_NAMED_PIPE", "TYPE_PRINTER", "TYPE_COMM" }; + + public static void main( String[] argv ) throws Exception { + + SmbFile file = new SmbFile( argv[0] ); + int type; + + switch( file.getType() ) { + case SmbFile.TYPE_FILESYSTEM: + type = 0; + break; + case SmbFile.TYPE_WORKGROUP: + type = 1; + break; + case SmbFile.TYPE_SERVER: + type = 2; + break; + case SmbFile.TYPE_SHARE: + type = 3; + break; + case SmbFile.TYPE_NAMED_PIPE: + type = 4; + break; + case SmbFile.TYPE_PRINTER: + type = 5; + break; + case SmbFile.TYPE_COMM: + type = 6; + break; + default: + throw new RuntimeException( "Unknown service type: " + file.getType() ); + } + System.out.println( types[type] ); + System.out.println(); + + long t1 = System.currentTimeMillis(); + String[] files = file.list(); + long t2 = System.currentTimeMillis() - t1; + + for( int i = 0; i < files.length; i++ ) { + System.out.print( " " + files[i] ); + } + System.out.println(); + System.out.println( files.length + " files in " + t2 + "ms" ); + } +} diff --git a/examples/GetURL.java b/examples/GetURL.java index 0ba6317..c93b2b4 100644 --- a/examples/GetURL.java +++ b/examples/GetURL.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import java.net.URL; import java.io.InputStream; @@ -25,7 +7,7 @@ public class GetURL { System.in.read(); - Class.forName( "jcifs.Config" ); + jcifs.Config.registerSmbURLHandler(); URL url = new URL( argv[0] ); InputStream in = url.openStream(); diff --git a/examples/GrowWrite.java b/examples/GrowWrite.java new file mode 100644 index 0000000..70ba4d4 --- /dev/null +++ b/examples/GrowWrite.java @@ -0,0 +1,30 @@ +import jcifs.smb.SmbFile; +import jcifs.smb.SmbFileOutputStream; +import java.io.FileInputStream; + +public class GrowWrite { + + static final int SIZE = 0x4FFF; + + public static void main( String argv[] ) throws Exception { + int n, tot; + byte[] buf = new byte[SIZE]; + SmbFile f = new SmbFile( argv[0] ); + SmbFileOutputStream out = new SmbFileOutputStream( f ); + + n = tot = 0; + do { + if(( n % 0x1F ) == 0) { + f = new SmbFile( argv[0] ); + out = new SmbFileOutputStream( f ); + System.out.print( '#' ); + } + out.write( buf, 0, n ); + out.flush(); + tot += n; + } while( n++ < SIZE ); + + System.out.println(); + System.out.println( tot + " bytes transfered." ); + } +} diff --git a/examples/Interleave.java b/examples/Interleave.java index 3fc9fd9..7378ce2 100644 --- a/examples/Interleave.java +++ b/examples/Interleave.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.*; public class Interleave { diff --git a/examples/IsDir.java b/examples/IsDir.java index 273a4e9..030703b 100644 --- a/examples/IsDir.java +++ b/examples/IsDir.java @@ -1,28 +1,11 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.util.Log; import jcifs.smb.SmbFile; public class IsDir { public static void main( String argv[] ) throws Exception { - (new SmbFile( argv[0] )).isDirectory(); + SmbFile f = new SmbFile( argv[0] ); + System.out.println( f.isDirectory() ); } } diff --git a/examples/Length.java b/examples/Length.java index 152a8b6..910faaa 100644 --- a/examples/Length.java +++ b/examples/Length.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFile; public class Length { diff --git a/examples/List.java b/examples/List.java index 56c15a1..98dcf43 100644 --- a/examples/List.java +++ b/examples/List.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.netbios.NbtAddress; import jcifs.smb.SmbFile; import jcifs.util.Log; @@ -31,14 +13,10 @@ public class List { String[] files = file.list(); long t2 = System.currentTimeMillis() - t1; - if( files != null ) { - for( int i = 0; i < files.length; i++ ) { - System.out.print( " " + files[i] ); - } - System.out.println(); - System.out.println( files.length + " files in " + t2 + "ms" ); - } else { - System.out.println( "no such file or directory" ); + for( int i = 0; i < files.length; i++ ) { + System.out.print( " " + files[i] ); } + System.out.println(); + System.out.println( files.length + " files in " + t2 + "ms" ); } } diff --git a/examples/ListFiles.java b/examples/ListFiles.java new file mode 100644 index 0000000..1af0c27 --- /dev/null +++ b/examples/ListFiles.java @@ -0,0 +1,22 @@ +import jcifs.netbios.NbtAddress; +import jcifs.smb.SmbFile; +import jcifs.util.Log; +import java.util.Date; + +public class ListFiles { + + public static void main( String[] argv ) throws Exception { + + SmbFile file = new SmbFile( argv[0] ); + + long t1 = System.currentTimeMillis(); + SmbFile[] files = file.listFiles(); + 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" ); + } +} diff --git a/examples/ListTypes.java b/examples/ListTypes.java new file mode 100644 index 0000000..f060728 --- /dev/null +++ b/examples/ListTypes.java @@ -0,0 +1,44 @@ +import jcifs.netbios.NbtAddress; +import jcifs.smb.SmbFile; +import jcifs.util.Log; +import java.util.Date; + +public class ListTypes { + + public static void main( String[] argv ) throws Exception { + + SmbFile file = new SmbFile( argv[0] ); + + long t1 = System.currentTimeMillis(); + SmbFile[] files = file.listFiles(); + long t2 = System.currentTimeMillis() - t1; + + for( int i = 0; i < files.length; i++ ) { + System.out.print( " " + files[i].getName() ); + switch(files[i].getType()) { + case SmbFile.TYPE_FILESYSTEM: + System.out.println( "[TYPE_FILESYSTEM]" ); + break; + case SmbFile.TYPE_WORKGROUP: + System.out.println( "[TYPE_WORKGROUP]" ); + break; + case SmbFile.TYPE_SERVER: + System.out.println( "[TYPE_SERVER]" ); + break; + case SmbFile.TYPE_SHARE: + System.out.println( "[TYPE_SHARE]" ); + break; + case SmbFile.TYPE_NAMED_PIPE: + System.out.println( "[TYPE_NAMEDPIPE]" ); + break; + case SmbFile.TYPE_PRINTER: + System.out.println( "[TYPE_PRINTER]" ); + break; + case SmbFile.TYPE_COMM: + System.out.println( "[TYPE_COMM]" ); + break; + }; + } + System.out.println( files.length + " files in " + t2 + "ms" ); + } +} diff --git a/examples/LogTest.java b/examples/LogTest.java index 6fb3eac..5af77cc 100644 --- a/examples/LogTest.java +++ b/examples/LogTest.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.util.Log; public class LogTest { diff --git a/examples/LogonTest.java b/examples/LogonTest.java new file mode 100644 index 0000000..57b9bd7 --- /dev/null +++ b/examples/LogonTest.java @@ -0,0 +1,17 @@ +import jcifs.UniAddress; +import jcifs.smb.SmbSession; +import jcifs.smb.NtlmPasswordAuthentication; + +public class LogonTest { + + public static void main( String argv[] ) throws Exception { + UniAddress dc = UniAddress.getByName( "miallen2" ); + NtlmPasswordAuthentication good = new NtlmPasswordAuthentication( "mlamrs", "miallen", "ru_RUhrd" ); + NtlmPasswordAuthentication bad = new NtlmPasswordAuthentication( "mlamrs", "miallen", "bogus" ); + SmbSession.logon( dc, good ); + System.out.println( "good" ); + SmbSession.logon( dc, bad ); + System.out.println( "bad" ); + } +} + diff --git a/examples/Mkdir.java b/examples/Mkdir.java index 310a2fa..56732e3 100644 --- a/examples/Mkdir.java +++ b/examples/Mkdir.java @@ -1,32 +1,10 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.util.Log; import jcifs.smb.SmbFile; public class Mkdir { - public static void main( String argv[] ) { - try { - (new SmbFile( argv[0] )).mkdir(); - } catch( Exception e ) { - e.printStackTrace(); - } + public static void main( String argv[] ) throws Exception { + (new SmbFile( argv[0] )).mkdir(); } } diff --git a/examples/NodeStatus.java b/examples/NodeStatus.java new file mode 100644 index 0000000..47b26b8 --- /dev/null +++ b/examples/NodeStatus.java @@ -0,0 +1,11 @@ +import jcifs.netbios.NbtAddress; + +public class NodeStatus { + + public static void main( String argv[] ) throws Exception { + NbtAddress[] addrs = NbtAddress.getAllByAddress( argv[0] ); + for( int i = 0; i < addrs.length; i++ ) { + System.out.println( addrs[i] ); + } + } +} diff --git a/examples/NtlmHttpAuthExample.java b/examples/NtlmHttpAuthExample.java new file mode 100644 index 0000000..1107439 --- /dev/null +++ b/examples/NtlmHttpAuthExample.java @@ -0,0 +1,32 @@ +import java.io.*; +import javax.servlet.*; +import javax.servlet.http.*; + +public class NtlmHttpAuthExample extends HttpServlet { + + public void doGet( HttpServletRequest req, + HttpServletResponse resp ) throws IOException, ServletException { + PrintWriter out = resp.getWriter(); + + resp.setContentType( "text/html" ); + out.println( "NTLM HTTP Authentication Example" ); + out.println( "

NTLM HTTP Authentication Example

" ); + + out.println( req.getRemoteUser() + " successfully logged in" ); + + out.println( "

Please submit some form data using POST

" ); + out.println( "
" ); + out.println( "" ); + out.println( "" ); + out.println( "
" ); + + out.println( "field1 = " + req.getParameter( "field1" )); + + out.println( "" ); + } + public void doPost( HttpServletRequest req, + HttpServletResponse resp ) throws IOException, ServletException { + doGet( req, resp ); + } +} + diff --git a/examples/OpenExclusive.java b/examples/OpenExclusive.java new file mode 100644 index 0000000..33e82a6 --- /dev/null +++ b/examples/OpenExclusive.java @@ -0,0 +1,20 @@ +import jcifs.smb.SmbFile; +import jcifs.smb.SmbFileOutputStream; + +public class OpenExclusive { + + public static void main( String argv[] ) throws Exception { + SmbFileOutputStream out; + SmbFile f = new SmbFile( argv[0], "", null, SmbFile.FILE_NO_SHARE ); + out = new SmbFileOutputStream( f ); +System.in.read(); + out.close(); +System.in.read(); +// OR + out = new SmbFileOutputStream( argv[1], SmbFile.FILE_NO_SHARE ); +System.in.read(); + out.close(); +System.in.read(); + } +} + diff --git a/examples/PeekNamedPipe.java b/examples/PeekNamedPipe.java new file mode 100644 index 0000000..463e533 --- /dev/null +++ b/examples/PeekNamedPipe.java @@ -0,0 +1,64 @@ +import jcifs.smb.SmbNamedPipe; +import java.io.OutputStream; +import java.io.InputStream; +import java.io.IOException; + +public class PeekNamedPipe { + + static class ReceiverThread extends Thread { + InputStream in; + byte[] buf = new byte[20]; + int n; + + ReceiverThread( InputStream in ) { + this.in = in; + } + public void run() { + try { + while( true ) { + while(( n = in.available() ) == 0 ) { + System.out.println( "0 available" ); + sleep( 3000 ); + } + System.out.println( n + " available" ); + + if(( n = in.read( buf )) == -1 ) { + break; + } + System.out.println( new String( buf, 0, n )); + } + } catch( Exception e ) { + e.printStackTrace(); + } + System.out.println( "run finished" ); + } + } + + public static void main( String[] argv ) throws Exception { + SmbNamedPipe pipe = new SmbNamedPipe( argv[0], SmbNamedPipe.PIPE_TYPE_RDWR ); + InputStream in = pipe.getNamedPipeInputStream(); + OutputStream out = pipe.getNamedPipeOutputStream(); + + ReceiverThread rt = new ReceiverThread( in ); + rt.start(); + + StringBuffer sb = new StringBuffer(); + String msg; + int c; + while(( c = System.in.read() ) != -1 ) { + if( c == '\n' ) { + msg = sb.toString(); + if( msg.startsWith( "exi" )) { + break; + } + out.write( msg.getBytes() ); + sb.setLength( 0 ); + } else { + sb.append( (char)c ); + } + } + in.close(); + out.close(); + } +} + diff --git a/examples/PipeTalk.java b/examples/PipeTalk.java index 0dc3408..a5fe346 100644 --- a/examples/PipeTalk.java +++ b/examples/PipeTalk.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbNamedPipe; import java.io.OutputStream; import java.io.InputStream; diff --git a/examples/Put.java b/examples/Put.java index 4317c4f..7876329 100644 --- a/examples/Put.java +++ b/examples/Put.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFile; import jcifs.smb.SmbFileOutputStream; import java.io.FileInputStream; @@ -30,7 +12,7 @@ public class Put { long t0 = System.currentTimeMillis(); - byte[] b = new byte[65535]; + byte[] b = new byte[8192]; int n, tot = 0; while(( n = in.read( b )) > 0 ) { out.write( b, 0, n ); diff --git a/examples/Query.java b/examples/Query.java index 8910ce8..9889c77 100644 --- a/examples/Query.java +++ b/examples/Query.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.netbios.NbtAddress; import jcifs.UniAddress; import java.net.InetAddress; diff --git a/examples/README.txt b/examples/README.txt deleted file mode 100644 index fc40721..0000000 --- a/examples/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -Many of these examples are quite wrong now that SmbFile methods throw -SmbException. They will be cleaned up before 0.6 final. diff --git a/examples/RenameTo.java b/examples/RenameTo.java index 91ffd3c..13e26c8 100644 --- a/examples/RenameTo.java +++ b/examples/RenameTo.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFile; public class RenameTo { diff --git a/examples/SlowRead.java b/examples/SlowRead.java index 7c297ce..4d97386 100644 --- a/examples/SlowRead.java +++ b/examples/SlowRead.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFile; import jcifs.smb.SmbFileInputStream; import java.io.FileOutputStream; diff --git a/examples/SlowWrite.java b/examples/SlowWrite.java index 3d4c38a..cdd8e80 100644 --- a/examples/SlowWrite.java +++ b/examples/SlowWrite.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFileOutputStream; public class SlowWrite { diff --git a/examples/SmbCrawler.java b/examples/SmbCrawler.java index 3409868..989b853 100644 --- a/examples/SmbCrawler.java +++ b/examples/SmbCrawler.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbFile; import java.util.LinkedList; import java.util.ListIterator; @@ -36,17 +18,16 @@ public class SmbCrawler { return; } - String[] l = f.list(); + SmbFile[] l = f.listFiles(); for(int i = 0; l != null && i < l.length; i++ ) { try { - SmbFile d = new SmbFile( f, l[i] ); for( int j = maxDepth - depth; j > 0; j-- ) { System.out.print( " " ); } - System.out.println( l[i] ); - if( d.isDirectory() ) { - traverse( d, depth - 1 ); + System.out.println( l[i] + " " + l[i].exists() ); + if( l[i].isDirectory() ) { + traverse( l[i], depth - 1 ); } } catch( IOException ioe ) { System.out.println( l[i] + ": " + ioe.getMessage() ); diff --git a/examples/SmbShell.java b/examples/SmbShell.java index ddcdf25..7d6d3c2 100644 --- a/examples/SmbShell.java +++ b/examples/SmbShell.java @@ -1,5 +1,5 @@ /* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" + * Copyright (C) 2000 "Michael B. Allen" * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,12 +17,37 @@ */ import jcifs.smb.*; -import jcifs.util.AuthHandler; -import jcifs.util.AuthInfo; import java.net.UnknownHostException; import java.net.MalformedURLException; +import java.util.GregorianCalendar; +import java.text.SimpleDateFormat; +import java.util.Date; -public class SmbShell implements AuthHandler { +public class SmbShell extends NtlmAuthenticator { + + protected NtlmPasswordAuthentication getNtlmPasswordAuthentication() { + System.out.println( getRequestingException().getMessage() + + " for " + getRequestingURL() ); + System.out.print( "username: " ); + try { + int i; + String username = readLine(); + String domain = null, password; + + if(( i = username.indexOf( '\\' )) != -1 ) { + domain = username.substring( 0, i ); + username = username.substring( i + 1 ); + } + System.out.print( "password: " ); + password = readLine(); + if( password.length() == 0 ) { + return null; + } + return new NtlmPasswordAuthentication( domain, username, password ); + } catch( Exception e ) { + } + return null; + } public static String readLine() throws Exception { int c; @@ -34,40 +59,29 @@ public class SmbShell implements AuthHandler { return sb.toString().trim(); } - public boolean authenticate( AuthInfo authInfo ) { - System.out.println( authInfo.exception.getMessage() + " on " + authInfo.target + " as " + authInfo.domain + "\\" + authInfo.username ); - System.out.print( " user: " ); - int i; - try { - String user = readLine(); - if((i = user.indexOf( '\\' )) != -1 ) { - authInfo.domain = user.substring( 0, i ); - authInfo.username = user.substring( i + 1 ); - } else { - authInfo.username = user; - } - System.out.print( "password: " ); - authInfo.password = readLine(); - if( authInfo.password.length() > 0 ) { - return true; - } - } catch( Exception e ) { - } - return false; + String start; + + public SmbShell( String start ) { + this.start = start; + NtlmAuthenticator.setDefault( this ); } void run() throws Exception { int c; String cmd, prompt; SmbFile conn, tmp; + SimpleDateFormat sdf1 = new SimpleDateFormat( "EEE MMM" ); + SimpleDateFormat sdf2 = new SimpleDateFormat( "d" ); + SimpleDateFormat sdf3 = new SimpleDateFormat( "yyyy h:mm a" ); + sdf1.setCalendar( new GregorianCalendar() ); + sdf2.setCalendar( new GregorianCalendar() ); + sdf3.setCalendar( new GregorianCalendar() ); - SmbFile.setAuthHandler( this ); - - conn = new SmbFile( "smb://" ); + conn = new SmbFile( start ); while( true ) { try { if( conn.exists() ) { - prompt = new SmbFile( conn.getCanonicalPath() ).getName() + "> "; + prompt = conn.getName() + "> "; } else { System.out.println( "error reading " + conn ); conn = new SmbFile( "smb://" ); @@ -84,7 +98,7 @@ public class SmbShell implements AuthHandler { conn = new SmbFile( "smb://" ); continue; } - tmp = new SmbFile( conn.getCanonicalPath(), dir ); + tmp = new SmbFile( conn, dir ); if( tmp.exists() ) { if( tmp.isDirectory() ) { conn = tmp; @@ -97,17 +111,49 @@ public class SmbShell implements AuthHandler { } else if( cmd.startsWith( "ls" )) { int i = cmd.indexOf( ' ' ); SmbFile d = conn; - String dir; + String dir, wildcard = "*"; if( i != -1 && (dir = cmd.substring( i ).trim()).length() != 0 ) { - d = new SmbFile( conn, dir ); + // there's an argument which could be a directory, + // a wildcard, or a directory with a wildcard appended + int s = dir.lastIndexOf( '/' ); + int a = dir.lastIndexOf( '*' ); + int q = dir.lastIndexOf( '?' ); + + if(( a != -1 && a > s ) || ( q != -1 && q > s )) { + // it's a wildcard + if( s == -1 ) { + wildcard = dir; + d = conn; + } else { + wildcard = dir.substring( s + 1 ); + d = new SmbFile( conn, dir.substring( 0, s )); + } + } else { + d = new SmbFile( conn, dir ); + } } - String[] list = d.list(); + long t0 = System.currentTimeMillis(); + SmbFile[] list = d.listFiles( wildcard ); + t0 = System.currentTimeMillis() - t0; if( list != null ) { for( int j = 0; j < list.length; j++ ) { - System.out.print( " " + list[j] ); + StringBuffer sb = new StringBuffer(); + Date date = new Date( list[j].lastModified() ); + Format.print( System.out, "%-40s", list[j].getName() ); + sb.append( list[j].isDirectory() ? 'd' : '-' ); + sb.append( list[j].canRead() ? 'r' : '-' ); + sb.append( list[j].canWrite() ? 'w' : '-' ); + sb.append( list[j].isHidden() ? 'h' : '-' ); + sb.append( list[j].getType() == SmbFile.TYPE_WORKGROUP ? 'g' : '-' ); + Format.print( System.out, "%-6s", sb.toString() ); + Format.print( System.out, "%10d ", list[j].length() ); + + System.out.print( sdf1.format( date )); + Format.print( System.out, "%3s ", sdf2.format( date )); + System.out.print( sdf3.format( date )); + System.out.println(); } - System.out.println(); - System.out.println( list.length + " items" ); + System.out.println( list.length + " items in " + t0 + "ms" ); } else { System.out.println( "no such file or directory" ); } @@ -128,14 +174,17 @@ public class SmbShell implements AuthHandler { } catch( MalformedURLException mue ) { mue.printStackTrace(); conn = null; + } catch( SmbException se ) { + se.printStackTrace(); } catch( Exception e ) { e.printStackTrace(); + System.exit( 1 ); } } System.exit( 0 ); } public static void main( String[] argv ) throws Exception { - SmbShell smbsh = new SmbShell(); + SmbShell smbsh = new SmbShell( argv.length > 0 ? argv[0] : "smb://" ); smbsh.run(); } } diff --git a/examples/T2Crawler.java b/examples/T2Crawler.java new file mode 100644 index 0000000..2a0359a --- /dev/null +++ b/examples/T2Crawler.java @@ -0,0 +1,128 @@ +/* examples for the jcifs smb client library in Java + * Copyright (C) 2000 "Michael B. Allen" + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +import jcifs.smb.SmbFile; +import jcifs.util.*; +import java.util.LinkedList; +import java.util.ListIterator; +import java.net.MalformedURLException; +import java.io.IOException; + +public class T2Crawler { + + class Semaphore { + private int value = 0; + + Semaphore() {value = 0;} + Semaphore(int initial) {value = initial;} + + public synchronized void P() { + value--; + if (value < 0) { + try { + wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public synchronized void V() { + value++; + notify(); + } + } + + class CrawlerThread extends Thread { + LinkedList list; + Semaphore sem; + SmbFile dir; + int depth; + + + CrawlerThread( SmbFile dir, Semaphore sem, int depth ) { + this.dir = dir; + list = new LinkedList(); + list.add( dir ); + this.sem = sem; + this.depth = depth; + } + + public void run() { + SmbFile d; + SmbFile l[]; + + while( list.isEmpty() == false ) { + int i; + d = (SmbFile)list.remove( 0 ); + try { + l = d.listFiles(); + +/* This is flawed. It decrements depth too agressively and causes the + * thread to finish prematurely. I do not know of a way to fix this + * because there is no concept of a stack here. + */ + depth--; + for( i = 0; i < l.length; i++ ) { + System.out.println( l[i] ); + // if( depth++ > 0 && l[i].isDirectory() && !l[i].isHidden() ) { + if( depth > 0 && l[i].isDirectory() ) { + list.add( l[i] ); + } + } + } catch( Exception e ) { + System.out.println( d ); + e.printStackTrace(); + } + } + sem.V(); + } + } + + T2Crawler( String dir, int numThreads, int depth ) throws Exception { + SmbFile top = new SmbFile( dir ); + Semaphore sem = new Semaphore( numThreads ); + SmbFile[] l = top.listFiles(); + depth--; + for( int i = 0; i < l.length; i++ ) { + try { + System.out.println( l[i] ); + if( !l[i].isDirectory() || l[i].isHidden() ) { + continue; + } + if( depth > 0 ) { + sem.P(); + (new CrawlerThread( l[i], sem, depth )).start(); + } + } catch( Exception e ) { + e.printStackTrace(); + } + } + for( int i = 0; i < l.length; i++ ) { + l[i].canRead(); + } + } + public static void main(String[] argv) throws Exception { + jcifs.util.Log.setMask( Log.EXCEPTIONS | 0x00010000 ); + if( argv.length < 3) { + System.out.println( "$ java -Djcifs.properties=miallen.prp T2Crawler "); + System.exit(1); + } + new T2Crawler( argv[0], Integer.parseInt( argv[1] ), Integer.parseInt( argv[2] )); + } +} diff --git a/examples/TestFile.java b/examples/TestFile.java deleted file mode 100644 index 97a644c..0000000 --- a/examples/TestFile.java +++ /dev/null @@ -1,34 +0,0 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -import java.io.File; - -public class TestFile { - - public static void main( String argv[] ) throws Exception { - File f = new File( argv[0] ); - System.out.println( "toString()=" + f.toString()); - System.out.println( "getCanonicalPath()=" + f.getCanonicalPath()); - System.out.println( "getName()=" + f.getName()); - System.out.println( "getParent()=" + f.getParent()); - System.out.println( "getPath()=" + f.getPath()); - System.out.println( "toURL().toString()=" + f.toURL().toString()); - System.out.println( "equals( " + argv[1] + " )=" + f.equals( new File( argv[1] ))); - } -} - diff --git a/examples/TestSmbFile.java b/examples/TestSmbFile.java deleted file mode 100644 index e2a86cd..0000000 --- a/examples/TestSmbFile.java +++ /dev/null @@ -1,50 +0,0 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -import java.util.Date; -import jcifs.smb.*; - -public class TestSmbFile { - - public static void main( String argv[] ) throws Exception { - SmbFile f; - if( argv.length == 1 ) { - f = new SmbFile( argv[0] ); - } else { - f = new SmbFile( argv[0], argv[1] ); - } - System.out.println( "toString() : " + f.toString()); - System.out.println( "getCanonicalPath() : " + f.getCanonicalPath()); - System.out.println( "getName() : " + f.getName()); - System.out.println( "getParent() : " + f.getParent()); - System.out.println( "getPath() : " + f.getPath()); - System.out.println( "getServer() : " + f.getServer()); - System.out.println( "getShare() : " + f.getShare()); - System.out.println( "exists() : " + f.exists()); - System.out.println( "isDirectory() : " + f.isDirectory()); - System.out.println( "isFile() : " + f.isFile()); - System.out.println( "length() : " + f.length()); - System.out.println( "lastModified() : " + (new Date( f.lastModified() ))); - System.out.println( "isWorkgroup() : " + f.isWorkgroup()); -// System.out.println( "toURL().toString() : " + f.toURL().toString()); - if( argv.length > 2 ) { - System.out.println( "equals( " + argv[1] + " )=" + f.equals( new SmbFile( argv[1] ))); - } - } -} - diff --git a/examples/TestSmbURL.java b/examples/TestSmbURL.java new file mode 100644 index 0000000..2ef4d96 --- /dev/null +++ b/examples/TestSmbURL.java @@ -0,0 +1,164 @@ +import java.util.Date; +import jcifs.smb.*; +import java.io.*; + +public class TestSmbURL { + + static void test( String url, String name ) throws Exception { + SmbFile f; + + if( name == null ) name = ""; + + System.out.println( "INPUT[" + url + ", " + name + "]"); + try { + f = new SmbFile( url, name ); + } catch( Exception e ) { + e.printStackTrace(); + return; + } + + System.out.print( "toString() : " ); + try { + System.out.println( f.toString() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "getCanonicalPath() : " ); + try { + System.out.println( f.getCanonicalPath() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "getUncPath() : " ); + try { + System.out.println( f.getUncPath() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "getName() : " ); + try { + System.out.println( f.getName() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "getParent() : " ); + try { + System.out.println( f.getParent() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "getPath() : " ); + try { + System.out.println( f.getPath() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "getServer() : " ); + try { + System.out.println( f.getServer() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "getShare() : " ); + try { + System.out.println( f.getShare() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "exists() : " ); + try { + System.out.println( f.exists() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "isDirectory() : " ); + try { + System.out.println( f.isDirectory() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "isFile() : " ); + try { + System.out.println( f.isFile() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "length() : " ); + try { + System.out.println( f.length() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "lastModified() : " ); + try { + System.out.println( (new Date( f.lastModified() ))); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + System.out.print( "toURL().toString() : " ); + try { + System.out.println( f.toURL() ); + } catch( Exception e ) { + e.printStackTrace(); System.out.println(); + } + + System.in.read(); + } + + public static void main( String argv[] ) throws Exception { + String workgroup, server, share, path, file; + + if( argv.length < 5 ) { + System.err.println( "TestSmbURL workgroup server share path file" ); + System.exit( 1 ); + } + + workgroup = argv[0]; + server = argv[1]; + share = argv[2]; + path = argv[3]; + file = argv[4]; + +/* + System.out.println(); + System.out.println( "-- UNUSUAL --" ); + System.out.println(); + test( "smb://" + server, "../" + server + "/" + share ); + test( "smb://foo", "../" + workgroup ); + test( "smb://", ".." ); +*/ + + System.out.println(); + System.out.println( "-- BASICS: ONE ARGUMENT --" ); + System.out.println(); + test( "smb://" + server + "/" + share + "/" + path + "/" + file, null ); + test( "smb://" + server + "/" + share + "/" + path + "/", null ); + test( "smb://" + server + "/" + share + "/", null ); + test( "smb://" + server + "/", null ); + test( "smb://" + workgroup + "/", null ); + test( "smb://", null ); + + System.out.println(); + System.out.println( "-- BASICS: TWO ARGUMENTS --" ); + System.out.println(); + test( "smb://" + server + "/" + share + "/" + path + "/", file); + test( "smb://" + server + "/" + share + "/", path + "/" + file); + test( "smb://" + server + "/", share + "/" + path + "/" + file); + test( "smb://", server + "/" + share + "/" + path + "/" + file); + test( "smb://", "smb://" + server + "/" + share + "/" + path + "/" + file); + test( "smb://", "smb://" + server + "/"); + test( "smb://", "smb://" + workgroup + "/"); + test( "smb://", "smb://"); + test( "smb://" + server + "/share/", "smb://"); + + System.out.println(); + System.out.println( "-- CANONICALIZATION --" ); + System.out.println(); + test( "smb://" + server + "/" + share + "/foo/../" + path + "/" + file, null ); + test( "smb://" + server + "/foo/bar/.././../" + share + "/" + path + "/" + file, null ); + test( "smb://" + server + "/foo/bar/.././.././" + share + "/fake/../" + path + "/" + file, null ); + test( "smb://" + server + "/foo/bar/.././.././", share + "/fake/../" + path + "/" + file); + test( "smb://", server + "/foo/bar/.././.././" + share + "/fake/../" + path + "/" + file); + } +} + diff --git a/examples/TestUnicode.java b/examples/TestUnicode.java new file mode 100644 index 0000000..fc8e703 --- /dev/null +++ b/examples/TestUnicode.java @@ -0,0 +1,60 @@ +import java.io.*; +import jcifs.smb.*; +import jcifs.util.*; + +public class TestUnicode { + static SmbFile dir; + + public static void mkobj( String name ) throws Exception { + int r = (int)(Math.random() * 100.0); + if( r < 50 ) { + SmbFile d = new SmbFile( dir.getParent(), dir.getName() + "/" + name ); + d.mkdir(); + if( r < 15 ) { + dir = d; + } + } else { + SmbFileOutputStream out = new SmbFileOutputStream( dir.getParent() + "/" + dir.getName() + "/" + name ); + out.close(); + } + } + + public static void main( String argv[] ) throws Exception { + if( argv.length < 1 ) { + throw new IllegalArgumentException( "Must provide path to directory in which to run test" ); + } + FileInputStream in = new FileInputStream( "data" ); + byte[] b = new byte[4096]; + int n = in.read( b ); + String data = new String( b, 0, n, "UTF-8" ); + char[] d = data.toCharArray(); + + dir = new SmbFile( argv[0] + "/TestUnicode" ); + try { + dir.delete(); + } catch( SmbException se ) { + se.printStackTrace(); + } + dir.mkdir(); + + int i, s, max = 8; + for( i = s = 0; i < d.length; i++ ) { + switch (d[i]) { + case '"': case '/': case '\\': case '[': case ']': + case ':': case '|': case '<': case '>': case '=': + case ';': case ',': case '*': case '?': case '\n': + d[i] = '_'; + } + if(Character.isWhitespace( d[i] )) { + if( i == s ) { + s++; + } + if( i > (s + max)) { + String name = new String( d, s, i - s ); + mkobj( name ); + s = i + 1; + } + } + } + } +} diff --git a/examples/ThreadedNbtQuery.java b/examples/ThreadedNbtQuery.java new file mode 100644 index 0000000..2addf3c --- /dev/null +++ b/examples/ThreadedNbtQuery.java @@ -0,0 +1,38 @@ +import jcifs.netbios.*; + +public class ThreadedNbtQuery { + + static class QThread extends Thread { + String name; + + QThread( String name ) { + this.name = name; + } + + public void run() { + try { + yield(); + System.out.println( getName() + ": started" ); + NbtAddress.getByName( name ); + System.out.println( getName() + ": done" ); + } catch( Exception x ) { + x.printStackTrace(); + } + } + } + + public static void main(String[] argv) throws Exception { + if( argv.length < 2 ) { + System.out.println( "java ThreadedNbtQuery name [name [name [...]]]" ); + return; + } + + QThread[] t = new QThread[argv.length]; + for( int i = 0; i < argv.length; i++ ) { + t[i] = new QThread( argv[i] ); + } + for( int j = 0; j < argv.length; j++ ) { + t[j].start(); + } + } +} diff --git a/examples/ThreadedSmbCrawler.java b/examples/ThreadedSmbCrawler.java index 9f4ec76..97d271e 100644 --- a/examples/ThreadedSmbCrawler.java +++ b/examples/ThreadedSmbCrawler.java @@ -1,5 +1,5 @@ /* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" + * Copyright (C) 2000 "Michael B. Allen" * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ import java.io.IOException; public class ThreadedSmbCrawler { - static long time; + static int workingThreads = 0; class DirEntry { SmbFile dir; @@ -41,24 +41,24 @@ public class ThreadedSmbCrawler { StringBuffer sb = new StringBuffer(); - SmbCrawlerThread() { - } - public void run() { while( true ) { try { DirEntry e; synchronized( dirList ) { -time = System.currentTimeMillis(); while( dirList.isEmpty() ) { - dirList.wait( 500 ); +System.err.println( "workingThreads=" + workingThreads ); + if( workingThreads == 0 ) { + return; // done + } + dirList.wait( 2000 ); } e = (DirEntry)dirList.remove( 0 ); - } - - if( e.depth == 0 ) { - continue; + if( e.depth == 0 ) { + continue; + } + workingThreads++; } String[] l = e.dir.list(); @@ -72,7 +72,7 @@ time = System.currentTimeMillis(); sb.append( " " ); } SmbFile d = new SmbFile( e.dir, l[i] ); - System.out.println( sb.append( d )); + System.err.println( sb.append( d )); if( d.isDirectory() ) { synchronized( dirList ) { dirList.add( new DirEntry( d, e.depth - 1 )); @@ -83,7 +83,13 @@ time = System.currentTimeMillis(); ioe.printStackTrace(); } } + synchronized( dirList ) { + workingThreads--; + } } catch( Exception x ) { + synchronized( dirList ) { + workingThreads--; + } x.printStackTrace(); } } @@ -91,26 +97,41 @@ time = System.currentTimeMillis(); } LinkedList dirList; - int maxDepth; + int maxDepth, numThreads; + Thread[] threads; ThreadedSmbCrawler( String dir, int maxDepth, int numThreads ) throws Exception { this.maxDepth = maxDepth; + this.numThreads = numThreads; + threads = new Thread[numThreads]; dirList = new LinkedList(); dirList.add( new DirEntry( new SmbFile( dir ), maxDepth )); - for( int i = 0; i < numThreads; i++ ) { - (new SmbCrawlerThread()).start(); + } + + long go() throws Exception { + int i; + long start = System.currentTimeMillis(); + + for( i = 0; i < numThreads; i++ ) { + threads[i] = new SmbCrawlerThread(); + threads[i].start(); } + for( i = 0; i < numThreads; i++ ) { + threads[i].join(); + } + + return System.currentTimeMillis() - start; } public static void main(String[] argv) throws Exception { + ThreadedSmbCrawler tsc; + if( argv.length < 3 ) { - System.out.println( "usage: ThreadedSmbCrawler dir depth numThreads" ); - return; + System.err.println( "usage: ThreadedSmbCrawler dir depth numThreads" ); + System.exit( 1 ); } - Log.setMask( Log.CRITICAL_EXCEPTIONS ); -long start = System.currentTimeMillis(); - new ThreadedSmbCrawler( argv[0], Integer.parseInt( argv[1] ), Integer.parseInt( argv[2] )); -System.in.read(); -System.out.println( "time=" + (time - start) + "ms" ); + + tsc = new ThreadedSmbCrawler( argv[0], Integer.parseInt( argv[1] ), Integer.parseInt( argv[2] )); + System.err.println( "Crawling Complete: " + (tsc.go() / 1000 / 60) + "min" ); } } diff --git a/examples/ThreadedUniQuery.java b/examples/ThreadedUniQuery.java new file mode 100644 index 0000000..feb756c --- /dev/null +++ b/examples/ThreadedUniQuery.java @@ -0,0 +1,50 @@ +import java.net.UnknownHostException; +import jcifs.*; + +public class ThreadedUniQuery { + + static class QThread extends Thread { + String name; + + QThread( String name ) { + super( name + "-thread" ); + this.name = name; + } + + public void run() { + try { + System.out.println( getName() + ": started" ); + for( int i = 0; i < 15; i++ ) { + Thread.sleep( (long)(Math.random() * 1000L )); + try { + UniAddress.getByName( name, true ); + } catch( UnknownHostException uhe ) { + uhe.printStackTrace(); + } + } + System.out.println( getName() + ": done" ); + } catch( Exception x ) { + x.printStackTrace(); + } + } + } + + public static void main(String[] argv) throws Exception { + if( argv.length < 2 ) { + System.out.println( "java ThreadedUniQuery name [name [name [...]]]" ); + return; + } + + QThread[] t = new QThread[argv.length]; + for( int i = 0; i < argv.length; i++ ) { + t[i] = new QThread( argv[i] ); + } + for( int j = 0; j < argv.length; j++ ) { + t[j].start(); + } + for( int j = 0; j < argv.length; j++ ) { + t[j].join(); + } + Runtime.getRuntime().exit(0); + } +} diff --git a/examples/Torture1.java b/examples/Torture1.java new file mode 100644 index 0000000..053f1ec --- /dev/null +++ b/examples/Torture1.java @@ -0,0 +1,102 @@ +import java.io.*; +import jcifs.smb.*; +import java.util.*; + +class Worker extends Thread { + + Torture1 t; + Exception e; + + Worker( Torture1 t ) { + this.t = t; + e = null; + } + public void run() { + try { + t.torture(); + } catch( Exception e ) { + this.e = e; + } + } +} + +public class Torture1 { + + Properties prp; + + Torture1( Properties prp ) { + this.prp = prp; + } + + void compare( SmbFile f1, SmbFile f2 ) throws Exception { + if( f1.isDirectory() && f2.isDirectory() ) { + SmbFile[] dirents = f1.listFiles(); + SmbFile f; + for( int i = 0; i < dirents.length; i++ ) { + f = new SmbFile( f2, dirents[i].getName() ); + compare( dirents[i], f ); + } + } + if( f1.isDirectory() != f2.isDirectory() ) { + System.err.println( "directory comparison failed" ); + } + if( f1.isFile() != f2.isFile() ) { + System.err.println( "file comparison failed" ); + } + if( f1.getType() != f2.getType() ) { + System.err.println( "type comparison failed" ); + } + if( f1.getName().equals( f2.getName() ) == false ) { + System.err.println( "name comparison failed: " + f1.getName() + " " + f2.getName() ); + } + if( f1.length() != f2.length() ) { + System.err.println( "length comparison failed: " + f1.length() + " " + f2.length() ); + } + } + + void torture() throws Exception { + String domain, username, password, server, share, directory; + NtlmPasswordAuthentication ntlm; + + domain = prp.getProperty( "torture.dst.domain" ); + username = prp.getProperty( "torture.dst.username" ); + password = prp.getProperty( "torture.dst.password" ); + + ntlm = new NtlmPasswordAuthentication( domain, username, password ); + + server = prp.getProperty( "torture.dst.server" ); + share = prp.getProperty( "torture.dst.share" ); + directory = prp.getProperty( "torture.dst.directory" ); + + SmbFile dst = new SmbFile( "smb://", ntlm ); + dst = new SmbFile( dst, server ); + dst = new SmbFile( dst, share ); + dst = new SmbFile( dst, directory ); + + SmbFile src = new SmbFile( prp.getProperty( "torture.src.url" )); + +System.err.println( src + " --> " + dst ); +System.in.read(); + + if( dst.exists() ) { + dst.delete(); + } + src.copyTo( dst ); +System.err.println( "CopyTo done" ); +System.in.read(); + compare( src, dst ); +System.err.println( "Test Complete" ); + } + + public static void main( String[] argv ) throws Exception { + Properties prp = new Properties(); + prp.load( new FileInputStream( "torture.prp" )); + Torture1 t = new Torture1( prp ); + Worker w = new Worker( t ); + w.start(); + w.join(); + if( w.e != null ) { + throw w.e; + } + } +} diff --git a/examples/Torture2.java b/examples/Torture2.java new file mode 100644 index 0000000..b92ac6e --- /dev/null +++ b/examples/Torture2.java @@ -0,0 +1,92 @@ +import java.io.*; +import jcifs.smb.*; +import java.util.*; + +public class Torture2 extends Thread { + + SmbFile from, to; + + Torture2( String from, String to ) throws Exception { + this.from = new SmbFile( from ); + this.to = new SmbFile( to ); + } + + public void run() { + try { + copyAndVerify(); + } catch( Exception e ) { + e.printStackTrace(); + } + } + + void compare( SmbFile f1, SmbFile f2 ) throws Exception { +//System.err.println( f1.getName() + " | " + f2.getName() ); +try { + if( f1.isDirectory() && f2.isDirectory() ) { + SmbFile[] dirents = f1.listFiles(); + SmbFile f; + for( int i = 0; i < dirents.length; i++ ) { + f = new SmbFile( f2, dirents[i].getName() ); +//System.err.println( f2 + " + " + dirents[i].getName() + " = " + f + ": isDirectory=" + f.isDirectory() ); + compare( dirents[i], f ); + } + } + if( f1.isDirectory() != f2.isDirectory() ) { + System.err.println( "directory comparison failed: " + f1.isDirectory() + " " + f2.isDirectory() ); + } + if( f1.isFile() != f2.isFile() ) { + System.err.println( "file comparison failed: " + f1.isFile() + " " + f2.isFile() ); + } + if( f1.getType() != f2.getType() ) { + System.err.println( "type comparison failed: " + f1.getName() + " " + f2.getName() ); + } + if( f1.getName().equals( f2.getName() ) == false ) { + System.err.println( "name comparison failed: " + f1.getName() + " " + f2.getName() ); + } + if( f1.length() != f2.length() ) { + System.err.println( "length comparison failed: " + f1.length() + " " + f2.length() ); + } +} catch( Exception x ) { + System.err.println( "Exception comparing: " + f1 + " | " + f2 ); + x.printStackTrace(); +} + } + + void copyAndVerify() throws Exception { + from.copyTo( to ); + compare( from, to ); + } + + public static void main( String[] argv ) throws Exception { + Properties prp; + Torture2[] threads; + String from, to; + int i; + + if( argv.length < 1 ) { + System.err.println( "Torture2 " ); + System.exit( 1 ); + } + + prp = new Properties(); + prp.load( new FileInputStream( argv[0] )); + + threads = new Torture2[10]; + + for( i = 0; i < 10; i++ ) { + from = prp.getProperty( "thread." + i + ".from.url" ); + to = prp.getProperty( "thread." + i + ".to.url" ); + if( from == null || to == null ) { + break; + } + threads[i] = new Torture2( from, to ); + threads[i].start(); + Thread.sleep( 12345 ); + } + while( i-- > 0 ) { + threads[i].join(); + } + System.err.println( "Test complete" ); + } +} + diff --git a/examples/TortureTest3.java b/examples/TortureTest3.java deleted file mode 100644 index b1a11b3..0000000 --- a/examples/TortureTest3.java +++ /dev/null @@ -1,86 +0,0 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -import java.util.*; -import jcifs.smb.*; - -class TortureTest3 { - - static final int NUM_OF_THREADS = 4; - - java.util.List dirList; - - TortureTest3() throws Exception { - dirList = Collections.synchronizedList( new LinkedList()); - } - - void execute() { - for( int i = 0; i < NUM_OF_THREADS; i++ ) { - Thread t = new Worker( this ); - t.start(); - } - } - - class Worker extends Thread { - TortureTest3 con; - int count = 0; - - Worker( TortureTest3 con ) { - this.con = con; - } - - public void run() { - try { - SmbFile dir, file; - String[] list; - while( true ) { - synchronized( con.dirList ) { - while( con.dirList.isEmpty() ) { - con.dirList.wait( 100 ); - System.out.println( "name=" + getName() + ",count=" + count ); - } - dir = (SmbFile)con.dirList.remove( 0 ); - } - list = dir.list(); - for( int i = 0; i < list.length; i++ ) { - file = new SmbFile( dir, list[i] ); - if( file.isDirectory() ) { - synchronized( con.dirList ) { - con.dirList.add( file ); - con.dirList.notify(); - } - System.out.println( "d " + file ); - } else { - count++; - System.out.println( " " + file ); - } - } - } - } catch( Exception e ) { - e.printStackTrace(); - } - } - } - - public static void main( String argv[] ) throws Exception { - TortureTest3 con = new TortureTest3(); - con.dirList.add( new SmbFile( argv[0] )); - con.execute(); - } -} - diff --git a/examples/TortureTest4.java b/examples/TortureTest4.java deleted file mode 100644 index c4f5318..0000000 --- a/examples/TortureTest4.java +++ /dev/null @@ -1,88 +0,0 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -import jcifs.smb.*; -import jcifs.netbios.NbtAddress; -import jcifs.util.*; -import java.util.Enumeration; - -public class TortureTest4 extends Thread { - - String url; - SmbFile file; - - TortureTest4( String domain, - String username, - String password, - String server, - String share ) { - - StringBuffer sb = new StringBuffer( "smb://" ); - - if( username != null ) { - if( domain != null ) { - sb.append( domain ).append( ';' ); - } - sb.append( username ); - if( password != null ) { - sb.append( ':' ).append( password ); - } - sb.append( '@' ); - } - sb.append( server + "/" + share + "/foo.txt" ); - - url = sb.toString(); - } - - public void run() { - try { -System.out.println( "url=" + url ); - file = new SmbFile( url ); - file.exists(); - } catch( Exception e ) { - e.printStackTrace(); - } - } - - public static void main( String[] argv ) throws Exception { - Thread[] threads = new Thread[5]; - String key; - Object val; - PropertiesTree shares = (PropertiesTree)jcifs.Config.get( argv[0] ); - String server = shares.getProperty( "server" ); - int i = 0; - for( Enumeration e = shares.keys(); e.hasMoreElements(); ) { - key = (String)e.nextElement(); - val = shares.get( key ); - if( val instanceof PropertiesTree ) { - threads[i++] = new TortureTest4( shares.getProperty( key + ".domain" ), - shares.getProperty( key + ".username" ), - shares.getProperty( key + ".password" ), - server, - key ); - } - } - for( int t = 0; t < i; t++ ) { - threads[t].start(); - } - for( int j = 0; j < i; j++ ) { - threads[j].join(); - } - System.exit( 0 ); - } -} diff --git a/examples/TortureTest5.java b/examples/TortureTest5.java index b204d14..aa24f73 100644 --- a/examples/TortureTest5.java +++ b/examples/TortureTest5.java @@ -1,22 +1,4 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -import jcifs.netbios.*; +import jcifs.UniAddress; import java.util.Enumeration; public class TortureTest5 extends Thread { @@ -29,7 +11,7 @@ public class TortureTest5 extends Thread { public void run() { try { - System.out.println( NbtAddress.getByName( name )); + System.out.println( UniAddress.getByName( name )); } catch( Exception e ) { e.printStackTrace(); } diff --git a/examples/TransactNamedPipe.java b/examples/TransactNamedPipe.java index 7a1d4b1..1f451e3 100644 --- a/examples/TransactNamedPipe.java +++ b/examples/TransactNamedPipe.java @@ -1,21 +1,3 @@ -/* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - import jcifs.smb.SmbNamedPipe; import java.io.InputStream; import java.io.OutputStream; diff --git a/examples/URLTest.java b/examples/URLTest.java new file mode 100644 index 0000000..60f1aa3 --- /dev/null +++ b/examples/URLTest.java @@ -0,0 +1,31 @@ +import java.net.*; +import java.util.*; + +public class URLTest { + + public static void main( String[] argv ) throws Exception { + URL url; + + jcifs.Config.registerSmbURLHandler(); + + if( argv.length > 2 ) { + url = new URL( new URL( new URL( argv[0] ), argv[1] ), argv[2] ); + } else if( argv.length > 1 ) { + url = new URL( new URL( argv[0] ), argv[1] ); + } else { + url = new URL( argv[0] ); + } + System.out.println( " authority: " + url.getAuthority() ); + System.out.println( " file: " + url.getFile() ); + System.out.println( " host: " + url.getHost() ); + System.out.println( " port: " + url.getPort() ); + System.out.println( " path: " + url.getPath() ); + System.out.println( " query: " + url.getQuery() ); + System.out.println( " ref: " + url.getRef() ); + System.out.println( " userinfo: " + url.getUserInfo() ); + System.out.println( "externalform: " + url.toExternalForm() ); + System.out.println( " string: " + url.toString() ); + + System.exit( 0 ); + } +} diff --git a/examples/VerifyIO.java b/examples/VerifyIO.java new file mode 100644 index 0000000..e99fc64 --- /dev/null +++ b/examples/VerifyIO.java @@ -0,0 +1,76 @@ +import java.net.MalformedURLException; +import jcifs.smb.*; +import java.io.*; + +public class VerifyIO { + + static File get( SmbFile f0 ) throws Exception { + int i; + File f1; + byte[] buf = new byte[8192]; + + f1 = new File( f0.getName() ); + FileOutputStream out = new FileOutputStream( f1 ); + SmbFileInputStream in = new SmbFileInputStream( f0 ); + + while(( i = in.read( buf )) > 0 ) { + out.write( buf, 0, i ); + System.err.print( '.' ); + } + + in.close(); + out.close(); + + return f1; + } + static void put( SmbFile f2 ) throws Exception { + int i; + byte[] buf = new byte[8192]; + + FileInputStream in = new FileInputStream( f2.getName() ); + SmbFileOutputStream out = new SmbFileOutputStream( f2 ); + + while(( i = in.read( buf )) > 0 ) { + out.write( buf, 0, i ); + System.err.print( '-' ); + } + + in.close(); + out.close(); + } + + public static void main(String[] argv) throws Exception { + BufferedReader in; + String name; + + if( argv.length < 2 ) { + System.err.println( "Must provide file of SMB URLs and destination directory" ); + System.exit( 1 ); + } + + in = new BufferedReader( new FileReader( argv[0] )); + while(( name = in.readLine() ) != null ) { + SmbFile f0, f2; + File f1; + + System.err.print( name + ": " ); + f0 = new SmbFile( name ); + f1 = get( f0 ); + + if( f0.length() != f1.length() ) { + throw new RuntimeException( "File lengths do not match: f0=" + f0.length() + ",f1=" + f1.length() ); + } + + f2 = new SmbFile( argv[1] + "/" + f0.getName() ); + put( f2 ); + + if( f1.length() != f2.length() ) { + throw new RuntimeException( "File lengths do not match: f1=" + f1.length() + ",f2=" + f2.length() ); + } + + f1.delete(); + System.err.println( " ok" ); + } + } +} + diff --git a/examples/VerifyReads.java b/examples/VerifyReads.java new file mode 100644 index 0000000..cfa42fa --- /dev/null +++ b/examples/VerifyReads.java @@ -0,0 +1,78 @@ +import java.net.MalformedURLException; +import jcifs.smb.*; +import java.io.*; + +public class VerifyReads { + + int maxDepth; + byte[] buf = new byte[8192]; + + VerifyReads( int maxDepth ) { + this.maxDepth = maxDepth; + } + + void mkdir( File dir ) { + if( dir != null && !dir.exists() ) { + mkdir( dir.getParentFile() ); + dir.mkdir(); + } + } + + void copy( SmbFile f, String path, int depth ) throws MalformedURLException, IOException { + int i, d; + File localFile, dir; + SmbFile[] list; + + if( depth == 0 ) { + return; + } + + localFile = new File( path + "/" + f.getName() ); + d = f.getName().lastIndexOf( '.' ); + + if( f.isDirectory() ) { + + list = f.listFiles(); + + for( i = 0; i < list.length; i++ ) { + copy( list[i], path + "/" + f.getName(), depth - 1 ); + } + } else if( d > 1 && f.getName().substring( d ).equalsIgnoreCase( ".ini" )) { + + mkdir( new File( path )); + + SmbFileInputStream in = new SmbFileInputStream( f ); + FileOutputStream out = new FileOutputStream( localFile ); + + while(( i = in.read( buf )) > 0 ) { + out.write( buf, 0, i ); + } + + in.close(); + out.close(); + } + } + + public static void main(String[] argv) throws Exception { + VerifyReads cd; + SmbFile top; + int depth; + + if( argv.length < 2 ) { + System.err.println( "Must specify ini directory location (e.g. smb://mlamrs\\;rschprod:grispass@rsch-nyc-19b9/vendorapps) followd by the maximum traversal depth"); + System.exit( 1 ); + } + + depth = Integer.parseInt( argv[1] ); + cd = new VerifyReads( depth ); + top = new SmbFile( argv[0] ); + + if( !top.isDirectory() ) { + System.err.println( "The path specified is not a directory" ); + System.exit( 1 ); + } + + cd.copy( top, ".", depth ); + } +} + diff --git a/examples/data b/examples/data new file mode 100644 index 0000000..86cc0b8 --- /dev/null +++ b/examples/data @@ -0,0 +1,17 @@ +Unë mund të ha qelq dhe nuk më gjen gjë +⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ +Mi povas manĝi vitron, ĝi ne damaĝas min +yoyo seti @ home Tarzan + Jane Barnum & Baley +J'peux bouffer d'la vitre, ça m'fa pas mal +Dji pou magnî do vêre, çoula m' freut nén må +которая состоится 10-12 марта 1997 года в Майнце в Германии +Pot să mănânc sticlă și ea nu mă rănește +Tá mé in ann gloine a ithe; Ní chuireann sé isteach nó amach orm +Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα +Èg get borðað gler, það meiðir mig ekki +Я можу їсти шкло, й воно мені не пошкодить +אני יכול לאכול זכוכית וזה לא מזיק לי +Mo lè je̩ dígí, kò ní pa mí lára +Μπορώ να φάω σπασμένα να γυαλιά χωρίς να πάθω τίποτα +Èg get borðað gler, það meiðir mig ekki +Я можу їсти шкло, й воно мені не пошкодить diff --git a/examples/jcifs.prp b/examples/jcifs.prp index 24ec9dc..79fd0c6 100644 --- a/examples/jcifs.prp +++ b/examples/jcifs.prp @@ -1,7 +1,8 @@ -# example jcifs properties tree file -;baddr=192.168.1.255 -;domain=foo -username=me -password=bar -;wins=146.123.82.22 -;log=all +domain=rsch +username=miallen +password=Fa!e@s +;wins=169.249.100.243 +wins=146.125.56.78 +;log=ALL +;resolveOrder=WINS +;soTimeout=3000 diff --git a/examples/ntlm.prp b/examples/ntlm.prp new file mode 100644 index 0000000..7313013 --- /dev/null +++ b/examples/ntlm.prp @@ -0,0 +1,38 @@ +! Lookup any domain contorller in the FOONET<1C> domain + +;domain=foonet + +! Or explicitly specify any SMB server to use as a +! "Domain Controller". This could be a real PDC or +! preferrably a BDC or just a plain workstation + +domainController=192.168.1.15 + +! WINS server is only necessary if you are using the +! jcifs.smb.client.domain property to lookup a domain +! controller + +;wins=136.135.65.85 + +! On machines with multiple interfaces it is usually +! necessary to set the broadcast address. See the jCIFS FAQ. + +baddr=192.168.1.255 + +! If we're sure we have a WINS server this is a +! little more direct + +;resolveOrder=WINS + +! Users will have to re-authenticate after 600000ms +! (10 minutes) if no clients trigger activity on the socket +! to the domain controller + +soTimeout=600000 + +! Uncomment this if it's not working to see what's going on. +! Logging output is directed to System.err. On Tomcat this +! goes to logs/catalina.out. Not sure about Resin. + +;log=ALL + diff --git a/examples/pipes/callnp.c b/examples/pipes/callnp.c index 095eb0e..4266c32 100644 --- a/examples/pipes/callnp.c +++ b/examples/pipes/callnp.c @@ -1,5 +1,5 @@ /* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" + * Copyright (C) 2000 "Michael B. Allen" * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/examples/pipes/createf.c b/examples/pipes/createf.c index 09e8d37..838d7ff 100644 --- a/examples/pipes/createf.c +++ b/examples/pipes/createf.c @@ -1,5 +1,5 @@ /* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" + * Copyright (C) 2000 "Michael B. Allen" * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/examples/pipes/createnp.c b/examples/pipes/createnp.c index ca8c33d..04e115d 100644 --- a/examples/pipes/createnp.c +++ b/examples/pipes/createnp.c @@ -1,5 +1,5 @@ /* examples for the jcifs smb client library in Java - * Copyright (C) 2001 "Michael B. Allen" + * Copyright (C) 2000 "Michael B. Allen" * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/examples/torture.prp b/examples/torture.prp new file mode 100644 index 0000000..c824b5c --- /dev/null +++ b/examples/torture.prp @@ -0,0 +1,9 @@ + +torture.src.url = smb://dom\;miallen:pass@server/pub/ +torture.dst.domain = dom +torture.dst.username = miallen +torture.dst.password = pass +torture.dst.server = server/ +torture.dst.share = share52/ +torture.dst.directory = torture1/ + diff --git a/examples/torture2.prp b/examples/torture2.prp new file mode 100644 index 0000000..e9d3687 --- /dev/null +++ b/examples/torture2.prp @@ -0,0 +1,7 @@ + +thread.0.from.url = smb://dom\;usr:pas@svr1/shr/dir/ +thread.0.to.url = smb://dom\;usr:pas@svr2/shr/dir/ +thread.1.from.url = smb://dom\;usr:pas@svr1/shr/dir/ +thread.1.to.url = smb://dom\;usr:pas@svr2/shr/dir/ +thread.2.from.url = smb://dom\;usr:pas@svr1/shr/dir/ +thread.2.to.url = smb://dom\;usr:pas@svr2/shr/dir/ diff --git a/examples/tt4.prp b/examples/tt4.prp deleted file mode 100644 index b36904d..0000000 --- a/examples/tt4.prp +++ /dev/null @@ -1,51 +0,0 @@ -# config for TortureTest4 - -;baddr=192.168.1.255 -wins=146.123.82.22 -;log=all - - - server = strauss - username = goober - password = mypass - - place = holder - - - place = holder - - - username = someone - password = hello - - - - server = hendrix - username = mike - password = x%43hhj - - place = holder - - - place = holder - - - place = holder - - - - server = fruit - username = guest - password = - - place = holder - - - username = whooly - password = cranapple - - - username = gardner - password = hoe - - diff --git a/examples/zzz.java b/examples/zzz.java deleted file mode 100644 index ba6b707..0000000 --- a/examples/zzz.java +++ /dev/null @@ -1,44 +0,0 @@ - -import jcifs.smb.*; - -public class zzz implements Runnable -{ - public zzz() - { - } - public void run() { - try { - SmbFile f = new SmbFile("smb://username:password@server/share/file.txt"); - SmbFileInputStream fin = new SmbFileInputStream(f); - fin.close(); - } - catch(Exception e) { - e.printStackTrace(); - } - } - - static public void main(String args[]) { - jcifs.util.Config.setProperty( "wins", "146.123.82.22" ); -// jcifs.util.Config.setProperty( "maxMpxCount", "1" ); - int i,j; - int iterations = 1; - int numthreads = 100; - for(i=0; i + * 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 @@ -28,33 +28,45 @@ import java.io.IOException; import java.net.InetAddress; /** - * This class enhances the {@link jcifs.util.Config} class to simply add - * additional configuration information specific to the jcifs smb library. - *

- * See also Setting JCIFS Properties + * This class mananges configuration information specific to the jCIFS library. There are several ways to set jCIFS properties. See the overview page of the API documentation for details. */ public class Config { - static { - Properties sys; - String mask; - String filename; - FileInputStream in = null; +/** + * This static method registers the SMB URL protocol handler which is required to use SMB URLs with the java.net.URL class. If this method is not called before attempting to create an SMB URL with the URL class the following exception will occur: +

+Exception MalformedURLException: unknown protocol: smb
+      at java.net.URL.(URL.java:480)
+      at java.net.URL.(URL.java:376)
+      at java.net.URL.(URL.java:330)
+      at jcifs.smb.SmbFile.(SmbFile.java:355)
+      ...
+
+ */ - sys = System.getProperties(); - synchronized( sys ) { - String pkgs = sys.getProperty( "java.protocol.handler.pkgs" ); - if( pkgs == null ) { - pkgs = "jcifs"; - } else { - pkgs += "|jcifs"; - } - sys.put( "java.protocol.handler.pkgs", pkgs ); + public static void registerSmbURLHandler() { + String ver, pkgs; + + ver = System.getProperty( "java.version" ); + if( ver.startsWith( "1.1." ) || ver.startsWith( "1.2." )) { + throw new RuntimeException( "jcifs-0.7.0b4+ requires Java 1.3 or above. You are running " + ver ); } + pkgs = System.getProperty( "java.protocol.handler.pkgs" ); + if( pkgs == null ) { + pkgs = "jcifs"; + } else { + pkgs += "|jcifs"; + } + System.setProperty( "java.protocol.handler.pkgs", pkgs ); + } + + static { + String filename, mask; + FileInputStream in = null; try { - filename = sys.getProperty( "jcifs.properties" ); + filename = System.getProperty( "jcifs.properties" ); if( filename != null && filename.length() > 1 ) { in = new FileInputStream( filename ); } diff --git a/src/jcifs/UniAddress.java b/src/jcifs/UniAddress.java index 4eae90f..1622613 100644 --- a/src/jcifs/UniAddress.java +++ b/src/jcifs/UniAddress.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -27,11 +27,21 @@ import jcifs.netbios.NbtAddress; import jcifs.netbios.Lmhosts; /** - * This class is a wrapper for both {@link jcifs.netbios.NbtAddress} and - * {@link java.net.InetAddress}. This frees the NetBIOS implementation - * from trying to handle DNS and abstacts the NetBIOS protocol from the smb - * package. This is a prerequisite of NetBIOS-less transport; a precedent - * set by Microsoft's latest servers. + *

Under normal conditions it is not necessary to use + * this class to use jCIFS properly. Name resolusion is + * handled internally to the jcifs.smb package. + *

+ * This class is a wrapper for both {@link jcifs.netbios.NbtAddress} + * and {@link java.net.InetAddress}. The name resolution mechanisms + * used will systematically query all available configured resolution + * services including WINS, broadcasts, DNS, and LMHOSTS. See + * Setting Name Resolution Properties + * and the jcifs.resolveOrder property. Changing + * jCIFS name resolution properties can greatly affect the behavior of + * the client and may be necessary for proper operation. + *

+ * This class should be used in favor of InetAddress to resolve hostnames on LANs and WANs that + * support a mixture of NetBIOS/WINS and DNS resolvable hosts. */ public class UniAddress { @@ -44,35 +54,6 @@ public class UniAddress { static int[] resolveOrder; static InetAddress nbns, baddr; - static class QueryThread extends Thread { - - Object lock; - String host, scope; - int type; - NbtAddress ans = null; - InetAddress svr; - UnknownHostException uhe; - - QueryThread( Object lock, String host, int type, - String scope, InetAddress svr ) { - this.lock = lock; - this.host = host; - this.type = type; - this.scope = scope; - this.svr = svr; - } - public void run() { - try { - ans = NbtAddress.getByName( host, type, scope, svr ); - } catch( UnknownHostException uhe ) { - this.uhe = uhe; - } - synchronized( lock ) { - lock.notify(); - } - } - } - static { String ro = Config.getProperty( "jcifs.resolveOrder" ); nbns = Config.getInetAddress( "jcifs.netbios.wins", null ); @@ -133,22 +114,63 @@ public class UniAddress { } } + static class Sem { + Sem( int count ) { + this.count = count; + } + int count; + } + + static class QueryThread extends Thread { + + Sem sem; + String host, scope; + int type; + NbtAddress ans = null; + InetAddress svr; + UnknownHostException uhe; + + QueryThread( Sem sem, String host, int type, + String scope, InetAddress svr ) { + super( "JCIFS-QueryThread: " + host ); + this.sem = sem; + this.host = host; + this.type = type; + this.scope = scope; + this.svr = svr; + } + public void run() { + try { + ans = NbtAddress.getByName( host, type, scope, svr ); + } catch( UnknownHostException uhe ) { + this.uhe = uhe; + } catch( Exception ex ) { + this.uhe = new UnknownHostException( ex.getMessage() ); + } finally { + synchronized( sem ) { + sem.count--; + sem.notify(); + } + } + } + } + static NbtAddress lookupServerOrWorkgroup( String name, InetAddress svr ) throws UnknownHostException { - Object lock = new Object(); + Sem sem = new Sem( 2 ); int type = svr == nbns ? 0x1b : 0x1d; - QueryThread q1x = new QueryThread( lock, name, type, null, svr ); - QueryThread q20 = new QueryThread( lock, name, 0x20, null, svr ); + QueryThread q1x = new QueryThread( sem, name, type, null, svr ); + QueryThread q20 = new QueryThread( sem, name, 0x20, null, svr ); q1x.setDaemon( true ); q20.setDaemon( true ); try { - synchronized( lock ) { + synchronized( sem ) { q1x.start(); q20.start(); - int i = 2; - while( i-- > 0 && q1x.ans == null && q20.ans == null ) { - lock.wait(); + while( sem.count > 0 && q1x.ans == null && q20.ans == null ) { +//System.out.println( "sem.count=" + sem.count + ",q1x.ans=" + q1x.ans + ",q20.ans=" + q20.ans ); + sem.wait(); } } } catch( InterruptedException ie ) { @@ -162,6 +184,15 @@ public class UniAddress { throw q1x.uhe; } } + +/** + * Determines the address of a host given it's host name. The name can be a + * machine name like "jcifs.samba.org", or an IP address like "192.168.1.15". + * + * @param host NetBIOS or DNS hostname to resolve + * @throws java.net.UnknownHostException if there is an error resolving the name + */ + public static UniAddress getByName( String hostname ) throws UnknownHostException { return getByName( hostname, false ); @@ -190,6 +221,11 @@ public class UniAddress { return false; } + static boolean isValidDnsName( String hostname ) { + // Simple for now. Just handles "1" --> 1/0.0.0.1 kind of stuff + return Character.isDigit( hostname.charAt( 0 )) == false; + } + public static UniAddress getByName( String hostname, boolean possibleNTDomainOrWorkgroup ) throws UnknownHostException { @@ -236,10 +272,13 @@ public class UniAddress { } break; case RESOLVER_DNS: + if( isValidDnsName( hostname ) == false ) { + throw new UnknownHostException( hostname ); + } addr = InetAddress.getByName( hostname ); break; default: - throw new UnknownHostException(); + throw new UnknownHostException( hostname ); } return new UniAddress( addr ); // Success } catch( IOException ioe ) { @@ -256,11 +295,15 @@ public class UniAddress { this.addr = addr; } + public int hashCode() { + return addr.hashCode(); + } public boolean equals( Object obj ) { - return obj instanceof UniAddress && addr.equals( ((UniAddress)obj).addr ); + return obj instanceof UniAddress && addr.hashCode() == obj.hashCode(); +// addr.equals( ((UniAddress)obj).addr ); } -/* Guess next called name to try for session establishment. These +/** Guess first called name to try for session establishment. This * methods are used by the smb package. */ public String firstCalledName() { @@ -284,6 +327,9 @@ public class UniAddress { return calledName; } +/** Guess next called name to try for session establishment. This + * methods are used by the smb package. + */ public String nextCalledName() { if( addr instanceof NbtAddress ) { return ((NbtAddress)addr).nextCalledName(); diff --git a/src/jcifs/http/NetworkExplorer.java b/src/jcifs/http/NetworkExplorer.java new file mode 100644 index 0000000..53ff1d4 --- /dev/null +++ b/src/jcifs/http/NetworkExplorer.java @@ -0,0 +1,443 @@ +/* jcifs smb client library in Java + * Copyright (C) 2002 "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.http; + +import java.io.*; +import javax.servlet.*; +import javax.servlet.http.*; +import java.util.*; +import java.text.SimpleDateFormat; +import java.net.UnknownHostException; +import jcifs.*; +import jcifs.http.*; +import jcifs.smb.*; +import jcifs.netbios.NbtAddress; +import jcifs.util.MimeMap; + +/** + * This servlet may be used to "browse" the entire hierarchy of resources + * on an SMB network like one might with Network Neighborhood or Windows + * Explorer. The users credentials with be negotiated using NTLM SSP if + * the client is Microsoft Internet Explorer. + * + * Please read jCIFS NTLM HTTP Authentication and the Network Explorer Servlet. + */ + +public class NetworkExplorer extends HttpServlet { + + MimeMap mimeMap; + String style; + NtlmSsp ntlmSsp; + boolean useNtlmSsp; + + public void init() throws ServletException { + InputStream is; + StringBuffer sb = new StringBuffer(); + byte[] buf = new byte[1024]; + int n; + String name; + + for( Enumeration e = getInitParameterNames(); e.hasMoreElements(); ) { + name = (String)e.nextElement(); + if( name.startsWith( "jcifs." )) { + Config.setProperty( name, getInitParameter( name )); + } + } + + try { + mimeMap = new MimeMap(); + is = getClass().getClassLoader().getResourceAsStream( "jcifs/http/ne.css" ); + while(( n = is.read( buf )) != -1 ) { + sb.append( new String( buf, 0, n, "ISO8859_1" )); + } + style = sb.toString(); + } catch( IOException ioe ) { + throw new ServletException( ioe.getMessage() ); + } + Config.setProperty( "jcifs.smb.client.attrExpirationPeriod", "120000" ); + + if( Config.getProperty( "jcifs.smb.client.username" ) == null ) { + ntlmSsp = new NtlmSsp(); + useNtlmSsp = true; + } + } + + String parseServerAndShare( String pathInfo ) { + char[] out = new char[256]; + char ch; + int len, p, i; + + if( pathInfo == null ) { + return null; + } + len = pathInfo.length(); + + p = i = 0; + while( p < len && pathInfo.charAt( p ) == '/' ) { + p++; + } + if( p == len ) { + return null; + } + out[i++] = pathInfo.charAt( p++ ); + while( p < len && ( ch = pathInfo.charAt( p++ )) != '/' ) { + out[i++] = ch; + } + if( p < len ) { + out[i++] = '/'; + while( p < len && pathInfo.charAt( p ) == '/' ) { + p++; + } + if( p == len ) { + return new String( out, 0, i - 1 ); + } + while( p < len && ( ch = pathInfo.charAt( p++ )) != '/' ) { + out[i++] = ch; + } + } + return new String( out, 0, i ); + } + void doFile( HttpServletRequest req, + HttpServletResponse resp, SmbFile file ) throws IOException { + byte[] buf = new byte[8192]; + SmbFileInputStream in; + ServletOutputStream out; + String url, type; + int n; + + in = new SmbFileInputStream( file ); + out = resp.getOutputStream(); + url = file.getPath(); + + resp.setContentType( "text/plain" ); + + if(( n = url.lastIndexOf( '.' )) > 0 && + ( type = url.substring( n + 1 )) != null && + type.length() > 1 && type.length() < 6 ) { + resp.setContentType( mimeMap.getMimeType( type )); + } + resp.setHeader( "Content-Length", file.length() + "" ); + resp.setHeader( "Accept-Ranges", "Bytes" ); + + while(( n = in.read( buf )) != -1 ) { + out.write( buf, 0, n ); + } + } + int compareNames( SmbFile f1, String f1name, SmbFile f2 ) throws IOException { + if( f1.isDirectory() != f2.isDirectory() ) { + return f1.isDirectory() ? -1 : 1; + } + return f1name.compareToIgnoreCase( f2.getName() ); + } + int compareSizes( SmbFile f1, String f1name, SmbFile f2 ) throws IOException { + long diff; + + if( f1.isDirectory() != f2.isDirectory() ) { + return f1.isDirectory() ? -1 : 1; + } + if( f1.isDirectory() ) { + return f1name.compareToIgnoreCase( f2.getName() ); + } + diff = f1.length() - f2.length(); + if( diff == 0 ) { + return f1name.compareToIgnoreCase( f2.getName() ); + } + return diff > 0 ? -1 : 1; + } + int compareTypes( SmbFile f1, String f1name, SmbFile f2 ) throws IOException { + String f2name, t1, t2; + int i; + + if( f1.isDirectory() != f2.isDirectory() ) { + return f1.isDirectory() ? -1 : 1; + } + f2name = f2.getName(); + if( f1.isDirectory() ) { + return f1name.compareToIgnoreCase( f2name ); + } + i = f1name.lastIndexOf( '.' ); + t1 = i == -1 ? "" : f1name.substring( i + 1 ); + i = f2name.lastIndexOf( '.' ); + t2 = i == -1 ? "" : f2name.substring( i + 1 ); + + i = t1.compareToIgnoreCase( t2 ); + if( i == 0 ) { + return f1name.compareToIgnoreCase( f2name ); + } + return i; + } + int compareDates( SmbFile f1, String f1name, SmbFile f2 ) throws IOException { + if( f1.isDirectory() != f2.isDirectory() ) { + return f1.isDirectory() ? -1 : 1; + } + if( f1.isDirectory() ) { + return f1name.compareToIgnoreCase( f2.getName() ); + } + return f1.lastModified() > f2.lastModified() ? -1 : 1; + } + void doDirectory( HttpServletRequest req, HttpServletResponse resp, SmbFile dir ) throws IOException { + PrintWriter out; + SmbFile[] dirents; + SmbFile f; + int i, j, len, maxLen, dirCount, fileCount, sort; + String str, name, path, fmt; + LinkedList sorted; + ListIterator iter; + SimpleDateFormat sdf = new SimpleDateFormat( "MM/d/yy h:mm a" ); + GregorianCalendar cal = new GregorianCalendar(); + + sdf.setCalendar( cal ); + + dirents = dir.listFiles(); + sorted = new LinkedList(); + if(( fmt = req.getParameter( "fmt" )) == null ) { + fmt = "col"; + } + sort = 0; + if(( str = req.getParameter( "sort" )) == null || str.equals( "name" )) { + sort = 0; + } else if( str.equals( "size" )) { + sort = 1; + } else if( str.equals( "type" )) { + sort = 2; + } else if( str.equals( "date" )) { + sort = 3; + } + dirCount = fileCount = 0; + maxLen = 28; + for( i = 0; i < dirents.length; i++ ) { + try { + if( dirents[i].getType() == SmbFile.TYPE_NAMED_PIPE ) { + continue; + } + } catch( SmbAuthException sae ) { + } + if( dirents[i].isDirectory() ) { + dirCount++; + } else { + fileCount++; + } + + name = dirents[i].getName(); + len = name.length(); + if( len > maxLen ) { + maxLen = len; + } + + iter = sorted.listIterator(); + for( j = 0; iter.hasNext(); j++ ) { + if( sort == 0 ) { + if( compareNames( dirents[i], name, (SmbFile)iter.next() ) < 0 ) { + break; + } + } else if( sort == 1 ) { + if( compareSizes( dirents[i], name, (SmbFile)iter.next() ) < 0 ) { + break; + } + } else if( sort == 2 ) { + if( compareTypes( dirents[i], name, (SmbFile)iter.next() ) < 0 ) { + break; + } + } else if( sort == 3 ) { + if( compareDates( dirents[i], name, (SmbFile)iter.next() ) < 0 ) { + break; + } + } + } + sorted.add( j, dirents[i] ); + } + if( maxLen > 50 ) { + maxLen = 50; + } + maxLen *= 9; /* convert to px */ + + out = resp.getWriter(); + + resp.setContentType( "text/html" ); + + out.println( "" ); + out.println( "Network Explorer" ); + out.println( "" ); + out.println( "" ); + out.println( "" ); + + out.print( "Name" ); + out.println( "Size" ); + out.println( "Type" ); + out.println( "Modified

" ); + + path = dir.getCanonicalPath(); + + if( path.length() < 7 ) { + out.println( "smb://
" ); + path = "."; + } else { + out.println( "" + path + "
" ); + path = "../"; + } + out.println( (dirCount + fileCount) + " objects (" + dirCount + " directories, " + fileCount + " files)
" ); + out.println( "normal | detailed" ); + out.println( "

" ); + + out.print( "" ); + if( fmt.equals( "detail" )) { + out.println( "
" ); + } + + if( path.length() == 1 || dir.getType() != SmbFile.TYPE_WORKGROUP ) { + path = ""; + } + + iter = sorted.listIterator(); + while( iter.hasNext() ) { + f = (SmbFile)iter.next(); + name = f.getName(); + + if( fmt.equals( "detail" )) { + out.print( "" ); + out.print( name ); + out.print( "" ); + } else { + out.print( "\">" ); + out.print( name ); + out.print( "
" ); + out.print( (f.length() / 1024) + " KB
" ); + i = name.lastIndexOf( '.' ) + 1; + if( i > 1 && (name.length() - i) < 6 ) { + out.print( name.substring( i ).toUpperCase() + "
" ); + } else { + out.print( " " ); + } + out.print( "
" ); + out.print( sdf.format( new Date( f.lastModified() ))); + out.print( "
" ); + } + out.println( "
" ); + } else { + out.print( "" ); + out.print( name ); + out.print( "" ); + } else { + out.print( ";\" HREF=\"" ); + out.print( path ); + out.print( name ); + out.print( "\">" ); + out.print( name ); + out.print( "
" ); + out.print( (f.length() / 1024) + "KB
" ); + out.print( sdf.format( new Date( f.lastModified() ))); + out.print( "
" ); + out.println( "" ); + } + } + } + + out.println( "
" ); + out.println( "" ); + out.close(); + } + public void doGet( HttpServletRequest req, + HttpServletResponse resp ) throws IOException, ServletException { + NtlmPasswordAuthentication ntlm; + UniAddress dc; + byte[] challenge; + String pathInfo, s; + SmbFile file; + + s = null; + if(( pathInfo = req.getPathInfo() ) != null ) { + s = parseServerAndShare( pathInfo ); + } + + if( useNtlmSsp ) { + String msg = req.getHeader( "Authorization" ); + if( msg == null || msg.startsWith( "NTLM " ) == false ) { + resp.setHeader( "WWW-Authenticate", "NTLM" ); + resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); + resp.flushBuffer(); + return; + } + + if( pathInfo == null || s == null ) { + s = NbtAddress.getByName( NbtAddress.MASTER_BROWSER_NAME, 0x01, null ).getHostAddress(); + dc = UniAddress.getByName( s ); + } else { + int i = s.indexOf( '/' ); + if( i > 0 ) { + s = s.substring( 0, i ); + } + dc = UniAddress.getByName( s, i == -1 ); + } + challenge = SmbSession.getChallenge( dc ); + + /* Be carefull what you put before this. It's called 3 times in a row + * before doAuthentication returns a good NtlmPasswordAuthentication + * object. + */ + + if(( ntlm = ntlmSsp.doAuthentication( req, resp, challenge )) == null ) { + return; + } + file = new SmbFile( "smb:/" + pathInfo , ntlm ); + } else if( s == null ) { + file = new SmbFile( "smb://" ); + } else { + file = new SmbFile( "smb:/" + pathInfo ); + } + + try { + if( file.isDirectory() ) { + doDirectory( req, resp, file ); + } else { + doFile( req, resp, file ); + } + } catch( SmbAuthException sae ) { + resp.setHeader( "WWW-Authenticate", "NTLM" ); + resp.setHeader( "Connection", "close" ); + resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); + resp.flushBuffer(); + return; + } + } +} + diff --git a/src/jcifs/http/NtlmHttpFilter.java b/src/jcifs/http/NtlmHttpFilter.java new file mode 100644 index 0000000..8b70e7d --- /dev/null +++ b/src/jcifs/http/NtlmHttpFilter.java @@ -0,0 +1,125 @@ +/* jcifs smb client library in Java + * Copyright (C) 2002 "Michael B. Allen" + * "Jason Pugsley" + * "skeetz" + * "Eric Glass" + * + * 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.http; + +import java.io.*; +import java.util.Enumeration; +import java.net.UnknownHostException; +import javax.servlet.*; +import javax.servlet.http.*; +import jcifs.*; +import jcifs.smb.SmbSession; +import jcifs.smb.NtlmPasswordAuthentication; +import jcifs.smb.SmbAuthException; + +/** + * This servlet Filter can be used to negotiate password hashes with + * MSIE clients using NTLM SSP. This is similar to Authentication: + * BASIC but weakly encrypted and without requiring the user to re-supply + * authentication credentials. + *

+ * Read jCIFS NTLM HTTP Authentication and the Network Explorer Servlet for complete details. + */ + +public class NtlmHttpFilter extends NtlmSsp implements Filter { + + private String domainController; + + public void init( FilterConfig filterConfig ) throws ServletException { + String name; + + /* Set jcifs properties we know we want; soTimeout and cachePolicy to 10min. + */ + Config.setProperty( "jcifs.smb.client.soTimeout", "300000" ); + Config.setProperty( "jcifs.netbios.cachePolicy", "600" ); + + Enumeration e = filterConfig.getInitParameterNames(); + while( e.hasMoreElements() ) { + name = (String)e.nextElement(); + if( name.startsWith( "jcifs." )) { + Config.setProperty( name, filterConfig.getInitParameter( name )); + } + } + + domainController = Config.getProperty( "jcifs.http.domainController" ); + if( domainController == null ) { + domainController = Config.getProperty( "jcifs.smb.client.domain" ); + } + } + public void destroy() { + } + public void doFilter( ServletRequest request, + ServletResponse response, + FilterChain chain ) throws IOException, ServletException { + HttpServletRequest req; + HttpServletResponse resp; + NtlmPasswordAuthentication ntlm; + UniAddress dc; + byte[] challenge; + String msg; + HttpSession ssn; + + req = (HttpServletRequest)request; + resp = (HttpServletResponse)response; + ssn = req.getSession(); + msg = req.getHeader( "Authorization" ); + + if( msg != null && msg.startsWith( "NTLM " )) { + dc = UniAddress.getByName( domainController, true ); + challenge = SmbSession.getChallenge( dc ); + if(( ntlm = doAuthentication( req, resp, challenge )) == null ) { + return; + } + try { + SmbSession.logon( dc, ntlm ); + } catch( SmbAuthException sae ) { + resp.setHeader( "WWW-Authenticate", "NTLM" ); + resp.setHeader( "Connection", "close" ); + resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); + resp.flushBuffer(); + return; + } + ssn.setAttribute( "NtlmHttpAuth", ntlm ); + } else if(( ntlm = (NtlmPasswordAuthentication)ssn.getAttribute( "NtlmHttpAuth" )) == null ) { + resp.setHeader( "WWW-Authenticate", "NTLM" ); + resp.setHeader( "Connection", "close" ); + resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); + resp.flushBuffer(); + return; + } + + chain.doFilter( new NtlmHttpServletRequest( req, ntlm ), response ); + } + + // Added by cgross to work with weblogic 6.1. + public void setFilterConfig( FilterConfig f ) { + try { + init( f ); + } catch( Exception e ) { + e.printStackTrace(); + } + } + public FilterConfig getFilterConfig() { + return null; + } +} + diff --git a/src/jcifs/util/AuthInfo.java b/src/jcifs/http/NtlmHttpServletRequest.java similarity index 55% rename from src/jcifs/util/AuthInfo.java rename to src/jcifs/http/NtlmHttpServletRequest.java index a8989e1..f8526ad 100644 --- a/src/jcifs/util/AuthInfo.java +++ b/src/jcifs/http/NtlmHttpServletRequest.java @@ -1,5 +1,6 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * Copyright (C) 2002 "Michael B. Allen" + * "Eric Glass" * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,13 +17,25 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package jcifs.util; +package jcifs.http; -public class AuthInfo { +import java.security.Principal; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; - public String target; - public String domain; - public String username; - public String password; - public Exception exception; +class NtlmHttpServletRequest extends HttpServletRequestWrapper { + + Principal principal; + + NtlmHttpServletRequest( HttpServletRequest req, Principal principal ) { + super( req ); + this.principal = principal; + } + public String getRemoteUser() { + return principal.getName(); + } + public Principal getUserPrincipal() { + return principal; + } } + diff --git a/src/jcifs/http/NtlmServlet.java b/src/jcifs/http/NtlmServlet.java new file mode 100644 index 0000000..14e47db --- /dev/null +++ b/src/jcifs/http/NtlmServlet.java @@ -0,0 +1,112 @@ +/* jcifs smb client library in Java + * Copyright (C) 2002 "Michael B. Allen" + * "Eric Glass" + * + * 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.http; + +import java.io.IOException; + +import java.net.UnknownHostException; + +import java.util.Enumeration; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.UnavailableException; + +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import jcifs.Config; +import jcifs.UniAddress; + +import jcifs.smb.NtlmPasswordAuthentication; +import jcifs.smb.SmbSession; + +/** + * This servlet may be used with pre-2.3 servlet containers + * to protect content with NTLM HTTP Authentication. Servlets that + * extend this abstract base class may be authenticatied against an SMB + * server or domain controller depending on how the + * jcifs.smb.client.domain or jcifs.http.domainController + * properties are be specified. With later containers the + * NtlmHttpFilter should be used/b>. For custom NTLM HTTP Authentication schemes the NtlmSsp may be used. + *

+ * Read jCIFS NTLM HTTP Authentication and the Network Explorer Servlet related information. + */ + +public abstract class NtlmServlet extends HttpServlet { + + private static final NtlmSsp AUTH = new NtlmSsp(); + + private UniAddress domainController; + + public void init(ServletConfig config) throws ServletException { + super.init(config); + + /* Set jcifs properties we know we want; soTimeout and cachePolicy to 10min. + */ + Config.setProperty( "jcifs.smb.client.soTimeout", "300000" ); + Config.setProperty( "jcifs.netbios.cachePolicy", "600" ); + + Enumeration e = config.getInitParameterNames(); + String name; + while (e.hasMoreElements()) { + name = (String) e.nextElement(); + if (name.startsWith("jcifs.")) { + Config.setProperty(name, config.getInitParameter(name)); + } + } + String dc = Config.getProperty("jcifs.http.domainController"); + if (dc == null && (dc = Config.getProperty( "jcifs.smb.client.domain" )) == null) { + throw new UnavailableException("No domain controller specified."); + } + try { + domainController = UniAddress.getByName(dc); + } catch (UnknownHostException ex) { + throw new UnavailableException("Specified DC unreachable."); + } + } + + protected void service(HttpServletRequest request, + HttpServletResponse response) throws ServletException, IOException { + String msg = request.getHeader("Authorization"); + if (msg != null && msg.startsWith("NTLM")) { + HttpSession ssn; + byte[] challenge = SmbSession.getChallenge(domainController); + NtlmPasswordAuthentication ntlm = AUTH.doAuthentication(request, + response, challenge); + if (ntlm == null) return; + SmbSession.logon(domainController, ntlm); + ssn = request.getSession(); + ssn.setAttribute("NtlmHttpAuth", ntlm); + ssn.setAttribute( "ntlmdomain", ntlm.getDomain() ); + ssn.setAttribute( "ntlmuser", ntlm.getUsername() ); + } else if (request.getSession().getAttribute("NtlmHttpAuth") == null) { + response.setHeader("WWW-Authenticate", "NTLM"); + response.setHeader("Connection", "close"); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.flushBuffer(); + return; + } + super.service(request, response); + } +} + diff --git a/src/jcifs/http/NtlmSsp.java b/src/jcifs/http/NtlmSsp.java new file mode 100644 index 0000000..d6a02d1 --- /dev/null +++ b/src/jcifs/http/NtlmSsp.java @@ -0,0 +1,131 @@ +/* jcifs smb client library in Java + * Copyright (C) 2002 "Michael B. Allen" + * "Jason Pugsley" + * "skeetz" + * + * 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.http; + +import java.io.*; +import javax.servlet.*; +import javax.servlet.http.*; +import jcifs.smb.NtlmPasswordAuthentication; +import jcifs.util.Base64; + +/** + * This class is used internally by NtlmHttpFilter, + * NtlmServlet, and NetworkExplorer to negiotiate password + * hashes via NTLM SSP with MSIE. It might also be used directly by servlet + * containers to incorporate similar functionality. + *

+ * How NTLMSSP is used in conjunction with HTTP and MSIE clients is + * described in an NTLM + * Authentication Scheme for HTTP.

Also, read jCIFS NTLM HTTP Authentication and + * the Network Explorer Servlet related information. + */ + +public class NtlmSsp { + + static final byte[] msg2 = { + (byte)0x4E, (byte)0x54, (byte)0x4C, (byte)0x4D, + (byte)0x53, (byte)0x53, (byte)0x50, (byte)0x00, + (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x28, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x01, (byte)0x82, (byte)0x00, (byte)0x00, + (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, + (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 + }; + + int readInt2( byte[] src, int srcIndex ) { + return ( src[srcIndex] & 0xFF ) + + (( src[srcIndex + 1] & 0xFF ) << 8 ); + } + + /* Decode the type-1-message and encode the type-2-message. Note the "domain" + * in the type-1-message isn't necessarily + * the authentication domain. There is a good possibilty it is only the + * workgroup used for browsing. The 3rd message with have the authenticating + * domain. + */ + int encodeType2Message( byte[] src, byte[] dst, byte[] challenge ) throws IOException { + +jcifs.util.Log.printHexDump( "type-1-message", src ); + + System.arraycopy( msg2, 0, dst, 0, 40 ); + System.arraycopy( challenge, 0, dst, 24, 8 ); + +jcifs.util.Log.printHexDump( "type-2-message", dst, 0, 40 ); + return 40; + } + /* Decode type-3-message. + */ + NtlmPasswordAuthentication decodeType3Message( byte[] src ) throws IOException { + int off, len; + byte[] lm_hash = new byte[24]; + byte[] nt_hash = new byte[24]; + String domain, user; + +jcifs.util.Log.printHexDump( "type-3-message", src ); + + off = readInt2( src, 16 ); + System.arraycopy( src, off, lm_hash, 0, 24 ); + off = readInt2( src, 24 ); + System.arraycopy( src, off, nt_hash, 0, 24 ); + len = readInt2( src, 28 ); + off = readInt2( src, 32 ); + domain = new String( src, off, len, "UnicodeLittleUnmarked" ); + len = readInt2( src, 36 ); + off = readInt2( src, 40 ); + user = new String( src, off, len, "UnicodeLittleUnmarked" ); + + return new NtlmPasswordAuthentication( domain, user, lm_hash, nt_hash ); + } + public NtlmPasswordAuthentication doAuthentication( HttpServletRequest req, + HttpServletResponse resp, byte[] challenge ) + throws IOException, ServletException { + String msg; + + msg = req.getHeader( "Authorization" ); + + if( msg != null && msg.startsWith( "NTLM " )) { + byte[] src = Base64.decode( msg.substring( 5 )); + + if( src[8] == 1 ) { + byte[] dst = new byte[40]; + + msg = Base64.encodeBytes( dst, 0, encodeType2Message( src, dst, challenge )); + + resp.setHeader( "WWW-Authenticate", "NTLM " + msg ); + resp.setContentLength( 0 ); + } else if( src[8] == 3 ) { + return decodeType3Message( src ); + } + } else { + resp.setHeader( "WWW-Authenticate", "NTLM" ); + resp.setHeader( "Connection", "close" ); + } + resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED ); + resp.flushBuffer(); + + return null; + } +} + diff --git a/src/jcifs/http/ne.css b/src/jcifs/http/ne.css new file mode 100644 index 0000000..3e59350 --- /dev/null +++ b/src/jcifs/http/ne.css @@ -0,0 +1,68 @@ + a { + display: block; + float: left; + width: 300px; + height: 50px; + padding: 2px; + font-family: Verdana, sans-serif; + font-size: 10pt; + color: #000000; + text-decoration: none; + } + a.plain { + display: inline; + float: none; + width: auto; + height: auto; + } + a.sort { + display: block; + float: left; + width: 100px; + height: 15px; + font-family: Verdana, sans-serif; + font-size: 8pt; + font-weight: bold; + text-decoration: none; + color: #000000; + background-color: #d0d0d0; + border-top-color: #ffffff; + border-bottom-color: #707070; + border-right-color: #707070; + border-left-color: #ffffff; + border-style: solid solid; + border-top-width: 1px; + border-bottom-width: 2px; + border-right-width: 2px; + border-left-width: 1px; + } + a:visited { + color: #333897; + } + a.sort:hover { + background-color: #d0d0d0; + } + a.sort:visited { + color: #000000; + } + div { + float: left; + width: 100px; + height: 18px; + padding: 2px; + font-family: Verdana, sans-serif; + font-size: 10pt; + } + body { + font-family: Verdana, sans-serif; + font-size: 10pt; + background-color: #ffffff; + margin-top: 0; + margin-left: 5; + } + small { + font-size: 8pt; + } + big { + font-size: 14pt; + } diff --git a/src/jcifs/netbios/Lmhosts.java b/src/jcifs/netbios/Lmhosts.java index 6e11029..1e50925 100644 --- a/src/jcifs/netbios/Lmhosts.java +++ b/src/jcifs/netbios/Lmhosts.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/Log.java b/src/jcifs/netbios/Log.java index 12e07fe..2ce7bba 100644 --- a/src/jcifs/netbios/Log.java +++ b/src/jcifs/netbios/Log.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/Name.java b/src/jcifs/netbios/Name.java index 449a732..330aebd 100644 --- a/src/jcifs/netbios/Name.java +++ b/src/jcifs/netbios/Name.java @@ -1,6 +1,6 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" - * "Christopher R. Hertel" + * Copyright (C) 2000 "Michael B. Allen" + * "Christopher R. Hertel" * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,7 @@ package jcifs.netbios; +import java.io.UnsupportedEncodingException; import jcifs.Config; class Name { @@ -31,9 +32,9 @@ class Name { static String toHexChars( int val ) { int len = 2; - byte[] tmp = new byte[2]; + char[] tmp = new char[2]; while( len > 0 ) { - tmp[ len - 1 ] = (byte)HEX_DIGITS[ val & 0x000F ]; + tmp[ len - 1 ] = HEX_DIGITS[val & 0x000F]; if( val != 0 ) { val >>>= 4; } @@ -46,6 +47,7 @@ class Name { static final int SCOPE_OFFSET = 33; static String defaultScope = Config.getProperty( "jcifs.netbios.scope" ); + static String encoding = Config.getProperty( "jcifs.netbios.encoding", "ISO8859_1" ); String name, scope; int hexCode; @@ -70,18 +72,21 @@ class Name { dst[dstIndex] = 0x20; // write name - byte tmp[] = name.getBytes(); - int i; - for( i = 0; i < tmp.length; i++ ) { - dst[dstIndex + ( 2 * i + 1 )] = (byte)((( tmp[i] & 0xF0 ) >> 4 ) + 0x41 ); - dst[dstIndex + ( 2 * i + 2 )] = (byte)(( tmp[i] & 0x0F ) + 0x41 ); - } - for( ; i < 15; i++ ) { - dst[dstIndex + ( 2 * i + 1 )] = (byte)0x43; - dst[dstIndex + ( 2 * i + 2 )] = (byte)0x41; - } - dst[dstIndex + TYPE_OFFSET] = (byte)((( hexCode & 0xF0 ) >> 4 ) + 0x41 ); - dst[dstIndex + TYPE_OFFSET + 1] = (byte)(( hexCode & 0x0F ) + 0x41 ); + try { + byte tmp[] = name.getBytes( Name.encoding ); + int i; + for( i = 0; i < tmp.length; i++ ) { + dst[dstIndex + ( 2 * i + 1 )] = (byte)((( tmp[i] & 0xF0 ) >> 4 ) + 0x41 ); + dst[dstIndex + ( 2 * i + 2 )] = (byte)(( tmp[i] & 0x0F ) + 0x41 ); + } + for( ; i < 15; i++ ) { + dst[dstIndex + ( 2 * i + 1 )] = (byte)0x43; + dst[dstIndex + ( 2 * i + 2 )] = (byte)0x41; + } + dst[dstIndex + TYPE_OFFSET] = (byte)((( hexCode & 0xF0 ) >> 4 ) + 0x41 ); + dst[dstIndex + TYPE_OFFSET + 1] = (byte)(( hexCode & 0x0F ) + 0x41 ); + } catch( UnsupportedEncodingException uee ) { + } return SCOPE_OFFSET + writeScopeWireFormat( dst, dstIndex + SCOPE_OFFSET ); } @@ -96,7 +101,10 @@ class Name { length = i + 1; } } - name = new String( tmp, 0, length ); + try { + name = new String( tmp, 0, length, Name.encoding ); + } catch( UnsupportedEncodingException uee ) { + } hexCode = (( src[srcIndex + TYPE_OFFSET] & 0xFF ) - 0x41 ) << 4; hexCode |= (( src[srcIndex + TYPE_OFFSET + 1] & 0xFF ) - 0x41 ) & 0x0F; return SCOPE_OFFSET + readScopeWireFormat( src, srcIndex + SCOPE_OFFSET ); @@ -109,7 +117,10 @@ class Name { // copy new scope in dst[dstIndex++] = (byte)'.'; - System.arraycopy( scope.getBytes(), 0, dst, dstIndex, scope.length() ); + try { + System.arraycopy( scope.getBytes( encoding ), 0, dst, dstIndex, scope.length() ); + } catch( UnsupportedEncodingException uee ) { + } dstIndex += scope.length(); dst[dstIndex++] = (byte)0x00; @@ -140,13 +151,16 @@ class Name { return 1; } - sb = new StringBuffer( new String( src, srcIndex, n )); - srcIndex += n; - while(( n = src[srcIndex++] & 0xFF ) != 0 ) { - sb.append( '.' ).append( new String( src, srcIndex, n )); + try { + sb = new StringBuffer( new String( src, srcIndex, n, Name.encoding )); srcIndex += n; + while(( n = src[srcIndex++] & 0xFF ) != 0 ) { + sb.append( '.' ).append( new String( src, srcIndex, n, Name.encoding )); + srcIndex += n; + } + scope = sb.toString(); + } catch( UnsupportedEncodingException uee ) { } - scope = sb.toString(); return srcIndex - start; } @@ -181,12 +195,14 @@ class Name { String n = name; // fix MSBROWSE name - if( n.charAt( 0 ) == 0x01 ) { - byte b[] = n.getBytes(); - b[0] = (byte)'.'; - b[1] = (byte)'.'; - b[14] = (byte)'.'; - n = new String( b ); + if( n == null ) { + n = "null"; + } else if( n.charAt( 0 ) == 0x01 ) { + char c[] = n.toCharArray(); + c[0] = '.'; + c[1] = '.'; + c[14] = '.'; + n = new String( c ); } sb.append( n ).append( "<" ).append( toHexChars( hexCode )).append( ">" ); diff --git a/src/jcifs/netbios/NameQueryRequest.java b/src/jcifs/netbios/NameQueryRequest.java index 3bdc0a9..97d5b01 100644 --- a/src/jcifs/netbios/NameQueryRequest.java +++ b/src/jcifs/netbios/NameQueryRequest.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/NameQueryResponse.java b/src/jcifs/netbios/NameQueryResponse.java index 1027e5f..a9a5942 100644 --- a/src/jcifs/netbios/NameQueryResponse.java +++ b/src/jcifs/netbios/NameQueryResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/NameServiceClient.java b/src/jcifs/netbios/NameServiceClient.java index c5a4acc..f763ef1 100644 --- a/src/jcifs/netbios/NameServiceClient.java +++ b/src/jcifs/netbios/NameServiceClient.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -119,7 +119,7 @@ class NameServiceClient implements Runnable { } else if( s.equalsIgnoreCase( "BCAST" )) { tmp[i++] = RESOLVER_BCAST; } else if( s.equalsIgnoreCase( "DNS" )) { - i++; // skip + ; // skip } else { Log.println( Log.WARNINGS, "netbios name service warning", "unknown resolver method: " + s ); @@ -145,7 +145,7 @@ class NameServiceClient implements Runnable { // be ignored; see tryClose comment. if( socket == null ) { socket = new DatagramSocket( port, laddr ); - thread = new Thread( this ); + thread = new Thread( this, "JCIFS-NameServiceClient" ); thread.setDaemon( true ); thread.start(); } @@ -180,7 +180,7 @@ class NameServiceClient implements Runnable { socket.receive( in ); } catch( IOException ioe ) { tryClose(); - continue; + break; } Log.println( Log.DEBUGGING, "nbt name service debugging", @@ -255,13 +255,14 @@ class NameServiceClient implements Runnable { Log.printStackTrace( "nbt name service send:", ioe ); throw new UnknownHostException( ioe.getMessage() ); } + if( response.received && response.resultCode == 0 ) { response.addrEntry.hostName.srcHashCode = addr.hashCode(); return response.addrEntry; } } while( --n > 0 && request.isBroadcast ); - throw new UnknownHostException( name.name ); + throw new UnknownHostException( name.toString() ); } /* If a target address to query was not specified explicitly diff --git a/src/jcifs/netbios/NameServicePacket.java b/src/jcifs/netbios/NameServicePacket.java index f3e455f..086e073 100644 --- a/src/jcifs/netbios/NameServicePacket.java +++ b/src/jcifs/netbios/NameServicePacket.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/NbtAddress.java b/src/jcifs/netbios/NbtAddress.java index aa7df31..b93409e 100644 --- a/src/jcifs/netbios/NbtAddress.java +++ b/src/jcifs/netbios/NbtAddress.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -22,6 +22,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.net.SocketException; import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.util.Hashtable; import jcifs.Config; @@ -77,42 +78,26 @@ import jcifs.Config; public final class NbtAddress { - static final byte[] MASTER_BROWSER_BYTES = { - (byte)0x01, (byte)0x02, (byte)0x5F, (byte)0x5F, (byte)0x4D, (byte)0x53, - (byte)0x42, (byte)0x52, (byte)0x4F, (byte)0x57, (byte)0x53, (byte)0x45, - (byte)0x5F, (byte)0x5F, (byte)0x02 - }; - static final byte[] SMBSERVER_BYTES = { - (byte)0x2a, (byte)0x53, (byte)0x4d, (byte)0x42, (byte)0x53, (byte)0x45, - (byte)0x52, (byte)0x56, (byte)0x45, (byte)0x52, (byte)0x20, (byte)0x20, - (byte)0x20, (byte)0x20, (byte)0x20 - }; - static final byte[] ALL_HOSTS_BYTES = { - (byte)0x2A, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x00 - }; - /* * This is a special name that means all hosts. If you wish to find all hosts * on a network querying a workgroup group name is the preferred method. */ - static final String ANY_HOSTS_NAME = new String( ALL_HOSTS_BYTES ); + static final String ANY_HOSTS_NAME = "*\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000"; /** * This is a special name for querying the master browser that serves the * list of hosts found in "Network Neighborhood". */ - public static final String MASTER_BROWSER_NAME = new String( MASTER_BROWSER_BYTES ); + public static final String MASTER_BROWSER_NAME = "\u0001\u0002__MSBROWSE__\u0002"; /** * A special generic name specified when connecting to a host for which * a name is not known. Not all servers respond to this name. */ - public static final String SMBSERVER_NAME = new String( SMBSERVER_BYTES ); + public static final String SMBSERVER_NAME = "*SMBSERVER "; /** * A B node only broadcasts name queries. This is the default if a @@ -149,6 +134,7 @@ public final class NbtAddress { static int cachePolicy; static Hashtable addressCache; + static Hashtable lookupTable; static Name unknownName; static NbtAddress unknownAddress; static byte[] unknownMacAddress = new byte[] { @@ -177,6 +163,7 @@ public final class NbtAddress { Name localName; addressCache = new Hashtable(); + lookupTable = new Hashtable(); cachePolicy = Config.getInt( "jcifs.netbios.cachePolicy", DEFAULT_CACHE_POLICY ); /* Construct the shared static client object that will @@ -223,7 +210,7 @@ public final class NbtAddress { * the name deduced above possibly with scope applied and * cache it forever. */ - localName = new Name( localHostname, 0x20, + localName = new Name( localHostname, 0x00, Config.getProperty( "jcifs.netbios.scope", null )); localhost = new NbtAddress( localName, localInetAddress.hashCode(), @@ -307,12 +294,19 @@ public final class NbtAddress { addr = getCachedAddress( name ); if( addr == null ) { - try { - addr = client.getByName( name, svr ); - } catch( UnknownHostException uhe ) { - addr = unknownAddress; - } finally { - cacheAddress( name, addr ); + /* This was copied amost verbatim from InetAddress.java. See the + * comments there for a description of how the lookupTable prevents + * redundant queries from going out on the wire. + */ + if(( addr = (NbtAddress)checkLookupTable( name )) == null ) { + try { + addr = client.getByName( name, svr ); + } catch( UnknownHostException uhe ) { + addr = unknownAddress; + } finally { + cacheAddress( name, addr ); + updateLookupTable( name ); + } } } if( addr == unknownAddress ) { @@ -321,6 +315,37 @@ public final class NbtAddress { return addr; } + private static Object checkLookupTable( Name name ) { + Object obj; + + synchronized( lookupTable ) { + if( lookupTable.containsKey( name ) == false ) { + lookupTable.put( name, name ); + return null; + } + while( lookupTable.containsKey( name )) { + try { + lookupTable.wait(); + } catch( InterruptedException e ) { + } + } + } + obj = getCachedAddress( name ); + if( obj == null ) { + synchronized( lookupTable ) { + lookupTable.put( name, name ); + } + } + + return obj; + } + private static void updateLookupTable( Name name ) { + synchronized( lookupTable ) { + lookupTable.remove( name ); + lookupTable.notifyAll(); + } + } + /** * Retrieves the local host address. * @@ -333,8 +358,10 @@ public final class NbtAddress { } /** - * Determines the address of a host given it's host name. The name can be a - * machine name like "jcifs.samba.org" or an IP address like "192.168.1.15". + * Determines the address of a host given it's host name. The name can be a NetBIOS name like + * "freto" or an IP address like "192.168.1.15". It cannot be a DNS name; + * the analygous {@link jcifs.UniAddress} or {@link java.net.InetAddress} + * getByName methods can be used for that. * * @param host hostname to resolve * @throws java.net.UnknownHostException if there is an error resolving the name @@ -552,7 +579,7 @@ public final class NbtAddress { calledName = SMBSERVER_NAME; break; } - if( data[i] == '.' ) { + if( i < len && data[i] == '.' ) { dots++; i++; } diff --git a/src/jcifs/netbios/NbtException.java b/src/jcifs/netbios/NbtException.java index c97994f..2934568 100644 --- a/src/jcifs/netbios/NbtException.java +++ b/src/jcifs/netbios/NbtException.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/NbtSocket.java b/src/jcifs/netbios/NbtSocket.java index 3258f97..2a2b5bd 100644 --- a/src/jcifs/netbios/NbtSocket.java +++ b/src/jcifs/netbios/NbtSocket.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/NodeStatusRequest.java b/src/jcifs/netbios/NodeStatusRequest.java index 841fe92..c4a6749 100644 --- a/src/jcifs/netbios/NodeStatusRequest.java +++ b/src/jcifs/netbios/NodeStatusRequest.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -23,6 +23,8 @@ class NodeStatusRequest extends NameServicePacket { NodeStatusRequest( Name name ) { questionName = name; questionType = NBSTAT; + isRecurDesired = false; + isBroadcast = false; } int writeBodyWireFormat( byte[] dst, int dstIndex ) { diff --git a/src/jcifs/netbios/NodeStatusResponse.java b/src/jcifs/netbios/NodeStatusResponse.java index c6efc2e..dc6787c 100644 --- a/src/jcifs/netbios/NodeStatusResponse.java +++ b/src/jcifs/netbios/NodeStatusResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,6 +18,8 @@ package jcifs.netbios; +import java.io.UnsupportedEncodingException; + class NodeStatusResponse extends NameServicePacket { NbtAddress queryAddress; @@ -80,53 +82,57 @@ class NodeStatusResponse extends NameServicePacket { boolean isPermanent; int j; boolean addrFound = false; - for( int i = 0; i < numberOfNames; srcIndex += 18, i++ ) { - for( j = srcIndex + 14; src[j] == 0x20; j-- ) - ; - n = new String( src, srcIndex, j - srcIndex + 1 ); - hexCode = src[srcIndex + 15] & 0xFF; - groupName = (( src[srcIndex + 16] & 0x80 ) == 0x80 ) ? true : false; - ownerNodeType = ( src[srcIndex + 16] & 0x60 ) >> 5; - isBeingDeleted = (( src[srcIndex + 16] & 0x10 ) == 0x10 ) ? true : false; - isInConflict = (( src[srcIndex + 16] & 0x08 ) == 0x08 ) ? true : false; - isActive = (( src[srcIndex + 16] & 0x04 ) == 0x04 ) ? true : false; - isPermanent = (( src[srcIndex + 16] & 0x02 ) == 0x02 ) ? true : false; - -/* The NbtAddress object used to query this node will be in the list - * returned by the Node Status. A new NbtAddress object should not be - * created for it because the original is potentially being actively - * referenced by other objects. We must populate the existing object's - * data explicitly (and carefully). - */ - if( !addrFound && queryAddress.hostName.hexCode == hexCode && - ( queryAddress.hostName == NbtAddress.unknownName || - queryAddress.hostName.name.equals( n ))) { - if( queryAddress.hostName == NbtAddress.unknownName ) { - queryAddress.hostName = new Name( n, hexCode, scope ); - } - queryAddress.groupName = groupName; - queryAddress.nodeType = ownerNodeType; - queryAddress.isBeingDeleted = isBeingDeleted; - queryAddress.isInConflict = isInConflict; - queryAddress.isActive = isActive; - queryAddress.isPermanent = isPermanent; - queryAddress.macAddress = macAddress; - queryAddress.isDataFromNodeStatus = true; - addrFound = true; - addressArray[i] = queryAddress; - } else { - addressArray[i] = new NbtAddress( new Name( n, hexCode, scope ), - queryAddress.address, - groupName, - ownerNodeType, - isBeingDeleted, - isInConflict, - isActive, - isPermanent, - macAddress ); - } - } + try { + for( int i = 0; i < numberOfNames; srcIndex += 18, i++ ) { + for( j = srcIndex + 14; src[j] == 0x20; j-- ) + ; + n = new String( src, srcIndex, j - srcIndex + 1, Name.encoding ); + hexCode = src[srcIndex + 15] & 0xFF; + groupName = (( src[srcIndex + 16] & 0x80 ) == 0x80 ) ? true : false; + ownerNodeType = ( src[srcIndex + 16] & 0x60 ) >> 5; + isBeingDeleted = (( src[srcIndex + 16] & 0x10 ) == 0x10 ) ? true : false; + isInConflict = (( src[srcIndex + 16] & 0x08 ) == 0x08 ) ? true : false; + isActive = (( src[srcIndex + 16] & 0x04 ) == 0x04 ) ? true : false; + isPermanent = (( src[srcIndex + 16] & 0x02 ) == 0x02 ) ? true : false; + + /* The NbtAddress object used to query this node will be in the list + * returned by the Node Status. A new NbtAddress object should not be + * created for it because the original is potentially being actively + * referenced by other objects. We must populate the existing object's + * data explicitly (and carefully). + */ + if( !addrFound && queryAddress.hostName.hexCode == hexCode && + ( queryAddress.hostName == NbtAddress.unknownName || + queryAddress.hostName.name.equals( n ))) { + + if( queryAddress.hostName == NbtAddress.unknownName ) { + queryAddress.hostName = new Name( n, hexCode, scope ); + } + queryAddress.groupName = groupName; + queryAddress.nodeType = ownerNodeType; + queryAddress.isBeingDeleted = isBeingDeleted; + queryAddress.isInConflict = isInConflict; + queryAddress.isActive = isActive; + queryAddress.isPermanent = isPermanent; + queryAddress.macAddress = macAddress; + queryAddress.isDataFromNodeStatus = true; + addrFound = true; + addressArray[i] = queryAddress; + } else { + addressArray[i] = new NbtAddress( new Name( n, hexCode, scope ), + queryAddress.address, + groupName, + ownerNodeType, + isBeingDeleted, + isInConflict, + isActive, + isPermanent, + macAddress ); + } + } + } catch( UnsupportedEncodingException uee ) { + } return srcIndex - start; } public String toString() { diff --git a/src/jcifs/netbios/SessionRequestPacket.java b/src/jcifs/netbios/SessionRequestPacket.java index 2faed0e..26618d2 100644 --- a/src/jcifs/netbios/SessionRequestPacket.java +++ b/src/jcifs/netbios/SessionRequestPacket.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/SessionRetargetResponsePacket.java b/src/jcifs/netbios/SessionRetargetResponsePacket.java index 2b55958..cf02b87 100644 --- a/src/jcifs/netbios/SessionRetargetResponsePacket.java +++ b/src/jcifs/netbios/SessionRetargetResponsePacket.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/SessionServicePacket.java b/src/jcifs/netbios/SessionServicePacket.java index e88e5d4..f90cdb2 100644 --- a/src/jcifs/netbios/SessionServicePacket.java +++ b/src/jcifs/netbios/SessionServicePacket.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/SocketInputStream.java b/src/jcifs/netbios/SocketInputStream.java index 0627c20..25e5493 100644 --- a/src/jcifs/netbios/SocketInputStream.java +++ b/src/jcifs/netbios/SocketInputStream.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/netbios/SocketOutputStream.java b/src/jcifs/netbios/SocketOutputStream.java index 177bb70..37c1e69 100644 --- a/src/jcifs/netbios/SocketOutputStream.java +++ b/src/jcifs/netbios/SocketOutputStream.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -25,7 +25,7 @@ import jcifs.util.Log; class SocketOutputStream extends FilterOutputStream { - private static int DEFAULT_BUFR_SIZE = 1500; + private static int DEFAULT_BUFR_SIZE = 4400; private byte[] bufr; private int count, writeSize; @@ -54,7 +54,7 @@ class SocketOutputStream extends FilterOutputStream { bufr[count++] = (byte)b; } public synchronized void write( byte[] b, int off, int len ) throws IOException { - if( len >= bufr.length ) { + if(( len + 4 ) > bufr.length ) { Log.println( Log.WARNINGS, "session service warning", "write len exceeds pre-allocated buffer size; performance " + "will suffer: len=" + len + ",writeSize=" + writeSize ); diff --git a/src/jcifs/util/AuthHandler.java b/src/jcifs/smb/AllocInfo.java similarity index 82% rename from src/jcifs/util/AuthHandler.java rename to src/jcifs/smb/AllocInfo.java index 6ef6ef5..42325d3 100644 --- a/src/jcifs/util/AuthHandler.java +++ b/src/jcifs/smb/AllocInfo.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * Copyright (C) 2002 "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 @@ -16,9 +16,9 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -package jcifs.util; +package jcifs.smb; -public interface AuthHandler { - - public boolean authenticate( AuthInfo auth ); +interface AllocInfo { + long getCapacity(); + long getFree(); } diff --git a/src/jcifs/smb/AndXServerMessageBlock.java b/src/jcifs/smb/AndXServerMessageBlock.java index cc471ba..f4f5955 100644 --- a/src/jcifs/smb/AndXServerMessageBlock.java +++ b/src/jcifs/smb/AndXServerMessageBlock.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/BufferCache.java b/src/jcifs/smb/BufferCache.java index 38c1246..41d1ec8 100644 --- a/src/jcifs/smb/BufferCache.java +++ b/src/jcifs/smb/BufferCache.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/Handler.java b/src/jcifs/smb/Handler.java index c76a6b6..84ac84c 100644 --- a/src/jcifs/smb/Handler.java +++ b/src/jcifs/smb/Handler.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -22,23 +22,86 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import java.io.PrintStream; public class Handler extends URLStreamHandler { - SmbFile f; + static final URLStreamHandler SMB_HANDLER = new Handler(); + +static void printURL( URL u, PrintStream out ) { + out.println( "host=" + u.getHost() + ",port=" + u.getPort() + ",authority=" + u.getAuthority() + ",userInfo=" + u.getUserInfo() + ",path=" + u.getPath() + ",query=" + u.getQuery() + ",ref=" + u.getRef() ); +} + + static String unescape( String str ) throws NumberFormatException, UnsupportedEncodingException { + char ch; + int i, j, state, len; + char[] out; + byte[] b = new byte[1]; + + if( str == null ) { + return null; + } + + len = str.length(); + out = new char[len]; + state = 0; + for( i = j = 0; i < len; i++ ) { + switch( state ) { + case 0: + ch = str.charAt( i ); + if( ch == '%' ) { + state = 1; + } else { + out[j++] = ch; + } + break; + case 1: + /* Get ASCII hex value and convert to platform dependant + * encoding like EBCDIC perhaps + */ + b[0] = (byte)(Integer.parseInt( str.substring( i, i + 2 ), 16 ) & 0xFF); + out[j++] = (new String( b, 0, 1, "ASCII" )).charAt( 0 ); + i++; + state = 0; + } + } + + return new String( out, 0, j ); + } + protected int getDefaultPort() { + return 139; + } public URLConnection openConnection( URL u ) throws IOException { - return new SmbURLConnection( u, f ); + return new SmbFile( u ); } protected void parseURL( URL u, String spec, int start, int limit ) { + String host = u.getHost(); + String userinfo, path, ref; + if( spec.equals( "smb://" )) { + spec = "smb:////"; + limit += 2; + } else if( spec.startsWith( "smb://" ) == false && + host != null && host.length() == 0 ) { + spec = "//" + spec; + limit += 2; + } + super.parseURL( u, spec, start, limit ); + userinfo = u.getUserInfo(); + path = u.getPath(); + ref = u.getRef(); try { - f = new SmbFile( spec, null, start, limit ); - } catch( IOException ioe ) { - Log.printStackTrace( "smb URLStreamHandler exception", ioe ); + userinfo = unescape( userinfo ); + } catch( UnsupportedEncodingException uee ) { } - setURL( u, "smb", f.server, f.port, f.canonicalPath, null ); - } - protected String toExternalForm( URL u ) { - return f.toString(); + if (ref != null) { + path += '#' + ref; + } + setURL( u, "smb://", u.getHost(), getDefaultPort(), + u.getAuthority(), userinfo, + path, u.getQuery(), null ); +//printURL( u, System.err ); } } diff --git a/src/jcifs/smb/Info.java b/src/jcifs/smb/Info.java index f800ff7..b9a3dbf 100644 --- a/src/jcifs/smb/Info.java +++ b/src/jcifs/smb/Info.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/Log.java b/src/jcifs/smb/Log.java index ed66505..94ad2b6 100644 --- a/src/jcifs/smb/Log.java +++ b/src/jcifs/smb/Log.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/NetServerEnum2.java b/src/jcifs/smb/NetServerEnum2.java index 81f3e8b..b9e8dc1 100644 --- a/src/jcifs/smb/NetServerEnum2.java +++ b/src/jcifs/smb/NetServerEnum2.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,13 +18,14 @@ package jcifs.smb; +import java.io.UnsupportedEncodingException; + class NetServerEnum2 extends SmbComTransaction { static final int SV_TYPE_ALL = 0xFFFFFFFF; static final int SV_TYPE_DOMAIN_ENUM = 0x80000000; - static final byte[] descripters = new String( - "WrLehDz" + '\0' + "B16BBDz" + '\0' ).getBytes(); + static final String DESCR = "WrLehDz\u0000B16BBDz\u0000"; String domain; int serverTypes; @@ -33,6 +34,7 @@ class NetServerEnum2 extends SmbComTransaction { this.domain = domain; this.serverTypes = serverTypes; command = SMB_COM_TRANSACTION; + subCommand = NET_SERVER_ENUM2; // not really true be used by upper logic name = "\\PIPE\\LANMAN"; maxParameterCount = 8; @@ -46,11 +48,18 @@ class NetServerEnum2 extends SmbComTransaction { } int writeParametersWireFormat( byte[] dst, int dstIndex ) { int start = dstIndex; + byte[] descr; + + try { + descr = DESCR.getBytes( "ASCII" ); + } catch( UnsupportedEncodingException uee ) { + return 0; + } writeInt2( NET_SERVER_ENUM2, dst, dstIndex ); dstIndex += 2; - System.arraycopy( descripters, 0, dst, dstIndex, descripters.length ); - dstIndex += descripters.length; + System.arraycopy( descr, 0, dst, dstIndex, descr.length ); + dstIndex += descr.length; writeInt2( 0x0001, dst, dstIndex ); dstIndex += 2; writeInt2( maxDataCount, dst, dstIndex ); diff --git a/src/jcifs/smb/NetServerEnum2Response.java b/src/jcifs/smb/NetServerEnum2Response.java index c2d1903..747be59 100644 --- a/src/jcifs/smb/NetServerEnum2Response.java +++ b/src/jcifs/smb/NetServerEnum2Response.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -79,8 +79,7 @@ class NetServerEnum2Response extends SmbComTransactionResponse { results = new ServerInfo1[entriesReturned]; for( int i = 0; i < entriesReturned; i++ ) { results[i] = new ServerInfo1(); - results[i].name = new String( buffer, bufferIndex, - readStringLength( buffer, bufferIndex, 16 )); + results[i].name = readString( buffer, bufferIndex, 16, false ); bufferIndex += 16; results[i].versionMajor = (int)( buffer[bufferIndex++] & 0xFF ); results[i].versionMinor = (int)( buffer[bufferIndex++] & 0xFF ); @@ -90,9 +89,8 @@ class NetServerEnum2Response extends SmbComTransactionResponse { bufferIndex += 4; off = ( off & 0xFFFF ) - converter; off = start + off; - results[i].commentOrMasterBrowser = new String( buffer, off, - readStringLength( buffer, off, 48 )); -Log.println( Log.DEBUGGING, "net server enum response entry", results[i] ); + results[i].commentOrMasterBrowser = readString( buffer, off, 48, false ); +Log.println( Log.WARNINGS, "net server enum response entry", results[i] ); } return bufferIndex - start; diff --git a/src/jcifs/smb/NetShareEnum.java b/src/jcifs/smb/NetShareEnum.java index 01e26ae..56c04d0 100644 --- a/src/jcifs/smb/NetShareEnum.java +++ b/src/jcifs/smb/NetShareEnum.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,13 +18,15 @@ package jcifs.smb; +import java.io.UnsupportedEncodingException; + class NetShareEnum extends SmbComTransaction { - static final byte[] descripters = new String( - "WrLeh" + '\0' + "B13BWz" + '\0' ).getBytes(); + static final String DESCR = "WrLeh\u0000B13BWz\u0000"; NetShareEnum() { command = SMB_COM_TRANSACTION; + subCommand = NET_SHARE_ENUM; // not really true be used by upper logic name = new String( "\\PIPE\\LANMAN" ); maxParameterCount = 8; @@ -39,11 +41,18 @@ class NetShareEnum extends SmbComTransaction { } int writeParametersWireFormat( byte[] dst, int dstIndex ) { int start = dstIndex; + byte[] descr; + + try { + descr = DESCR.getBytes( "ASCII" ); + } catch( UnsupportedEncodingException uee ) { + return 0; + } writeInt2( NET_SHARE_ENUM, dst, dstIndex ); dstIndex += 2; - System.arraycopy( descripters, 0, dst, dstIndex, descripters.length ); - dstIndex += descripters.length; + System.arraycopy( descr, 0, dst, dstIndex, descr.length ); + dstIndex += descr.length; writeInt2( 0x0001, dst, dstIndex ); dstIndex += 2; writeInt2( maxDataCount, dst, dstIndex ); diff --git a/src/jcifs/smb/NetShareEnumResponse.java b/src/jcifs/smb/NetShareEnumResponse.java index 3c80143..662f6b9 100644 --- a/src/jcifs/smb/NetShareEnumResponse.java +++ b/src/jcifs/smb/NetShareEnumResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -77,8 +77,7 @@ class NetShareEnumResponse extends SmbComTransactionResponse { results = new ShareInfo1[entriesReturned]; for( int i = 0; i < entriesReturned; i++ ) { results[i] = new ShareInfo1(); - results[i].netName = new String( buffer, bufferIndex, - readStringLength( buffer, bufferIndex, 13 )); + results[i].netName = readString( buffer, bufferIndex, 13, false ); bufferIndex += 14; results[i].type = readInt2( buffer, bufferIndex ); bufferIndex += 2; @@ -86,9 +85,8 @@ class NetShareEnumResponse extends SmbComTransactionResponse { bufferIndex += 4; off = ( off & 0xFFFF ) - converter; off = start + off; - results[i].remark = new String( buffer, off, - readStringLength( buffer, off, 128 )); -Log.println( Log.DEBUGGING, "smb warning", results[i] ); + results[i].remark = readString( buffer, off, 128, false ); +Log.println( Log.WARNINGS, "smb warning", results[i] ); } return bufferIndex - start; diff --git a/src/jcifs/smb/NtlmAuthenticator.java b/src/jcifs/smb/NtlmAuthenticator.java new file mode 100644 index 0000000..9eb5bad --- /dev/null +++ b/src/jcifs/smb/NtlmAuthenticator.java @@ -0,0 +1,77 @@ +/* jcifs smb client library in Java + * Copyright (C) 2002 "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; + +/** +This class can be extended by applications that wish to trap authentication related exceptions and automatically retry the exceptional operation with different credentials. Read jCIFS Exceptions and NtlmAuthenticator for complete details. + */ + +public abstract class NtlmAuthenticator { + + private static NtlmAuthenticator auth; + + private String url; + private SmbAuthException sae; + + private void reset() { + url = null; + sae = null; + } + +/** +Set the default NtlmAuthenticator. Once the default authenticator is set it cannot be changed. Calling this metho again will have no effect. + */ + + public synchronized static void setDefault( NtlmAuthenticator a ) { + if( auth != null ) { + return; + } + auth = a; + } + + protected final String getRequestingURL() { + return url; + } + protected final SmbAuthException getRequestingException() { + return sae; + } + +/** +Used internally by jCIFS when an SmbAuthException is trapped to retrieve new user credentials. + */ + + public static NtlmPasswordAuthentication + requestNtlmPasswordAuthentication( String url, SmbAuthException sae ) { + if( auth == null ) { + return null; + } + synchronized( auth ) { + auth.url = url; + auth.sae = sae; + return auth.getNtlmPasswordAuthentication(); + } + } +/** +An application extending this class must provide an implementation for this method that returns new user credentials try try when accessing SMB resources described by the getRequestingURL and getRequestingException methods. +If this method returns null the SmbAuthException that triggered the authenticator check will simply be rethrown. The default implementation returns null. +*/ + protected NtlmPasswordAuthentication getNtlmPasswordAuthentication() { + return null; + } +} diff --git a/src/jcifs/smb/NtlmPasswordAuthentication.java b/src/jcifs/smb/NtlmPasswordAuthentication.java new file mode 100644 index 0000000..529fc89 --- /dev/null +++ b/src/jcifs/smb/NtlmPasswordAuthentication.java @@ -0,0 +1,271 @@ +/* jcifs smb client library in Java + * Copyright (C) 2002 "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.util.DES; +import jcifs.util.MD4; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.util.Arrays; +import jcifs.Config; + +/** + * This class stores and encrypts NTLM user credentials. The default + * credentials are retrieved from the jcifs.smb.client.domain, + * jcifs.smb.client.username, and jcifs.smb.client.password + * properties. + *

+ * Read jCIFS Exceptions and + * NtlmAuthenticator for related information. + */ + +public final class NtlmPasswordAuthentication implements Principal { + + // KGS!@#$% + static final byte[] S8 = { + (byte)0x4b, (byte)0x47, (byte)0x53, (byte)0x21, + (byte)0x40, (byte)0x23, (byte)0x24, (byte)0x25 + }; + static void E( byte[] key, byte[] data, byte[] e ) { + byte[] key7 = new byte[7]; + byte[] e8 = new byte[8]; + + for( int i = 0; i < key.length / 7; i++ ) { + System.arraycopy( key, i * 7, key7, 0, 7 ); + DES des = new DES( key7 ); + des.encrypt( data, e8 ); + System.arraycopy( e8, 0, e, i * 8, 8 ); + } + } + static byte[] getPreNTLMResponse( String password, byte[] challenge ) { + byte[] p14 = new byte[14]; + byte[] p21 = new byte[21]; + byte[] p24 = new byte[24]; + byte[] passwordBytes; + try { + passwordBytes = password.toUpperCase().getBytes( ServerMessageBlock.encoding ); + } catch( UnsupportedEncodingException uee ) { + return null; + } + int passwordLength = passwordBytes.length; + + // Only encrypt the first 14 bytes of the password for Pre 0.12 NT LM + if( passwordLength > 14) { + passwordLength = 14; + } + System.arraycopy( passwordBytes, 0, p14, 0, passwordLength ); + E( p14, S8, p21); + E( p21, challenge, p24); + return p24; + } + static byte[] getNTLMResponse( String password, byte[] challenge ) { + byte[] uni = null; + byte[] p21 = new byte[21]; + byte[] p24 = new byte[24]; + + try { + uni = password.getBytes( "UnicodeLittleUnmarked" ); + } catch( UnsupportedEncodingException uee ) { + Log.printStackTrace( "password encryption exception", uee ); + } + MD4 md4 = new MD4(); + md4.update( uni ); + System.arraycopy( md4.digest(), 0, p21, 0, 16 ); + E( p21, challenge, p24 ); + return p24; + } + + static final NtlmPasswordAuthentication NULL = + new NtlmPasswordAuthentication( "", "", "" ); + static final NtlmPasswordAuthentication GUEST = + new NtlmPasswordAuthentication( "?", "GUEST", "" ); + + String domain; + String username; + String password; + byte[] ansiHash; + byte[] unicodeHash; + boolean hashesExternal = false; + +/** + * Create an NtlmPasswordAuthentication object from the userinfo + * component of an SMB URL like "domain;user:pass". This constructor + * is used internally be jCIFS when parsing SMB URLs. + */ + + public NtlmPasswordAuthentication( String userInfo ) { + domain = username = password = null; + + if( userInfo != null ) { + int i, u, end; + char c; + + end = userInfo.length(); + for( i = 0, u = 0; i < end; i++ ) { + c = userInfo.charAt( i ); + if( c == ';' ) { + domain = userInfo.substring( 0, i ); + u = i + 1; + } else if( c == ':' ) { + password = userInfo.substring( i + 1 ); + break; + } + } + username = userInfo.substring( u, i ); + } + + if( domain == null ) { + this.domain = Config.getProperty( "jcifs.smb.client.domain", "?" ); + } + if( username == null ) { + this.username = Config.getProperty( "jcifs.smb.client.username", "GUEST" ); + } + if( password == null ) { + this.password = Config.getProperty( "jcifs.smb.client.password", "" ); + } + } +/** + * Create an NtlmPasswordAuthentication object from a + * domain, username, and password. Parameters that are null + * will be substituted with jcifs.smb.client.domain, + * jcifs.smb.client.username, jcifs.smb.client.password + * property values. + */ + public NtlmPasswordAuthentication( String domain, String username, String password ) { + this.domain = domain; + this.username = username; + this.password = password; + if( domain == null ) { + this.domain = Config.getProperty( "jcifs.smb.client.domain", "?" ); + } + if( username == null ) { + this.username = Config.getProperty( "jcifs.smb.client.username", "GUEST" ); + } + if( password == null ) { + this.password = Config.getProperty( "jcifs.smb.client.password", "" ); + } + } +/** + * Create an NtlmPasswordAuthentication object with raw password + * hashes. This is used exclusively by the jcifs.http.NtlmSsp + * class which is in turn used by NTLM HTTP authentication functionality. + */ + public NtlmPasswordAuthentication( String domain, String username, + byte[] ansiHash, byte[] unicodeHash ) { + if( domain == null || username == null || + ansiHash == null || unicodeHash == null ) { + throw new IllegalArgumentException( "External credentials cannot null" ); + } + this.domain = domain; + this.username = username; + this.password = null; + this.ansiHash = ansiHash; + this.unicodeHash = unicodeHash; + hashesExternal = true; + } + +/** + * Returns the domain. + */ + public String getDomain() { + return domain; + } +/** + * Returns the username. + */ + public String getUsername() { + return username; + } +/** + * Returns the password in plain text or null if the raw password + * hashes were used to construct this NtlmPasswordAuthentication + * object which will be the case when NTLM HTTP Authentication is + * used. There is no way to retrieve a users password in plain text unless + * it is supplied by the user at runtime. + */ + public String getPassword() { + return password; + } +/** + * Return the domain and username in the format: + * domain\\username. This is equivalent to toString(). + */ + public String getName() { + boolean d = domain.length() > 0 && domain.equals( "?" ) == false; + return d ? domain + "\\" + username : username; + } +/** + * Computes the 24 byte ANSI password hash given the 8 byte server challenge. + */ + public byte[] getAnsiHash( byte[] challenge ) { + if( hashesExternal ) { + return ansiHash; + } + return getPreNTLMResponse( password, challenge ); + } +/** + * Computes the 24 byte Unicode password hash given the 8 byte server challenge. + */ + public byte[] getUnicodeHash( byte[] challenge ) { + if( hashesExternal ) { + return unicodeHash; + } + return getNTLMResponse( password, challenge ); + } +/** + * Compares two NtlmPasswordAuthentication objects for + * equality. Two NtlmPasswordAuthentication objects are equal if + * their caseless domain and username fields are equal and either both hashes are external and they are equal or both internally supplied passwords are equal. If one NtlmPasswordAuthentication object has external hashes (meaning negotiated via NTLM HTTP Authentication) and the other does not they will not be equal. This is technically not correct however the server 8 byte challage would be required to compute and compare the password hashes but that it not available with this method. + */ + public boolean equals( Object obj ) { + if( obj instanceof NtlmPasswordAuthentication ) { + NtlmPasswordAuthentication ntlm = (NtlmPasswordAuthentication)obj; + if( ntlm.domain.toUpperCase().equals( domain.toUpperCase() ) && + ntlm.username.toUpperCase().equals( username.toUpperCase() )) { + if( hashesExternal && ntlm.hashesExternal ) { + return Arrays.equals( ansiHash, ntlm.ansiHash ) && + Arrays.equals( unicodeHash, ntlm.unicodeHash ); + /* This still isn't quite right. If one npa object does not have external + * hashes and the other does then they will not be considered equal even + * though they may be. + */ + } else if( !hashesExternal && password.equals( ntlm.password )) { + return true; + } + } + } + return false; + } + + +/** + * Return the upcased username hash code. + */ + public int hashCode() { + return getName().toUpperCase().hashCode(); + } +/** + * Return the domain and username in the format: + * domain\\username. This is equivalent to getName(). + */ + public String toString() { + return getName(); + } +} + diff --git a/src/jcifs/smb/ServerMessageBlock.java b/src/jcifs/smb/ServerMessageBlock.java index 66d1faa..7d5f6e4 100644 --- a/src/jcifs/smb/ServerMessageBlock.java +++ b/src/jcifs/smb/ServerMessageBlock.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -101,6 +101,9 @@ abstract class ServerMessageBlock { static final TimeZone TZ = TimeZone.getDefault(); static boolean useBatching = Config.getBoolean( "jcifs.smb.client.useBatching", true ); + static String encoding = Config.getProperty( "jcifs.smb.client.codepage", + Config.getProperty( "jcifs.encoding", + System.getProperty( "file.encoding" ))); static final byte[] header = { (byte)0xFF, (byte)'S', (byte)'M', (byte)'B', @@ -153,20 +156,20 @@ abstract class ServerMessageBlock { synchronized( TZ ) { if( TZ.inDaylightTime( new Date() )) { - // in dst + // in DST if( TZ.inDaylightTime( new Date( t ))) { - // t also in dst so no correction + // t also in DST so no correction return t; } - // t not in dst so add 1 hour + // t not in DST so add 1 hour return t + 3600000; } else { - // not in dst + // not in DST if( TZ.inDaylightTime( new Date( t ))) { - // t is in dst so subtract 1 hour + // t is in DST so subtract 1 hour return t - 3600000; } - // t isn't in dst either + // t isn't in DST either return t; } } @@ -174,6 +177,32 @@ abstract class ServerMessageBlock { static long readUTime( byte[] buffer, int bufferIndex ) { return readInt4( buffer, bufferIndex ) * 1000L; } + static void writeTime( long t, byte[] dst, int dstIndex ) { + if( t == 0L || t == 0xFFFFFFFFFFFFFFFFL ) { + writeInt4( 0xFFFFFFFF, dst, dstIndex ); + return; + } + synchronized( TZ ) { + if( TZ.inDaylightTime( new Date() )) { + // in DST + if( TZ.inDaylightTime( new Date( t ))) { + // t also in DST so no correction + } else { + // t not in DST so subtract 1 hour + t -= 3600000; + } + } else { + // not in DST + if( TZ.inDaylightTime( new Date( t ))) { + // t is in DST so add 1 hour + t += 3600000; + } else { + // t isn't in DST either + } + } + } + writeInt4( (int)(t / 1000L), dst, dstIndex ); + } /* @@ -195,7 +224,6 @@ abstract class ServerMessageBlock { static final byte SMB_COM_CHECK_DIRECTORY = (byte)0x10; static final byte SMB_COM_TRANSACTION = (byte)0x25; static final byte SMB_COM_TRANSACTION_SECONDARY = (byte)0x26; - static final byte SMB_COM_COPY = (byte)0x29; static final byte SMB_COM_MOVE = (byte)0x2A; static final byte SMB_COM_ECHO = (byte)0x2B; static final byte SMB_COM_OPEN_ANDX = (byte)0x2D; @@ -246,8 +274,8 @@ abstract class ServerMessageBlock { int writeString( String str, byte[] dst, int dstIndex, boolean useUnicode ) { int start = dstIndex; - if( useUnicode ) { - try { + try { + if( useUnicode ) { // Unicode requires word alignment if((( dstIndex - headerStart ) % 2 ) != 0 ) { dst[dstIndex++] = (byte)'\0'; @@ -255,47 +283,52 @@ abstract class ServerMessageBlock { System.arraycopy( str.getBytes( "UnicodeLittleUnmarked" ), 0, dst, dstIndex, str.length() * 2 ); dstIndex += str.length() * 2; - } catch( UnsupportedEncodingException uee ) { - Log.printStackTrace( "smb exception", uee ); + dst[dstIndex++] = (byte)'\0'; + dst[dstIndex++] = (byte)'\0'; + } else { + byte[] b = str.getBytes( encoding ); + System.arraycopy( b, 0, dst, dstIndex, b.length ); + dstIndex += b.length; + dst[dstIndex++] = (byte)'\0'; } - dst[dstIndex++] = (byte)'\0'; - dst[dstIndex++] = (byte)'\0'; - } else { - System.arraycopy( str.getBytes(), 0, dst, dstIndex, str.length() ); - dstIndex += str.length(); - dst[dstIndex++] = (byte)'\0'; + } catch( UnsupportedEncodingException uee ) { + Log.printStackTrace( "smb exception", uee ); } return dstIndex - start; } String readString( byte[] src, int srcIndex ) { + return readString( src, srcIndex, 256, useUnicode ); + } + String readString( byte[] src, int srcIndex, int maxLen, boolean useUnicode ) { int len = 0; String str = null; - if( useUnicode ) { - // Unicode requires word alignment - if((( srcIndex - headerStart ) % 2 ) != 0 ) { - srcIndex++; - } - while( src[srcIndex + len] != (byte)0x00 || - src[srcIndex + len + 1] != (byte)0x00 ) { - len += 2; - if( len > 256 ) { - throw new RuntimeException( "zero termination not found" ); + try { + if( useUnicode ) { + // Unicode requires word alignment + if((( srcIndex - headerStart ) % 2 ) != 0 ) { + srcIndex++; + } + while( src[srcIndex + len] != (byte)0x00 || + src[srcIndex + len + 1] != (byte)0x00 ) { + len += 2; + if( len > maxLen ) { +jcifs.util.Log.printHexDump( System.err, src, 0, 256 ); + throw new RuntimeException( "zero termination not found" ); + } } - } - try { str = new String( src, srcIndex, len, "UnicodeLittle" ); - } catch( UnsupportedEncodingException uee ) { - Log.printStackTrace( "smb exception", uee ); - } - } else { - while( src[srcIndex + len] != (byte)0x00 ) { - len++; - if( len > 256 ) { - throw new RuntimeException( "zero termination not found" ); + } else { + while( src[srcIndex + len] != (byte)0x00 ) { + len++; + if( len > maxLen ) { + throw new RuntimeException( "zero termination not found" ); + } } + str = new String( src, srcIndex, len, encoding ); } - str = new String( src, srcIndex, len ); + } catch( UnsupportedEncodingException uee ) { + Log.printStackTrace( "smb exception", uee ); } return str; } @@ -508,9 +541,6 @@ abstract class ServerMessageBlock { case SMB_COM_RENAME: c = "SMB_COM_RENAME"; break; - case SMB_COM_COPY: - c = "SMB_COM_COPY"; - break; case SMB_COM_DELETE: c = "SMB_COM_DELETE"; break; diff --git a/src/jcifs/smb/SmbAuthException.java b/src/jcifs/smb/SmbAuthException.java index 4d6e9d8..65b073d 100644 --- a/src/jcifs/smb/SmbAuthException.java +++ b/src/jcifs/smb/SmbAuthException.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,6 +18,13 @@ package jcifs.smb; +/** + * The SmbAuthException encapsulates the variety of + * authentication related error codes returned by an SMB server. + *

+ * See jCIFS Exceptions and NtlmAuthenticator for more information about SmbAuthException. + */ + public class SmbAuthException extends SmbException { public SmbAuthException( int code ) { diff --git a/src/jcifs/smb/SmbComBlankResponse.java b/src/jcifs/smb/SmbComBlankResponse.java index 9093482..96b0e36 100644 --- a/src/jcifs/smb/SmbComBlankResponse.java +++ b/src/jcifs/smb/SmbComBlankResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComCheckDirectory.jav b/src/jcifs/smb/SmbComCheckDirectory.jav index a8501b7..771d3ce 100644 --- a/src/jcifs/smb/SmbComCheckDirectory.jav +++ b/src/jcifs/smb/SmbComCheckDirectory.jav @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComClose.java b/src/jcifs/smb/SmbComClose.java index 163eb79..40642de 100644 --- a/src/jcifs/smb/SmbComClose.java +++ b/src/jcifs/smb/SmbComClose.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -22,18 +22,19 @@ import java.util.Date; class SmbComClose extends ServerMessageBlock { - int fid, lastWriteTime; + int fid; + long lastWriteTime; - SmbComClose( int fid ) { + SmbComClose( int fid, long lastWriteTime ) { this.fid = fid; + this.lastWriteTime = lastWriteTime; command = SMB_COM_CLOSE; } int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) { writeInt2( fid, dst, dstIndex ); dstIndex += 2; - lastWriteTime = 0xFFFFFFFF; - writeInt4( lastWriteTime, dst, dstIndex ); + writeTime( lastWriteTime, dst, dstIndex ); return 6; } int writeBytesWireFormat( byte[] dst, int dstIndex ) { @@ -49,6 +50,6 @@ class SmbComClose extends ServerMessageBlock { return new String( "SmbComClose[" + super.toString() + ",fid=" + fid + - ",lastWriteTime=" + ( new Date( lastWriteTime )) + "]" ); + ",lastWriteTime=" + lastWriteTime + "]" ); } } diff --git a/src/jcifs/smb/SmbComCopy.jav b/src/jcifs/smb/SmbComCopy.jav deleted file mode 100644 index 78c266a..0000000 --- a/src/jcifs/smb/SmbComCopy.jav +++ /dev/null @@ -1,68 +0,0 @@ -/* 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; - -class SmbComCopy extends ServerMessageBlock { - - String sourceFileName; - String targetFileName; - int tid2; - int openFunction; - int flags; - - SmbComCopy( String sourceFileName, String targetFileName, int tid2 ) { - this.sourceFileName = sourceFileName; - this.targetFileName = targetFileName; - this.tid2 = tid2 > 0 ? tid2 : -1; - command = SMB_COM_COPY; - openFunction = OPEN_FUNCTION_FAIL_IF_EXISTS; - flags = FLAGS_TARGET_MUST_BE_FILE; - } - - int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) { - writeInt2( tid2, dst, dstIndex ); - dstIndex += 2; - writeInt2( openFunction, dst, dstIndex ); - dstIndex += 2; - writeInt2( flags, dst, dstIndex ); - return 6; - } - int writeBytesWireFormat( byte[] dst, int dstIndex ) { - int start = dstIndex; - - dst[dstIndex++] = (byte)0x04; - dstIndex += writeString( sourceFileName, dst, dstIndex ); - dst[dstIndex++] = (byte)0x04; - dstIndex += writeString( targetFileName, dst, dstIndex ); - - return dstIndex - start; - } - int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) { - return 0; - } - int readBytesWireFormat( byte[] buffer, int bufferIndex ) { - return 0; - } - public String toString() { - return new String( "SmbComCopy[" + - super.toString() + - ",sourceFileName=" + sourceFileName + - ",targetFileName=" + targetFileName + "]" ); - } -} diff --git a/src/jcifs/smb/SmbComCopyResponse.jav b/src/jcifs/smb/SmbComCopyResponse.jav deleted file mode 100644 index 8d8595b..0000000 --- a/src/jcifs/smb/SmbComCopyResponse.jav +++ /dev/null @@ -1,52 +0,0 @@ -/* 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; - -class SmbComCopyResponse extends ServerMessageBlock { - - int count; - String errorFileName; - - SmbComCopyResponse() { - count = 0; - errorFileName = ""; - } - - int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) { - return 0; - } - int writeBytesWireFormat( byte[] dst, int dstIndex ) { - return 0; - } - int readParameterWordsWireFormat( byte[] buffer, int bufferIndex ) { - count = readInt2( buffer, bufferIndex ); - return 2; - } - int readBytesWireFormat( byte[] buffer, int bufferIndex ) { - bufferIndex++; - errorFileName = readString( buffer, bufferIndex ); - return stringWireLength( errorFileName, bufferIndex ); - } - public String toString() { - return new String( "SmbComCopyResponse[" + - super.toString() + - ",count=" + count + - ",errorFileName=" + errorFileName + "]" ); - } -} diff --git a/src/jcifs/smb/SmbComCreateDirectory.java b/src/jcifs/smb/SmbComCreateDirectory.java index b4288f2..fc51f57 100644 --- a/src/jcifs/smb/SmbComCreateDirectory.java +++ b/src/jcifs/smb/SmbComCreateDirectory.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComDelete.java b/src/jcifs/smb/SmbComDelete.java index 0066680..fecdf0e 100644 --- a/src/jcifs/smb/SmbComDelete.java +++ b/src/jcifs/smb/SmbComDelete.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComDeleteDirectory.java b/src/jcifs/smb/SmbComDeleteDirectory.java index c97eba5..6506fc0 100644 --- a/src/jcifs/smb/SmbComDeleteDirectory.java +++ b/src/jcifs/smb/SmbComDeleteDirectory.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComEcho.jav b/src/jcifs/smb/SmbComEcho.jav index 7c7246d..04dcea9 100644 --- a/src/jcifs/smb/SmbComEcho.jav +++ b/src/jcifs/smb/SmbComEcho.jav @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComEchoResponse.jav b/src/jcifs/smb/SmbComEchoResponse.jav index a4c4a10..91f59f8 100644 --- a/src/jcifs/smb/SmbComEchoResponse.jav +++ b/src/jcifs/smb/SmbComEchoResponse.jav @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComFindClose2.java b/src/jcifs/smb/SmbComFindClose2.java index 5c3ae17..42ac876 100644 --- a/src/jcifs/smb/SmbComFindClose2.java +++ b/src/jcifs/smb/SmbComFindClose2.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComLogoffAndX.java b/src/jcifs/smb/SmbComLogoffAndX.java index cc869b5..8d6404c 100644 --- a/src/jcifs/smb/SmbComLogoffAndX.java +++ b/src/jcifs/smb/SmbComLogoffAndX.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComMove.jav b/src/jcifs/smb/SmbComMove.jav index b94383f..21de75b 100644 --- a/src/jcifs/smb/SmbComMove.jav +++ b/src/jcifs/smb/SmbComMove.jav @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComMoveResponse.jav b/src/jcifs/smb/SmbComMoveResponse.jav index 7c267c9..c30b69b 100644 --- a/src/jcifs/smb/SmbComMoveResponse.jav +++ b/src/jcifs/smb/SmbComMoveResponse.jav @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComNTCreateAndX.java b/src/jcifs/smb/SmbComNTCreateAndX.java index 99d9261..bec6d11 100644 --- a/src/jcifs/smb/SmbComNTCreateAndX.java +++ b/src/jcifs/smb/SmbComNTCreateAndX.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -43,11 +43,7 @@ class SmbComNTCreateAndX extends AndXServerMessageBlock { static final int GENERIC_WRITE = 0x40000000; // 30 static final int GENERIC_READ = 0x80000000; // 31 - // share access - static final int FILE_NO_SHARE = 0x00; - static final int FILE_SHARE_READ = 0x01; - static final int FILE_SHARE_WRITE = 0x02; - static final int FILE_SHARE_DELETE = 0x04; + // share access specified in SmbFile // create disposition @@ -109,7 +105,7 @@ class SmbComNTCreateAndX extends AndXServerMessageBlock { long allocationSize; byte securityFlags; - SmbComNTCreateAndX( String name, int flags, ServerMessageBlock andx ) { + SmbComNTCreateAndX( String name, int flags, ServerMessageBlock andx, int shareAccess ) { super( andx ); this.name = name; command = SMB_COM_NT_CREATE_ANDX; @@ -122,7 +118,7 @@ class SmbComNTCreateAndX extends AndXServerMessageBlock { extFileAttributes = ATTR_NORMAL; // shareAccess - shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + this.shareAccess = shareAccess; // createDisposition if(( flags & SmbFile.O_TRUNC ) == SmbFile.O_TRUNC ) { diff --git a/src/jcifs/smb/SmbComNTCreateAndXResponse.java b/src/jcifs/smb/SmbComNTCreateAndXResponse.java index e488a04..74a24df 100644 --- a/src/jcifs/smb/SmbComNTCreateAndXResponse.java +++ b/src/jcifs/smb/SmbComNTCreateAndXResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComNegotiate.java b/src/jcifs/smb/SmbComNegotiate.java index 37d25e5..202a010 100644 --- a/src/jcifs/smb/SmbComNegotiate.java +++ b/src/jcifs/smb/SmbComNegotiate.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,10 +18,11 @@ package jcifs.smb; +import java.io.UnsupportedEncodingException; + class SmbComNegotiate extends ServerMessageBlock { - static final byte[] dialects = new String( - '\2' + "NT LM 0.12" + '\0' ).getBytes(); + static final String DIALECTS = "\u0002NT LM 0.12\u0000"; SmbComNegotiate() { command = SMB_COM_NEGOTIATE; @@ -31,6 +32,12 @@ class SmbComNegotiate extends ServerMessageBlock { return 0; } int writeBytesWireFormat( byte[] dst, int dstIndex ) { + byte[] dialects; + try { + dialects = DIALECTS.getBytes( "ASCII" ); + } catch( UnsupportedEncodingException uee ) { + return 0; + } System.arraycopy( dialects, 0, dst, dstIndex, dialects.length ); return dialects.length; } @@ -44,7 +51,6 @@ class SmbComNegotiate extends ServerMessageBlock { return new String( "SmbComNegotiate[" + super.toString() + ",wordCount=" + wordCount + - ",byteCount=" + dialects.length + ",dialects=NT LM 0.12]" ); } } diff --git a/src/jcifs/smb/SmbComNegotiateResponse.java b/src/jcifs/smb/SmbComNegotiateResponse.java index 2ce1fb9..0988df1 100644 --- a/src/jcifs/smb/SmbComNegotiateResponse.java +++ b/src/jcifs/smb/SmbComNegotiateResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -90,30 +90,37 @@ class SmbComNegotiateResponse extends ServerMessageBlock { encryptionKey, 0, encryptionKeyLength ); bufferIndex += encryptionKeyLength; - int len = 0; - if(( flags2 & FLAGS2_UNICODE ) == FLAGS2_UNICODE ) { - while( buffer[bufferIndex + len] != (byte)0x00 || - buffer[bufferIndex + len + 1] != (byte)0x00 ) { - len += 2; - if( len > 256 ) { - throw new RuntimeException( "zero termination not found" ); + if( byteCount > encryptionKeyLength ) { + int len = 0; + if(( flags2 & FLAGS2_UNICODE ) == FLAGS2_UNICODE ) { + while( buffer[bufferIndex + len] != (byte)0x00 || + buffer[bufferIndex + len + 1] != (byte)0x00 ) { + len += 2; + if( len > 256 ) { + throw new RuntimeException( "zero termination not found" ); + } } - } - try { - oemDomainName = new String( buffer, bufferIndex, len, "UnicodeLittle" ); - } catch( UnsupportedEncodingException uee ) { - Log.printStackTrace( "smb exception", uee ); - } - } else { - while( buffer[bufferIndex + len] != (byte)0x00 ) { - len++; - if( len > 256 ) { - throw new RuntimeException( "zero termination not found" ); + try { + oemDomainName = new String( buffer, bufferIndex, len, "UnicodeLittle" ); + } catch( UnsupportedEncodingException uee ) { + Log.printStackTrace( "smb exception", uee ); + } + } else { + while( buffer[bufferIndex + len] != (byte)0x00 ) { + len++; + if( len > 256 ) { + throw new RuntimeException( "zero termination not found" ); + } + } + try { + oemDomainName = new String( buffer, bufferIndex, len, ServerMessageBlock.encoding ); + } catch( UnsupportedEncodingException uee ) { } } - oemDomainName = new String( buffer, bufferIndex, len ); + bufferIndex += len; + } else { + oemDomainName = new String(); } - bufferIndex += len; return bufferIndex - start; } diff --git a/src/jcifs/smb/SmbComOpenAndX.java b/src/jcifs/smb/SmbComOpenAndX.java index afbe4da..ea2eca4 100644 --- a/src/jcifs/smb/SmbComOpenAndX.java +++ b/src/jcifs/smb/SmbComOpenAndX.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComOpenAndXResponse.java b/src/jcifs/smb/SmbComOpenAndXResponse.java index 1d7e6e5..727b6ad 100644 --- a/src/jcifs/smb/SmbComOpenAndXResponse.java +++ b/src/jcifs/smb/SmbComOpenAndXResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComQueryInformation.java b/src/jcifs/smb/SmbComQueryInformation.java index b7ac641..3a23cf4 100644 --- a/src/jcifs/smb/SmbComQueryInformation.java +++ b/src/jcifs/smb/SmbComQueryInformation.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComQueryInformationResponse.java b/src/jcifs/smb/SmbComQueryInformationResponse.java index 1feb9ef..868945e 100644 --- a/src/jcifs/smb/SmbComQueryInformationResponse.java +++ b/src/jcifs/smb/SmbComQueryInformationResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComReadAndX.java b/src/jcifs/smb/SmbComReadAndX.java index 4d184e9..b98664b 100644 --- a/src/jcifs/smb/SmbComReadAndX.java +++ b/src/jcifs/smb/SmbComReadAndX.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -26,14 +26,19 @@ class SmbComReadAndX extends AndXServerMessageBlock { static final int BATCH_LIMIT = Config.getInt( "jcifs.smb.client.ReadAndX.Close", 1 ); + long offset; int fid, - offset, maxCount, minCount, openTimeout, remaining; - SmbComReadAndX( int fid, int offset, int maxCount, ServerMessageBlock andx ) { + SmbComReadAndX() { + super( null ); + command = SMB_COM_READ_ANDX; + openTimeout = 0xFFFFFFFF; + } + SmbComReadAndX( int fid, long offset, int maxCount, ServerMessageBlock andx ) { super( andx ); this.fid = fid; this.offset = offset; @@ -42,6 +47,11 @@ class SmbComReadAndX extends AndXServerMessageBlock { openTimeout = 0xFFFFFFFF; } + void setParam( int fid, long offset, int maxCount ) { + this.fid = fid; + this.offset = offset; + this.maxCount = minCount = maxCount; + } int getBatchLimit( byte command ) { return command == SMB_COM_CLOSE ? BATCH_LIMIT : 0; } @@ -50,7 +60,7 @@ class SmbComReadAndX extends AndXServerMessageBlock { writeInt2( fid, dst, dstIndex ); dstIndex += 2; - writeInt4( offset, dst, dstIndex ); + writeInt4( offset & 0xFFFFFFFFL, dst, dstIndex ); dstIndex += 4; writeInt2( maxCount, dst, dstIndex ); dstIndex += 2; @@ -60,7 +70,7 @@ class SmbComReadAndX extends AndXServerMessageBlock { dstIndex += 4; writeInt2( remaining, dst, dstIndex ); dstIndex += 2; - writeInt4( 0, dst, dstIndex ); + writeInt4(( offset >> 32 ) & 0xFFFFFFFFL, dst, dstIndex ); dstIndex += 4; return dstIndex - start; diff --git a/src/jcifs/smb/SmbComReadAndXResponse.java b/src/jcifs/smb/SmbComReadAndXResponse.java index 560b4fb..712e0fe 100644 --- a/src/jcifs/smb/SmbComReadAndXResponse.java +++ b/src/jcifs/smb/SmbComReadAndXResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -29,11 +29,17 @@ class SmbComReadAndXResponse extends AndXServerMessageBlock { dataOffset, off; + SmbComReadAndXResponse() { + } SmbComReadAndXResponse( byte[] b, int off ) { this.b = b; this.off = off; } + void setParam( byte[] b, int off ) { + this.b = b; + this.off = off; + } int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) { return 0; } diff --git a/src/jcifs/smb/SmbComRename.java b/src/jcifs/smb/SmbComRename.java index bffbe07..7a53da2 100644 --- a/src/jcifs/smb/SmbComRename.java +++ b/src/jcifs/smb/SmbComRename.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComSessionSetupAndX.java b/src/jcifs/smb/SmbComSessionSetupAndX.java index 6d54646..8beed59 100644 --- a/src/jcifs/smb/SmbComSessionSetupAndX.java +++ b/src/jcifs/smb/SmbComSessionSetupAndX.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -53,17 +53,29 @@ class SmbComSessionSetupAndX extends AndXServerMessageBlock { int start = dstIndex; if( session.transport.server.security == SECURITY_USER && - session.password.length() != 0 ) { + ( session.auth.hashesExternal || + session.auth.password.length() > 0 )) { if( session.transport.server.encryptedPasswords ) { // encrypted - accountPassword = SmbSession.getPreNTLMResponse( session.password, - session.transport.server.encryptionKey ); - unicodePassword = SmbSession.getNTLMResponse( session.password, - session.transport.server.encryptionKey ); + accountPassword = session.auth.getAnsiHash( session.transport.server.encryptionKey ); + unicodePassword = session.auth.getUnicodeHash( session.transport.server.encryptionKey ); passwordLength = unicodePasswordLength = 24; + } else if( Config.getBoolean( "jcifs.smb.client.disablePlainTextPasswords", true )) { + throw new RuntimeException( "Plain text passwords are disabled" ); + } else if( useUnicode ) { + // plain text + String password = session.auth.getPassword(); + accountPassword = new byte[0]; + passwordLength = 0; + unicodePassword = new byte[(password.length() + 1) * 2]; + unicodePasswordLength = writeString( password, unicodePassword, 0 ); } else { // plain text - throw new RuntimeException( "plain text passwords not implemented" ); + String password = session.auth.getPassword(); + accountPassword = new byte[(password.length() + 1) * 2]; + passwordLength = writeString( password, accountPassword, 0 ); + unicodePassword = new byte[0]; + unicodePasswordLength = 0; } } else { // no password in session setup @@ -99,13 +111,14 @@ class SmbComSessionSetupAndX extends AndXServerMessageBlock { int writeBytesWireFormat( byte[] dst, int dstIndex ) { int start = dstIndex; - accountName = session.username; - primaryDomain = session.domain; + accountName = session.auth.username.toUpperCase(); + primaryDomain = session.auth.domain.toUpperCase(); nativeOs = session.transport.client.nativeOs; nativeLanMan = session.transport.client.nativeLanMan; if( session.transport.server.security == SECURITY_USER && - session.password.length() != 0 ) { + ( session.auth.hashesExternal || + session.auth.password.length() > 0 )) { System.arraycopy( accountPassword, 0, dst, dstIndex, passwordLength ); dstIndex += passwordLength; System.arraycopy( unicodePassword, 0, dst, dstIndex, unicodePasswordLength ); @@ -148,7 +161,6 @@ This still isn't quite right. ",passwordLength=" + passwordLength + ",unicodePasswordLength=" + unicodePasswordLength + ",capabilities=" + session.transport.client.capabilities + - ",accountPassword=" + accountPassword + ",accountName=" + accountName + ",primaryDomain=" + primaryDomain + ",nativeOs=" + nativeOs + diff --git a/src/jcifs/smb/SmbComSessionSetupAndXResponse.java b/src/jcifs/smb/SmbComSessionSetupAndXResponse.java index 9695e6b..b6efa9b 100644 --- a/src/jcifs/smb/SmbComSessionSetupAndXResponse.java +++ b/src/jcifs/smb/SmbComSessionSetupAndXResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -20,6 +20,7 @@ package jcifs.smb; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; class SmbComSessionSetupAndXResponse extends AndXServerMessageBlock { @@ -49,8 +50,32 @@ class SmbComSessionSetupAndXResponse extends AndXServerMessageBlock { bufferIndex += stringWireLength( nativeOs, bufferIndex ); nativeLanMan = readString( buffer, bufferIndex ); bufferIndex += stringWireLength( nativeLanMan, bufferIndex ); - primaryDomain = readString( buffer, bufferIndex ); - bufferIndex += stringWireLength( primaryDomain, bufferIndex ); + + if( useUnicode ) { + int len; + + if((( bufferIndex - headerStart ) % 2 ) != 0 ) { + bufferIndex++; + } + + len = 0; + while( buffer[bufferIndex + len] != (byte)0x00 ) { + len += 2; + if( len > 256 ) { +jcifs.util.Log.printHexDump( System.err, buffer, 0, 256 ); + throw new RuntimeException( "zero termination not found" ); + } + } + try { + primaryDomain = new String( buffer, bufferIndex, len, "UnicodeLittle" ); + } catch( UnsupportedEncodingException uee ) { + Log.printStackTrace( "smb exception", uee ); + } + bufferIndex += len; + } else { + primaryDomain = readString( buffer, bufferIndex ); + bufferIndex += stringWireLength( primaryDomain, bufferIndex ); + } return bufferIndex - start; } diff --git a/src/jcifs/smb/SmbComTransaction.java b/src/jcifs/smb/SmbComTransaction.java index 7127452..6a02f17 100644 --- a/src/jcifs/smb/SmbComTransaction.java +++ b/src/jcifs/smb/SmbComTransaction.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -31,6 +31,7 @@ abstract class SmbComTransaction extends ServerMessageBlock implements Enumerati static final int NET_SHARE_ENUM = 0x0000; static final int NET_SERVER_ENUM2 = 0x0068; + static final byte TRANS_PEEK_NAMED_PIPE = (byte)0x23; static final byte TRANS_WAIT_NAMED_PIPE = (byte)0x53; static final byte TRANS_CALL_NAMED_PIPE = (byte)0x54; static final byte TRANS_TRANSACT_NAMED_PIPE = (byte)0x26; diff --git a/src/jcifs/smb/SmbComTransactionResponse.java b/src/jcifs/smb/SmbComTransactionResponse.java index fa0a8f9..a0384ba 100644 --- a/src/jcifs/smb/SmbComTransactionResponse.java +++ b/src/jcifs/smb/SmbComTransactionResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -43,6 +43,7 @@ abstract class SmbComTransactionResponse extends ServerMessageBlock implements E int pad1; boolean hasMore = true; boolean isPrimary = true; + boolean parametersDone, dataDone; byte[] txn_buf; int bufParameterStart; @@ -119,8 +120,17 @@ abstract class SmbComTransactionResponse extends ServerMessageBlock implements E * read. If so call the read methods. */ - if(( parameterDisplacement + parameterCount ) == totalParameterCount && - ( dataDisplacement + dataCount ) == totalDataCount ) { + if( !parametersDone && + ( parameterDisplacement + parameterCount ) == totalParameterCount) { + parametersDone = true; + } + + if( !dataDone && + ( dataDisplacement + dataCount ) == totalDataCount) { + dataDone = true; + } + + if( parametersDone && dataDone ) { hasMore = false; readParametersWireFormat( txn_buf, bufParameterStart, totalParameterCount ); readDataWireFormat( txn_buf, bufDataStart, totalDataCount ); diff --git a/src/jcifs/smb/SmbComTreeConnectAndX.java b/src/jcifs/smb/SmbComTreeConnectAndX.java index 792c9fc..0437116 100644 --- a/src/jcifs/smb/SmbComTreeConnectAndX.java +++ b/src/jcifs/smb/SmbComTreeConnectAndX.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -22,6 +22,7 @@ import jcifs.Config; import jcifs.util.PropertiesTree; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; class SmbComTreeConnectAndX extends AndXServerMessageBlock { @@ -34,7 +35,6 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock { /* batchLimits indecies * * 0 = SMB_COM_CHECK_DIRECTORY - * 1 = SMB_COM_COPY * 2 = SMB_COM_CREATE_DIRECTORY * 3 = SMB_COM_DELETE * 4 = SMB_COM_DELETE_DIRECTORY @@ -59,9 +59,6 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock { if(( s = pt.getProperty( "CheckDirectory" )) != null ) { batchLimits[0] = Byte.parseByte( s ); } - if(( s = pt.getProperty( "Copy" )) != null ) { - batchLimits[1] = Byte.parseByte( s ); - } if(( s = pt.getProperty( "CreateDirectory" )) != null ) { batchLimits[2] = Byte.parseByte( s ); } @@ -101,8 +98,6 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock { switch( c ) { case SMB_COM_CHECK_DIRECTORY: return batchLimits[0]; - case SMB_COM_COPY: - return batchLimits[1]; case SMB_COM_CREATE_DIRECTORY: return batchLimits[2]; case SMB_COM_DELETE: @@ -124,23 +119,27 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock { int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) { if( session.transport.server.security == SECURITY_SHARE && - session.password.length() != 0 ) { + ( session.auth.hashesExternal || + session.auth.password.length() > 0 )) { + if( session.transport.server.encryptedPasswords ) { // encrypted - password = SmbSession.getPreNTLMResponse( session.password, - session.transport.server.encryptionKey ); + password = session.auth.getAnsiHash( session.transport.server.encryptionKey ); passwordLength = 24; + } else if( Config.getBoolean( "jcifs.smb.client.disablePlainTextPasswords", true )) { + throw new RuntimeException( "Plain text passwords are disabled" ); } else { // plain text - throw new RuntimeException( "plain text passwords not implemented" ); + password = new byte[(session.auth.password.length() + 1) * 2]; + passwordLength = writeString( session.auth.password, password, 0 ); } } else { // no password in tree connect passwordLength = 1; } - dst[dstIndex++] = (byte)0x00; dst[dstIndex++] = disconnectTid ? (byte)0x01 : (byte)0x00; + dst[dstIndex++] = (byte)0x00; writeInt2( passwordLength, dst, dstIndex ); return 4; } @@ -148,21 +147,20 @@ class SmbComTreeConnectAndX extends AndXServerMessageBlock { int start = dstIndex; if( session.transport.server.security == SECURITY_SHARE && - session.password.length() != 0 ) { - if( session.transport.server.encryptedPasswords ) { - // encrypted - System.arraycopy( password, 0, dst, dstIndex, passwordLength ); - dstIndex += passwordLength; - } else { - // plain text - throw new RuntimeException( "plain text passwords not implemented" ); - } + ( session.auth.hashesExternal || + session.auth.password.length() > 0 )) { + System.arraycopy( password, 0, dst, dstIndex, passwordLength ); + dstIndex += passwordLength; } else { // no password in tree connect dst[dstIndex++] = (byte)0x00; } dstIndex += writeString( path, dst, dstIndex ); - System.arraycopy( service.getBytes(), 0, dst, dstIndex, service.length() ); + try { + System.arraycopy( service.getBytes( "ASCII" ), 0, dst, dstIndex, service.length() ); + } catch( UnsupportedEncodingException uee ) { + return 0; + } dstIndex += service.length(); dst[dstIndex++] = (byte)'\0'; diff --git a/src/jcifs/smb/SmbComTreeConnectAndXResponse.java b/src/jcifs/smb/SmbComTreeConnectAndXResponse.java index fd53dd6..e583438 100644 --- a/src/jcifs/smb/SmbComTreeConnectAndXResponse.java +++ b/src/jcifs/smb/SmbComTreeConnectAndXResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -20,6 +20,7 @@ package jcifs.smb; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; class SmbComTreeConnectAndXResponse extends AndXServerMessageBlock { @@ -50,7 +51,11 @@ class SmbComTreeConnectAndXResponse extends AndXServerMessageBlock { int start = bufferIndex; int len = readStringLength( buffer, bufferIndex, 32 ); - service = new String( buffer, bufferIndex, len ); + try { + service = new String( buffer, bufferIndex, len, "ASCII" ); + } catch( UnsupportedEncodingException uee ) { + return 0; + } bufferIndex += len + 1; // win98 observed not returning nativeFileSystem if( byteCount > bufferIndex - start ) { diff --git a/src/jcifs/smb/SmbComTreeDisconnect.java b/src/jcifs/smb/SmbComTreeDisconnect.java index ca8d101..b1f8b0e 100644 --- a/src/jcifs/smb/SmbComTreeDisconnect.java +++ b/src/jcifs/smb/SmbComTreeDisconnect.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbComWriteAndX.java b/src/jcifs/smb/SmbComWriteAndX.java index c77f3e0..8f751b2 100644 --- a/src/jcifs/smb/SmbComWriteAndX.java +++ b/src/jcifs/smb/SmbComWriteAndX.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -30,16 +30,19 @@ class SmbComWriteAndX extends AndXServerMessageBlock { Config.getInt( "jcifs.smb.client.WriteAndX.Close", 1 ); int fid, - offset, writeMode, remaining, dataLength, dataOffset, - off, - pad; + off; byte[] b; + long offset; - SmbComWriteAndX( int fid, int offset, int remaining, + SmbComWriteAndX() { + super( null ); + command = SMB_COM_WRITE_ANDX; + } + SmbComWriteAndX( int fid, long offset, int remaining, byte[] b, int off, int len, ServerMessageBlock andx ) { super( andx ); this.fid = fid; @@ -51,6 +54,15 @@ class SmbComWriteAndX extends AndXServerMessageBlock { command = SMB_COM_WRITE_ANDX; } + void setParam( int fid, long offset, int remaining, + byte[] b, int off, int len ) { + this.fid = fid; + this.offset = offset; + this.remaining = remaining; + this.b = b; + this.off = off; + dataLength = len; + } int getBatchLimit( byte command ) { if( command == SMB_COM_READ_ANDX ) { return READ_ANDX_BATCH_LIMIT; @@ -63,14 +75,16 @@ class SmbComWriteAndX extends AndXServerMessageBlock { int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) { int start = dstIndex; - dataOffset = dstIndex + 22; // 22 = off from here to pad - pad = ( dataOffset - headerStart ) % 4; - pad = pad == 0 ? 0 : 4 - pad; - dataOffset += pad; + dataOffset = dstIndex + 26; // 26 = off from here to pad +/* + * pad = ( dataOffset - headerStart ) % 4; + * pad = pad == 0 ? 0 : 4 - pad; + * dataOffset += pad; + */ writeInt2( fid, dst, dstIndex ); dstIndex += 2; - writeInt4( offset, dst, dstIndex ); + writeInt4( offset & 0xFFFFFFFFL, dst, dstIndex ); dstIndex += 4; for( int i = 0; i < 4; i++ ) { dst[dstIndex++] = (byte)0x00; @@ -85,16 +99,19 @@ class SmbComWriteAndX extends AndXServerMessageBlock { dstIndex += 2; writeInt2( dataOffset, dst, dstIndex ); dstIndex += 2; - // offsetHigh another day + writeInt4(( offset >> 32 ) & 0xFFFFFFFFL, dst, dstIndex ); + dstIndex += 4; return dstIndex - start; } int writeBytesWireFormat( byte[] dst, int dstIndex ) { int start = dstIndex; - while( pad-- > 0 ) { - dst[dstIndex++] = (byte)0x00; - } +/* Netware doesn't like this + * while( pad-- > 0 ) { + * dst[dstIndex++] = (byte)0x00; + * } + */ System.arraycopy( b, off, dst, dstIndex, dataLength ); dstIndex += dataLength; diff --git a/src/jcifs/smb/SmbComWriteAndXResponse.java b/src/jcifs/smb/SmbComWriteAndXResponse.java index 8d802b0..d728bb6 100644 --- a/src/jcifs/smb/SmbComWriteAndXResponse.java +++ b/src/jcifs/smb/SmbComWriteAndXResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/SmbException.java b/src/jcifs/smb/SmbException.java index 54b6c6c..39c9ebb 100644 --- a/src/jcifs/smb/SmbException.java +++ b/src/jcifs/smb/SmbException.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -22,8 +22,9 @@ import java.io.IOException; import jcifs.UniAddress; /** - * Don't get to attached to these constants, we'll be switching to NT - * status codes sooner or later. + * There are hundreds of error codes that may be returned by a CIFS server. Rather than represent each with it's own Exception class, this class represents all of them. For many of the popular error codes, constants and text messages like "The device is not ready" are provided. +

+ * See jCIFS Exceptions and NtlmAuthenticator for more information about SmbException. */ public class SmbException extends IOException { @@ -71,9 +72,10 @@ public class SmbException extends IOException { * The network name cannot be found */ public static final int ERRbadnetname = 67; + public static final int ERRnomoreconn = 71; public static final int ERRbadparm = 87; /** - * Cannot create a file when that file alread exists + * Cannot create a file when that file already exists */ public static final int ERRfilexists = 80; /** @@ -85,6 +87,10 @@ public class SmbException extends IOException { */ public static final int ERRinvname = 123; /** + * The directory is not empty + */ + public static final int ERRnotempty = 145; +/** * File exists */ public static final int ERRexists = 183; @@ -96,6 +102,10 @@ public class SmbException extends IOException { * The pipe is being closed */ public static final int ERRnodata = 232; +/** + * No process is on the other end of the pipe + */ + public static final int ERRnoproc = 233; // srv error codes /** @@ -130,6 +140,11 @@ public class SmbException extends IOException { */ public static final int ERRpasswordExpired = 2242; +/** + * The list of servers for this workgroup is not currently available + */ + public static final int ERRnolisting = 6118; + // hrd error codes /** * Attempt to write on write-protected media @@ -150,6 +165,11 @@ public class SmbException extends IOException { public static final int ERRserverTimeout = 5000; public static final int ERRbadDialect = 5001; public static final int ERRioe = 5002; + public static final int ERRlistFiles = 5003; + public static final int ERRunknownHost = 5004; + public static final int ERRinappro = 5005; + public static final int ERRunknownType = 5006; + public static final int ERRimpossible = 5007; int errorClass; int errorCode; @@ -180,8 +200,11 @@ public class SmbException extends IOException { case ERRinvname: result += "Invalid name"; break; + case ERRnotempty: + result += "The directory is not empty"; + break; case ERRfilexists: - result += "File exists"; + result += "Cannot create a file when that file already exists"; break; case ERRbadfid: result += "Invalid file handle"; @@ -202,7 +225,7 @@ public class SmbException extends IOException { result += "The network name cannot be found"; break; case ERRexists: - result += "Cannot create a file when that file alread exists"; + result += "File exists"; break; case ERRpipebusy: result += "All pipe instances are busy"; @@ -210,11 +233,17 @@ public class SmbException extends IOException { case ERRnodata: result += "The pipe is being closed"; break; + case ERRnoproc: + result += "No process is on the other end of the pipe"; + break; case ERRbrokenpipe: result += "The pipe has been ended"; break; + case ERRnomoreconn: + result += "No more connections can be made to this remote computer at this time because there are already as many connections as the computer can accept"; + break; default: - result += "No description available. Please update error string for errorCode=" + errorCode; + result += "No description available [ERRDOS/" + errorCode + "]"; } break; case ERRSRV: @@ -250,7 +279,7 @@ public class SmbException extends IOException { result += "The password of the user has expired"; break; default: - result += "No description available [errorCode=" + errorCode + "]"; + result += "No description available [ERRSRV/" + errorCode + "]"; } break; case ERRHRD: @@ -262,7 +291,7 @@ public class SmbException extends IOException { result += "The device is not ready"; break; default: - result += "No description available [errorCode=" + errorCode + "]"; + result += "No description available [ERRHRD/" + errorCode + "]"; } break; case ERRCMD: @@ -282,8 +311,11 @@ public class SmbException extends IOException { case NERR_BasicTransactConfig: result += "The server is not configured for transactions"; break; + case ERRnolisting: + result += "The list of servers for this workgroup is not currently available"; + break; default: - result += "No description available [errorCode=" + errorCode + "]"; + result += "No description available [ERRRAP/" + errorCode + "]"; } break; case ERRCLI: @@ -297,8 +329,20 @@ public class SmbException extends IOException { case ERRioe: result += "An IO error occured."; break; + case ERRlistFiles: + result += "The derived URL was malformed or a name service error occured during a listFiles() operation (this should not be possible, please report it to jcifs at samba dot org)"; + break; + case ERRunknownHost: + result += "The hostname retrived from the Browser service is no longer valid"; + break; + case ERRinappro: + result += "Inappropriate operation"; + break; + case ERRunknownType: + result += "Unknown resource type"; + break; default: - result += "No description available [errorCode=" + errorCode + "]"; + result += "No description available [ERRCLI/" + errorCode + "]"; } break; default: @@ -341,9 +385,16 @@ public class SmbException extends IOException { errorCode = ( code >> 16 ) & 0xFFFF; } + /** + * Retrieve the error class associated with this error. + */ public int getErrorClass() { return errorClass; } + + /** + * Retrieve the error code associated with this error. + */ public int getErrorCode() { return errorCode; } diff --git a/src/jcifs/smb/SmbFile.java b/src/jcifs/smb/SmbFile.java index b607bd9..c53f127 100644 --- a/src/jcifs/smb/SmbFile.java +++ b/src/jcifs/smb/SmbFile.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,19 +18,21 @@ package jcifs.smb; -import jcifs.UniAddress; -import jcifs.util.Config; -import jcifs.netbios.NbtAddress; -import jcifs.util.AuthHandler; -import jcifs.util.AuthInfo; +import java.net.URLConnection; +import java.net.URL; import java.net.MalformedURLException; import java.net.UnknownHostException; -import java.net.URL; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import jcifs.util.Config; +import jcifs.UniAddress; +import jcifs.netbios.NbtAddress; + +import java.util.Date; /** + *

* This class represents a resource on an SMB network. Mainly these * resources are files and directories however an SmbFile * may also refer to servers and workgroups. If the resource is a file or @@ -40,7 +42,7 @@ import java.io.OutputStream; * directory. SmbFile URLs have the following syntax: * *

- *     smb://[[[domain;]username[:password]@]server[:port][/share[/path]]]
+ *     smb://[[[domain;]username[:password]@]server[:port]/[[share/[dir/]file]]]
  * 
* * This example: @@ -52,7 +54,22 @@ import java.io.OutputStream; * would referece the file foo.txt in the share * public on the server storage15. In addition * to referencing files and directories, jCIFS can also address servers, - * and workgroups. When used in conjunction with the list + * and workgroups. +

+ * Please note that beginning with jcifs-0.7.0b4 all SMB URLs that represent workgroups, servers, shares, or directories require a trailing slash '/'. This will break older code and you may or may not get an exception. For example: +

+smb://server/share/path/to/dir/  <-- GOOD
+
+smb://server/share/path/to/dir   <-- BAD
+
+To assist you with this, the getName method will now include a slash '/' after the name if the URL refers to a directory (e.g. 'dir/'). + +

+When using the java.net.URL class with 'smb://' URLs it is necessary to first call the static jcifs.Config.registerSmbURLHandler(); method (prior to jcifs-0.7.0b12 it was Class.forName( "jcifs.Config" ); but this is no longer necessary). +

+The userinfo component of the SMB URL (domain;user:pass) must be URL encoded if it contains reserved characters. According to RFC 2396 these characters are non US-ASCII characters and most meta characters however jCIFS will work correctly with anything but '@' which is used to delimit the userinfo component from the server and '%' which is the URL escape character itself. +

+When used in conjunction with the list * method, this functionality can be usefull for network diagnostics * tools or "Network Neighborhood" like functionality. The server * component may a traditional NetBIOS name, a DNS name, or IP @@ -65,8 +82,8 @@ import java.io.OutputStream; * JCIFS Properties). Here are some examples of SMB URLs with brief * descriptions of what they do: * - *

* This URL scheme conforms to the SMB + *

* This URL scheme is based largely on the SMB * Filesharing URL Scheme IETF draft. * *

@@ -74,26 +91,26 @@ import java.io.OutputStream; * * * - * * * * - * * - * * * * - * * - * - * + * + * + * *
SMB URL Examples
URLDescription
smb://users-nyc;miallen:mypass@angus/tmp + *
smb://users-nyc;miallen:mypass@angus/tmp/ * This URL references a share called tmp on the server * angus as user miallen who's password is * mypass. *
- * smb://Administrator:P@ss@msmith1/c/WINDOWS/Desktop/foo.txt + * smb://Administrator:P%40ss@msmith1/c/WINDOWS/Desktop/foo.txt * A relativly sophisticated example that references a file - * msmith1's desktop as user Administrator. + * msmith1's desktop as user Administrator. Notice the '@' is URL encoded with the '%40' hexcode escape. *
smb://angus + *
smb://angus/ * This references only a server. The behavior of some methods is different * in this context(e.g. you cannot delete a server) however * as you might expect the list method will list the available * shares on this server. *
smb://myworkgroup + *
smb://myworkgroup/ * This syntactically is identical to the above example. However if * myworkgroup happends to be a workgroup(which is indeed * suggested by the name) the list method will return @@ -102,8 +119,8 @@ import java.io.OutputStream; *
smb:// - * Just as smb://server lists shares and - * smb://workgroup lists servers, the smb:// + * Just as smb://server/ lists shares and + * smb://workgroup/ lists servers, the smb:// * URL lists all available workgroups on a netbios LAN. Again, * in this context many methods are not valid and return default * values(e.g. isHidden and renameTo will always @@ -116,7 +133,7 @@ import java.io.OutputStream; * for details. *
smb://192.168.1.15/ADMIN$ + *
smb://192.168.1.15/ADMIN$/ * The server name may also be an IP address. See Setting Name Resolution Properties * for details. @@ -127,11 +144,16 @@ import java.io.OutputStream; * A prototypical example that uses all the fields. *
smb://myworkgroup/angus <-- ILLEGAL + *
smb://myworkgroup/angus/ <-- ILLEGAL * Despite the hierarchial relationship between workgroups, servers, and * filesystems this example is not valid. *
+ * smb://server/share/path/to/dir <-- ILLEGAL + * URLs that represent workgroups, servers, shares, or directories require a trailing slash '/'. + *
* *

A second constructor argument may be specified to augment the URL @@ -150,15 +172,15 @@ import java.io.OutputStream; * First ParameterSecond ParameterResult * * - * smb://host/share/a/b + * smb://host/share/a/b/ * - * c/d + * c/d/ * - * smb://host/share/a/b/c/d + * smb://host/share/a/b/c/d/ * * * - * smb://host/share/foo/bar + * smb://host/share/foo/bar/ * * /share2/zig/zag * @@ -166,35 +188,27 @@ import java.io.OutputStream; * * * - * smb://host/share/foo/bar + * smb://host/share/foo/bar/ * - * ../zip + * ../zip/ * - * smb://host/share/foo/zip + * smb://host/share/foo/zip/ * * * * smb://host/share/zig/zag * - * smb://foo/bar + * smb://foo/bar/ * - * smb://foo/bar + * smb://foo/bar/ * * * - * smb://host/share/foo + * smb://host/share/foo/ * - * ../.././.././../foo + * ../.././.././../foo/ * - * smb://foo - * - * - * - * smb://host/share/zig/zag - * - * null - * - * smb://host/share/zig/zag + * smb://host/foo/ * * * @@ -202,54 +216,43 @@ import java.io.OutputStream; * * / * - * smb://host + * smb://host/ * * * - * smb://server + * smb://server/ * - * .. + * ../ * - * smb:// + * smb://server/ * * * * smb:// * - * myworkgroup + * myworkgroup/ * - * smb://myworkgroup + * smb://myworkgroup/ * * * - * smb://myworkgroup + * smb://myworkgroup/ * - * angus + * angus/ * - * smb://angus + * smb://myworkgroup/angus/ <-- ILLEGAL
(But if you first create an SmbFile with 'smb://workgroup/' and use and use it as the first parameter to a constructor that accepts it with a second String parameter jCIFS will factor out the 'workgroup'.) *
* * * - *

Notice there are two exceptional examples where the workgroup - * resource smb://myworkgroup and server angus - * are combined to produce just smb://angus and not - * smb://myworkgroup/angus. Similarly, when combining - * smb://angus with .., - * angus' workgroup resource smb://myworkgroup is not - * returned. This is by design and in accordance with the SMB - * Filesharing URL Scheme IETF draft. - * *

Instances of the SmbFile class are immutable; that is, * once created, the abstract pathname represented by an SmbFile object * will never change. * * @see java.io.File - * @since jcifs-0.4 */ -public class SmbFile { +public class SmbFile extends URLConnection { // these are shifted for use in flags static final int O_RDONLY = 0x010000; @@ -257,6 +260,12 @@ public class SmbFile { static final int O_RDWR = 0x030000; static final int O_APPEND = 0x040000; + // share access + public static final int FILE_NO_SHARE = 0x00; + public static final int FILE_SHARE_READ = 0x01; + public static final int FILE_SHARE_WRITE = 0x02; + public static final int FILE_SHARE_DELETE = 0x04; + // Open Function Encoding // create if the file does not exist static final int O_CREAT = 0x0010; @@ -273,35 +282,73 @@ public class SmbFile { static final int ATTR_DIRECTORY = 0x10; static final int ATTR_ARCHIVE = 0x20; - static final long ATTR_EXPIRATION_PERIOD = Config.getLong( "jcifs.smb.client.attrExpirationPeriod", 100 ); + static final int DEFAULT_ATTR_EXPIRATION_PERIOD = 5000; + + static long attrExpirationPeriod; static { - // is this needed ?? try { Class.forName( "jcifs.Config" ); } catch( ClassNotFoundException cnfe ) { cnfe.printStackTrace(); } + attrExpirationPeriod = Config.getLong( "jcifs.smb.client.attrExpirationPeriod", DEFAULT_ATTR_EXPIRATION_PERIOD ); } - static AuthHandler authHandler = null; - - public static void setAuthHandler( AuthHandler authHandler ) { - SmbFile.authHandler = authHandler; - } - - AuthInfo authInfo = new AuthInfo(); - String url, server, share, canonicalPath, uncPath, name; - int port; - boolean isWorkgroup, isExists; + /** + * Returned by {@link #getType()} if the resource this SmbFile + * represents is a regular file or directory. + */ + public static final int TYPE_FILESYSTEM = 0x01; + /** + * Returned by {@link #getType()} if the resource this SmbFile + * represents is a workgroup. + */ + public static final int TYPE_WORKGROUP = 0x02; + /** + * Returned by {@link #getType()} if the resource this SmbFile + * represents is a server. + */ + public static final int TYPE_SERVER = 0x04; + /** + * Returned by {@link #getType()} if the resource this SmbFile + * represents is a share. + */ + public static final int TYPE_SHARE = 0x08; + /** + * Returned by {@link #getType()} if the resource this SmbFile + * represents is a named pipe. + */ + public static final int TYPE_NAMED_PIPE = 0x10; + /** + * Returned by {@link #getType()} if the resource this SmbFile + * represents is a printer. + */ + public static final int TYPE_PRINTER = 0x20; + /** + * Returned by {@link #getType()} if the resource this SmbFile + * represents is a communications device. + */ + public static final int TYPE_COMM = 0x40; + + + SmbTree tree = null; // Initially null; may be !tree.treeConnected + String canon; // Initially null; set by getUncPath; dir must end with '/' + String unc; // Initially null; set by getUncPath; never ends with '/' + String share; // Can be null + int fid; // Initially 0; set by open() + int type; + long lastModified; + int attributes; + long attrExpiration; + long size; + long sizeExpiration; + NtlmPasswordAuthentication auth; // Cannot be null + boolean opened; + boolean isExists; + int shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + SmbComBlankResponse blank_resp = new SmbComBlankResponse(); - SmbTree tree; - int fid, hash; - int attributes = ATTR_READONLY | ATTR_DIRECTORY; - long lastModified, size; - boolean opened, isPipe; - UniAddress address; - long attrExpiration = 0; /** * Constructs an SmbFile representing a resource on an SMB network such as @@ -311,14 +358,10 @@ public class SmbFile { * @throws MalformedURLException * If the parent and child parameters * do not follow the prescribed syntax - * @throws UnknownHostException - * If the name of a server specified cannot be resolved using - * the configured name resolution methods */ - public SmbFile( String url ) - throws MalformedURLException, UnknownHostException { - this( url, null, 4, url.length() ); + public SmbFile( String url ) throws MalformedURLException { + this( new URL( null, url, Handler.SMB_HANDLER )); } /** @@ -333,13 +376,13 @@ public class SmbFile { * If the parent and child parameters * do not follow the prescribed syntax * @throws UnknownHostException - * If the name of a server specified cannot be resolved using - * the configured name resolution methods + * If the server or workgroup of the context file cannot be determined */ - public SmbFile( SmbFile parent, String child ) - throws MalformedURLException, UnknownHostException { - this( parent.getCanonicalPath(), child ); + public SmbFile( SmbFile context, String name ) throws MalformedURLException, UnknownHostException { + this( context.isWorkgroup0() ? + new URL( null, "smb://" + name, Handler.SMB_HANDLER ) : + new URL( context.url, name, Handler.SMB_HANDLER ), context.auth ); } /** @@ -353,151 +396,200 @@ public class SmbFile { * @throws MalformedURLException * If the parent and child parameters * do not follow the prescribed syntax - * @throws UnknownHostException - * If the name of a server specified cannot be resolved using - * the configured name resolution methods */ - public SmbFile( String parent, String child ) - throws MalformedURLException, UnknownHostException { - this( parent, child, 4, parent.length() ); + public SmbFile( String context, String name ) throws MalformedURLException { + this( new URL( new URL( null, context, Handler.SMB_HANDLER ), name, Handler.SMB_HANDLER )); } - SmbFile( String parent, String child, int start, int limit ) - throws MalformedURLException, UnknownHostException { - - SmbURL.parseSmbURL( this, parent, child, start, limit ); - if( server == null ) { - address = UniAddress.getByName( NbtAddress.getByName( - NbtAddress.MASTER_BROWSER_NAME, - 0x01, null).getHostAddress() ); - } else if( isWorkgroup ) { - address = UniAddress.getByName( address.getHostAddress() ); - } else { - address = UniAddress.getByName( server ); + public SmbFile( String url, NtlmPasswordAuthentication auth ) + throws MalformedURLException { + this( new URL( null, url, Handler.SMB_HANDLER ), auth ); + } + public SmbFile( String context, String name, NtlmPasswordAuthentication auth ) + throws MalformedURLException { + this( new URL( new URL( null, context, Handler.SMB_HANDLER ), name, Handler.SMB_HANDLER ), auth ); + } + public SmbFile( String context, String name, NtlmPasswordAuthentication auth, int shareAccess ) + throws MalformedURLException { + this( new URL( new URL( null, context, Handler.SMB_HANDLER ), name, Handler.SMB_HANDLER ), auth ); + if ((shareAccess & ~(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)) != 0) { + throw new RuntimeException( "Illegal shareAccess parameter" ); } + this.shareAccess = shareAccess; + } + public SmbFile( URL url ) { + this( url, new NtlmPasswordAuthentication( url.getUserInfo() )); + } + public SmbFile( URL url, NtlmPasswordAuthentication auth ) { + super( url ); + this.auth = auth == null ? new NtlmPasswordAuthentication( url.getUserInfo() ) : auth; - if( canonicalPath == null ) { - uncPath = "\\"; + getUncPath0(); + } + SmbFile( SmbFile context, String name, int type, + int attributes, long lastModified, long size ) + throws MalformedURLException, UnknownHostException { + this( context, name + (( attributes & ATTR_DIRECTORY ) > 0 ? "/" : "" )); + if( context.share != null ) { + this.tree = context.tree; + } + int last = name.length() - 1; + if( name.charAt( last ) == '/' ) { + name = name.substring( 0, last ); + } + if( context.share == null ) { + this.unc = "\\"; + } else if( context.unc.equals( "\\" )) { + this.unc = '\\' + name; } else { - uncPath = canonicalPath.replace( '/', '\\' ); + this.unc = context.unc + '\\' + name; } + this.type = type; + this.attributes = attributes; + this.lastModified = lastModified; + this.size = size; + isExists = true; + + attrExpiration = sizeExpiration = + System.currentTimeMillis() + attrExpirationPeriod; } void sendTransaction( SmbComTransaction request, SmbComTransactionResponse response ) throws SmbException { - while( true ) { - if( tree == null ) { - SmbTransport trans = SmbTransport.getSmbTransport( address, port ); - SmbSession ssn = isWorkgroup ? trans.getSmbSession( "", "", "" ) : - trans.getSmbSession( authInfo.username, - authInfo.password, authInfo.domain ); - tree = share == null ? ssn.getSmbTree( "IPC$", null ) : - ssn.getSmbTree( share, null ); - } - try { - tree.sendTransaction( request, response ); - break; - } catch( SmbAuthException sae ) { - if( authHandler == null ) { - throw sae; - } - tree = null; - authInfo.exception = sae; - authInfo.target = url; - if( authHandler.authenticate( authInfo ) == false ) { - throw sae; - } - } - } + connect0(); + tree.sendTransaction( request, response ); } void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException { - while( true ) { - if( tree == null ) { - SmbTransport trans = SmbTransport.getSmbTransport( address, port ); - SmbSession ssn = isWorkgroup ? trans.getSmbSession( "", "", "" ) : - trans.getSmbSession( authInfo.username, - authInfo.password, authInfo.domain ); - tree = share == null ? ssn.getSmbTree( "IPC$", null ) : - ssn.getSmbTree( share, null ); - } - try { - tree.send( request, response ); - break; - } catch( SmbAuthException sae ) { - if( authHandler == null ) { - throw sae; - } - tree = null; - authInfo.exception = sae; - authInfo.target = url; - if( authHandler.authenticate( authInfo ) == false ) { - throw sae; - } - } - } + connect0(); + tree.send( request, response ); } - boolean isOpen() { - return opened && tree.treeConnected; + UniAddress getAddress() throws UnknownHostException { + String host = url.getHost(); + String path = url.getPath(); + + if( host.length() == 0 ) { + return UniAddress.getByName( NbtAddress.getByName( + NbtAddress.MASTER_BROWSER_NAME, 0x01, null).getHostAddress() ); + } else if( path.length() == 0 || path.equals( "/" )) { + return UniAddress.getByName( host, true ); + } else { + return UniAddress.getByName( host ); + } } - void open( int flags ) throws SmbException { + void connect0() throws SmbException { + try { + connect(); + } catch( UnknownHostException uhe ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRunknownHost, + "Unknown host: " + uhe.getMessage() ); + } catch( SmbException se ) { + throw se; + } catch( IOException ioe ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRioe, + ioe.getMessage() ); + } + } + public void connect() throws IOException { SmbTransport trans; + SmbSession ssn; + UniAddress addr; + + if( isConnected() ) { + return; + } + + getUncPath0(); + addr = getAddress(); + + trans = SmbTransport.getSmbTransport( addr, url.getPort() ); + ssn = trans.getSmbSession( auth ); + tree = ssn.getSmbTree( share, null ); + try { + tree.treeConnect( null, null ); + } catch( SmbAuthException sae ) { + NtlmPasswordAuthentication a; + + if( share == null ) { // IPC$ - try "anonymous" credentials + trans = SmbTransport.getSmbTransport( addr, url.getPort() ); + ssn = trans.getSmbSession( NtlmPasswordAuthentication.NULL ); + tree = ssn.getSmbTree( null, null ); + tree.treeConnect( null, null ); + } else if(( a = NtlmAuthenticator.requestNtlmPasswordAuthentication( url.toString(), sae )) != null ) { + auth = a; + trans = SmbTransport.getSmbTransport( addr, url.getPort() ); + ssn = trans.getSmbSession( auth ); + tree = ssn.getSmbTree( share, null ); + tree.treeConnect( null, null ); + } else { + throw sae; + } + } + } + boolean isConnected() { + return (connected = tree != null && tree.treeConnected); + } + void open( int flags ) throws SmbException { if( isOpen() ) { return; } + connect0(); - Log.println( Log.WARNINGS, "smb open warning", " name=" + canonicalPath ); + Log.println( Log.WARNINGS, "smb open warning: ", unc ); /* * Open AndX Request / Response */ - /* To query server capabilities we must ensure the negotiation has talken place - */ - - trans = SmbTransport.getSmbTransport( address, port ); - trans.negotiate(); - - if(( trans.negotiatedCapabilities & - ServerMessageBlock.CAP_NT_SMBS ) == - ServerMessageBlock.CAP_NT_SMBS ) { + if( tree.session.transport.hasCapability( ServerMessageBlock.CAP_NT_SMBS )) { SmbComNTCreateAndXResponse response = new SmbComNTCreateAndXResponse(); - send( new SmbComNTCreateAndX( uncPath, flags, null ), response ); + send( new SmbComNTCreateAndX( unc, flags, null, shareAccess ), response ); fid = response.fid; } else { SmbComOpenAndXResponse response = new SmbComOpenAndXResponse(); - send( new SmbComOpenAndX( uncPath, flags, null ), response ); + send( new SmbComOpenAndX( unc, flags, null ), response ); fid = response.fid; } opened = true; } + boolean isOpen() { + return opened && isConnected(); + } void close() throws SmbException { + close( 0L ); + } + void close( long lastWriteTime ) throws SmbException { if( isOpen() == false ) { return; } + opened = false; - Log.println( Log.WARNINGS, "smb close warning", - " fid=" + fid ); + Log.println( Log.WARNINGS, "smb close warning", " fid=" + fid ); /* * Close Request / Response */ - send( new SmbComClose( fid ), new SmbComBlankResponse() ); + send( new SmbComClose( fid, lastWriteTime ), blank_resp ); } - /** * Returns the last component of the target URL. This will * effectively be the name of the file or directory represented by this * SmbFile or in the case of URLs that only specify a server * or workgroup, the server or workgroup will be returned. The name of - * the root URL smb:// is also smb://. + * the root URL smb:// is also smb://. If this + * SmbFile refers to a workgroup, server, share, or directory, + * the name will include a trailing slash '/' so that composing new + * SmbFiles will maintain the trailing slash requirement introduced + * in jcifs-0.7.0b4. * * @return The last component of the URL associated with this SMB * resource or smb:// if the resource is smb:// @@ -505,8 +597,20 @@ public class SmbFile { */ public String getName() { - int p = url.lastIndexOf( '/' ) + 1; - return p == url.length() ? "smb://" : url.substring( p ); + getUncPath0(); + if( canon.length() > 1 ) { + int i = canon.length() - 2; + while( canon.charAt( i ) != '/' ) { + i--; + } + return canon.substring( i + 1 ); + } else if( share != null ) { + return share + '/'; + } else if( url.getHost().length() > 0 ) { + return url.getHost() + '/'; + } else { + return "smb://"; + } } /** @@ -520,8 +624,24 @@ public class SmbFile { */ public String getParent() { - int p = url.lastIndexOf( '/' ); - return p > 5 ? url.substring( 0, p ) : "smb://"; + StringBuffer sb = new StringBuffer( "smb://" ); + String str = url.getAuthority(); + if( str.length() > 0 ) { + sb.append( str ); + sb.append( '/' ); + } + getUncPath0(); + if( canon.length() > 1 ) { + int i = canon.length() - 2; + while( canon.charAt( i ) != '/' ) { + i--; + } + if( i > 1 ) { + sb.append( canon.substring( 1, i )); + sb.append( '/' ); + } + } + return sb.toString(); } /** @@ -533,9 +653,90 @@ public class SmbFile { */ public String getPath() { - return url; + return url.toString(); } + String getUncPath0() { + if( unc == null ) { + char[] in = url.getPath().toCharArray(); + char[] out = new char[in.length]; + int i, o, state, s; + + state = 0; + o = 0; + for( i = 0; i < in.length; i++ ) { + switch( state ) { + case 0: + if( in[i] != '/' ) { + return null; + } + out[o++] = in[i]; + state = 1; + break; + case 1: + if( in[i] == '/' ) { + break; + } else if( in[i] == '.' && + (( i + 1 ) >= in.length || in[i + 1] == '/' )) { + i++; + break; + } else if(( i + 1 ) < in.length && + in[i] == '.' && + in[i + 1] == '.' && + (( i + 2 ) >= in.length || in[i + 2] == '/' )) { + i += 2; + if( o == 1 ) break; + do { + o--; + } while( o > 1 && out[o - 1] != '/' ); + break; + } + state = 2; + case 2: + if( in[i] == '/' ) { + state = 1; + } + out[o++] = in[i]; + break; + } + } + + canon = new String( out, 0, o ); + + if( o > 1 ) { + o--; + i = canon.indexOf( '/', 1 ); + if( i < 0 ) { + share = canon.substring( 1 ); + unc = "\\"; + } else if( i == o ) { + share = canon.substring( 1, i ); + unc = "\\"; + } else { + share = canon.substring( 1, i ); + unc = canon.substring( i, out[o] == '/' ? o : o + 1 ); + unc = unc.replace( '/', '\\' ); + } + } else { + share = null; + unc = "\\"; + } + } + return unc; + } +/** + * Retuns the Windows UNC style path with backslashs intead of forward slashes. + * + * @return The UNC path. + */ + + public String getUncPath() { + String path = getUncPath0(); + if( share == null ) { + return "\\\\" + url.getHost(); + } + return "\\\\" + url.getHost() + "\\" + share + path; + } /** * Returns the full URL of this SMB resource with '.' and '..' components * factored out. An SmbFile constructed with the result of @@ -546,30 +747,12 @@ public class SmbFile { */ public String getCanonicalPath() { - StringBuffer sb = new StringBuffer( "smb://" ); - if( server == null ) { - return "smb://"; - } else if( authInfo.username != null ) { - if( authInfo.domain != null ) { - sb.append( authInfo.domain ).append( ';' ); - } - sb.append( authInfo.username ); - if( authInfo.password != null ) { - sb.append( ':' ).append( authInfo.password ); - } - sb.append( '@' ); - } - sb.append( server ); - if( port != 0 && port != 139 ) { - sb.append( ":" ).append( port ); - } - if( share != null ) { - sb.append( '/' ).append( share ); - if( canonicalPath != null ) { - sb.append( canonicalPath ); - } + String str = url.getAuthority(); + getUncPath0(); + if( str.length() > 0 ) { + return "smb://" + url.getAuthority() + canon; } - return sb.toString(); + return "smb://"; } /** @@ -596,28 +779,85 @@ public class SmbFile { */ public String getServer() { - return server; + String str = url.getHost(); + if( str.length() == 0 ) { + return null; + } + return str; } /** - * Determines wheather or not this resource is an NT Domain/workgroup by querying - * the NetBIOS name service. Only a URL of the form smb://name - * has the capacity to be a workgroup. - * - * @return true if this SmbFile refers to a - * workgroup and false otherwise. + * Returns type of of object this SmbFile represents. + * @return TYPE_FILESYSTEM, TYPE_WORKGROUP, TYPE_SERVER, TYPE_SHARE, + * TYPE_PRINTER, TYPE_NAMED_PIPE, or TYPE_COMM. */ - - public boolean isWorkgroup() { - return isWorkgroup; + public int getType() throws SmbException { + if( type == 0 ) { + if( getUncPath0().length() > 1 ) { + type = TYPE_FILESYSTEM; + } else if( share != null ) { + // treeConnect good enough to test service type + connect0(); + if( share.equals( "IPC$" )) { + type = TYPE_NAMED_PIPE; + } else if( tree.service.equals( "LPT1:" )) { + type = TYPE_PRINTER; + } else if( tree.service.equals( "COMM" )) { + type = TYPE_COMM; + } else { + type = TYPE_SHARE; + } + } else if( url.getAuthority().length() == 0 ) { + type = TYPE_WORKGROUP; + } else { + UniAddress addr; + try { + addr = getAddress(); + } catch( UnknownHostException uhe ) { + throw new SmbException( SmbException.ERRCLI | + SmbException.ERRunknownHost, + "Unknown host: " + uhe.getMessage() ); + } + if( addr.getAddress() instanceof NbtAddress ) { + int code = ((NbtAddress)addr.getAddress()).getNameType(); + if( code == 0x1d || code == 0x1b ) { + type = TYPE_WORKGROUP; + return type; + } + } + type = TYPE_SERVER; + } + } + return type; + } + boolean isWorkgroup0() throws UnknownHostException { + if( type == TYPE_WORKGROUP || url.getHost().length() == 0 ) { + type = TYPE_WORKGROUP; + return true; + } else { + getUncPath0(); + if( share == null ) { + UniAddress addr = getAddress(); + if( addr.getAddress() instanceof NbtAddress ) { + int code = ((NbtAddress)addr.getAddress()).getNameType(); + if( code == 0x1d || code == 0x1b ) { + type = TYPE_WORKGROUP; + return true; + } + } + type = TYPE_SERVER; + } + } + return false; } - Info queryPath( int infoLevel ) throws SmbException { + Info queryPath( String path, int infoLevel ) throws SmbException { SmbTransport trans; - Info info; + + connect0(); Log.println( Log.WARNINGS, "smb query path warning", - " querying path=" + uncPath ); + " querying path=" + path ); /* normally we'd check the negotiatedCapabilities for CAP_NT_SMBS * however I can't seem to get a good last modified time from @@ -627,22 +867,18 @@ public class SmbFile { * to(overrides negotiatedCapabilities). */ - /* make sure we're negotiated before we query capabilities - */ - trans = SmbTransport.getSmbTransport( address, port ); - trans.negotiate(); - if(( trans.server.capabilities & ServerMessageBlock.CAP_NT_SMBS ) == - ServerMessageBlock.CAP_NT_SMBS ) { + if( tree.session.transport.hasCapability( ServerMessageBlock.CAP_NT_SMBS )) { /* * Trans2 Query Path Information Request / Response */ Trans2QueryPathInformationResponse response = - new Trans2QueryPathInformationResponse( infoLevel ); - sendTransaction( new Trans2QueryPathInformation( uncPath, - infoLevel ), response ); - info = response.info; + new Trans2QueryPathInformationResponse( infoLevel ); + sendTransaction( new Trans2QueryPathInformation( path, + infoLevel ), response ); + + return response.info; } else { /* @@ -650,13 +886,11 @@ public class SmbFile { */ SmbComQueryInformationResponse response = - new SmbComQueryInformationResponse( - trans.server.serverTimeZone * 1000 * 60L ); - send( new SmbComQueryInformation( uncPath ), response ); - info = (Info)response; + new SmbComQueryInformationResponse( + tree.session.transport.server.serverTimeZone * 1000 * 60L ); + send( new SmbComQueryInformation( path ), response ); + return response; } - - return info; } /** @@ -673,42 +907,32 @@ public class SmbFile { * false otherwise */ - void updateAttributes() throws SmbException { - Info info; + public boolean exists() throws SmbException { if( attrExpiration > System.currentTimeMillis() ) { - return; + return isExists; } attributes = ATTR_READONLY | ATTR_DIRECTORY; lastModified = 0L; - info = queryPath( Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO ); - attributes = info.getAttributes(); - lastModified = info.getLastWriteTime(); - - attrExpiration = System.currentTimeMillis() + ATTR_EXPIRATION_PERIOD; - } - public boolean exists() throws SmbException { - if( attrExpiration > System.currentTimeMillis() ) { - return isExists; - } - isExists = false; try { - if( server == null ) { - isExists = true; + if( url.getHost().length() == 0 ) { } else if( share == null ) { - if( isWorkgroup ) { - NbtAddress.getByName( server, 0x1d, null ); + if( true || type == TYPE_WORKGROUP ) { + UniAddress.getByName( url.getHost(), true ); } else { - UniAddress.getByName( server ).getHostName(); + UniAddress.getByName( url.getHost() ).getHostName(); } - } else if( canonicalPath == null || + } else if( getUncPath0().length() == 1 || share.equalsIgnoreCase( "IPC$" )) { - send( null, null ); // treeConnect is good enough + connect0(); // treeConnect is good enough } else { - updateAttributes(); + Info info = queryPath( getUncPath0(), + Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO ); + attributes = info.getAttributes(); + lastModified = info.getLastWriteTime(); } /* If any of the above fail, isExists will not be set true @@ -717,17 +941,18 @@ public class SmbFile { isExists = true; } catch( UnknownHostException uhe ) { - isExists = false; } catch( SmbException se ) { if( se.errorClass == SmbException.ERRDOS && ( se.errorCode == SmbException.ERRbadfile || - se.errorCode == SmbException.ERRbadnetname )) { - isExists = false; + se.errorCode == SmbException.ERRbadnetname || + se.errorCode == SmbException.ERRbadpath )) { } else { throw se; } } + attrExpiration = System.currentTimeMillis() + attrExpirationPeriod; + return isExists; } @@ -740,7 +965,7 @@ public class SmbFile { */ public boolean canRead() throws SmbException { - if( isPipe ) { // try opening the pipe for writing? + if( getType() == TYPE_NAMED_PIPE ) { // try opening the pipe for reading? return true; } return exists(); // try opening and catch sharing violation? @@ -758,7 +983,7 @@ public class SmbFile { */ public boolean canWrite() throws SmbException { - if( isPipe ) { // try opening the pipe for writing? + if( getType() == TYPE_NAMED_PIPE ) { // try opening the pipe for writing? return true; } return exists() && ( attributes & ATTR_READONLY ) == 0; @@ -771,10 +996,10 @@ public class SmbFile { */ public boolean isDirectory() throws SmbException { - if( canonicalPath == null ) { + if( getUncPath0().length() == 1 ) { return true; } - updateAttributes(); + exists(); return ( attributes & ATTR_DIRECTORY ) == ATTR_DIRECTORY; } @@ -785,10 +1010,10 @@ public class SmbFile { */ public boolean isFile() throws SmbException { - if( canonicalPath == null ) { + if( getUncPath0().length() == 1 ) { return false; } - updateAttributes(); + exists(); return ( attributes & ATTR_DIRECTORY ) == 0; } @@ -801,13 +1026,13 @@ public class SmbFile { public boolean isHidden() throws SmbException { if( share == null ) { return false; - } else if( canonicalPath == null ) { + } else if( getUncPath0().length() == 1 ) { if( share.endsWith( "$" )) { return true; } return false; } - updateAttributes(); + exists(); return ( attributes & ATTR_HIDDEN ) == ATTR_HIDDEN; } @@ -823,41 +1048,49 @@ public class SmbFile { */ public long lastModified() throws SmbException { - if( canonicalPath != null ) { - updateAttributes(); + if( getUncPath0().length() > 1 ) { + exists(); return lastModified; } return 0L; } /** - * List the contents of this SMB resource. The list returned by this method will be; + * List the contents of this SMB resource. The list returned by this + * method will be; * *

    - *
  • files and directories contained within this resource if the resource is a normal disk file directory, - *
  • all available NetBIOS workgroups or domains if this resource is the top level URL smb://, - *
  • all servers registered as members of a NetBIOS workgroup if this resource refers to a workgroup in a smb://workgroup URL, - *
  • all browseable shares of a server including printers, IPC services, or disk volumes if this resource is a server URL in the form smb://server, + *
  • files and directories contained within this resource if the + * resource is a normal disk file directory, + *
  • all available NetBIOS workgroups or domains if this resource is + * the top level URL smb://, + *
  • all servers registered as members of a NetBIOS workgroup if this + * resource refers to a workgroup in a smb://workgroup URL, + *
  • all browseable shares of a server including printers, IPC + * services, or disk volumes if this resource is a server URL in the form + * smb://server, *
  • or null if the resource cannot be resolved. *
* - * @return A String array of file and directories, workgroups, servers, or shares depending on the context of the resource URL + * @return A String[] array of files and directories, + * workgroups, servers, or shares depending on the context of the + * resource URL */ public String[] list() throws SmbException { - if( server == null ) { - // if share is null send/sendTransaction will tcon to IPC$ - SmbTransport trans = SmbTransport.getSmbTransport( address, port ); - trans.negotiate(); + connect0(); + + if( url.getHost().length() == 0 ) { NetServerEnum2Response response = new NetServerEnum2Response(); - sendTransaction( new NetServerEnum2( trans.server.oemDomainName, - NetServerEnum2.SV_TYPE_DOMAIN_ENUM ), response ); + sendTransaction( new NetServerEnum2( + tree.session.transport.server.oemDomainName, + NetServerEnum2.SV_TYPE_DOMAIN_ENUM ), response ); if( response.status != SmbException.NERR_Success && - response.status != SmbException.ERROR_MORE_DATA ) { + response.status != SmbException.ERROR_MORE_DATA ) { throw new SmbException( SmbException.ERRRAP, - response.status, response.toString() ); + response.status, response.toString() ); } String[] ret = new String[response.entriesReturned]; @@ -866,9 +1099,9 @@ public class SmbFile { } return ret; } else if( share == null ) { - if( isWorkgroup ) { + if( getType() == TYPE_WORKGROUP ) { NetServerEnum2Response response = new NetServerEnum2Response(); - sendTransaction( new NetServerEnum2( server, + sendTransaction( new NetServerEnum2( url.getHost(), NetServerEnum2.SV_TYPE_ALL ), response ); if( response.status != SmbException.NERR_Success && @@ -899,7 +1132,7 @@ public class SmbFile { return ret; } } else { - return list( uncPath ); + return list( unc ); } } String[] list( String dirPath ) throws SmbException { @@ -908,7 +1141,7 @@ public class SmbFile { String filename; Log.println( Log.WARNINGS, "smb find warning", - " find with path=" + canonicalPath ); + " find with path=" + dirPath ); Trans2FindFirst2Response response = new Trans2FindFirst2Response(); sendTransaction( new Trans2FindFirst2( dirPath + "\\*" ), response ); @@ -963,7 +1196,7 @@ public class SmbFile { } } - send( new SmbComFindClose2( sid ), new SmbComBlankResponse() ); + send( new SmbComFindClose2( sid ), blank_resp ); if( results.length != count ) { String[] tmp = results; @@ -975,6 +1208,259 @@ public class SmbFile { } /** + * List the contents of this SMB resource as an array of + * SmbFile objects. This method is much more efficient than + * the regular list method when querying attributes of each + * file in the result set. + *

+ * The list of SmbFiles returned by this method will be; + * + *

    + *
  • files and directories contained within this resource if the + * resource is a normal disk file directory, + *
  • all available NetBIOS workgroups or domains if this resource is + * the top level URL smb://, + *
  • all servers registered as members of a NetBIOS workgroup if this + * resource refers to a workgroup in a smb://workgroup URL, + *
  • all browseable shares of a server including printers, IPC + * services, or disk volumes if this resource is a server URL in the form + * smb://server, + *
  • or null if the resource cannot be resolved. + *
+ * + * @return An array of SmbFile objects representing file + * and directories, workgroups, servers, or shares depending on the context + * of the resource URL + */ + + public SmbFile[] listFiles() throws SmbException { + return listFiles( "*" ); + } + +/** + * The CIFS protocol provides for DOS "wildcards" to be used as + * a performance enhancement. The client does not have to filter + * the names ane the server does not have to return all directory + * entries. + *

+ * The wildcard expression may consist of two special meta + * characters in addition to the normal filename characters. The '*' + * character matches any number of characters in part of a name. If + * the expression begins with one or more '?'s then exactly that + * many characters will be matched whereas if it ends with '?'s + * it will match that many characters or less. + *

+ * Wildcard expressions will not filter workgroup names or server names. + * + *

+ * winnt> ls c?o*
+ * clock.avi                  -rw--      82944 Mon Oct 14 1996 1:38 AM
+ * Cookies                    drw--          0 Fri Nov 13 1998 9:42 PM
+ * 2 items in 5ms
+ * 
+ * + * @param wildcard a wildcard expression + * @throws SmbException + * @return An array of SmbFile objects representing file + * and directories, workgroups, servers, or shares depending on the context + * of the resource URL + */ + + public SmbFile[] listFiles( String wildcard ) throws SmbException { + if( url.toString().lastIndexOf( '/' ) != ( url.toString().length() - 1 )) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRlistFiles, url.toString() + " directory must end with '/'" ); + } + try { + if( url.getHost().length() == 0 ) { + connect0(); + + NetServerEnum2Response response = new NetServerEnum2Response(); + sendTransaction( new NetServerEnum2( + tree.session.transport.server.oemDomainName, + NetServerEnum2.SV_TYPE_DOMAIN_ENUM ), response ); + + if( response.status != SmbException.NERR_Success && + response.status != SmbException.ERROR_MORE_DATA ) { + throw new SmbException( SmbException.ERRRAP, + response.status, response.toString() ); + } + + SmbFile[] ret = new SmbFile[response.entriesReturned]; + for( int i = 0; i < response.entriesReturned; i++ ) { + ret[i] = new SmbFile( this, + response.results[i].name, + TYPE_WORKGROUP, + ATTR_READONLY | ATTR_DIRECTORY, + 0L, + 0L ); + } +//System.err.println( "ret=" + ret.length + ",ret[0]=" + ret[0] + ",name=" + response.results[0].name ); + + return ret; + } else if( share == null ) { + if( getType() == TYPE_WORKGROUP ) { + NetServerEnum2Response response = new NetServerEnum2Response(); + sendTransaction( new NetServerEnum2( url.getHost(), + NetServerEnum2.SV_TYPE_ALL ), response ); + + if( response.status != SmbException.NERR_Success && + response.status != SmbException.ERROR_MORE_DATA ) { + throw new SmbException( SmbException.ERRRAP, response.status ); + } + + SmbFile[] ret = new SmbFile[response.entriesReturned]; + for( int i = 0; i < response.entriesReturned; i++ ) { + ret[i] = new SmbFile( this, + response.results[i].name, + TYPE_SERVER, + ATTR_READONLY | ATTR_DIRECTORY, + 0L, + 0L ); + } + + return ret; + } else { + NetShareEnumResponse response = new NetShareEnumResponse(); + sendTransaction( new NetShareEnum(), response ); + + if( response.status != SmbException.NERR_Success && + response.status != SmbException.ERROR_MORE_DATA ) { + throw new SmbException( SmbException.ERRRAP, response.status ); + } + + SmbFile[] ret = new SmbFile[response.entriesReturned]; + for( int i = 0; i < response.entriesReturned; i++ ) { + int shareType = response.results[i].type; + switch( shareType ) { + case 1: + shareType = TYPE_PRINTER; + break; + case 3: + shareType = TYPE_NAMED_PIPE; + break; + default: + shareType = TYPE_SHARE; + break; + } + ret[i] = new SmbFile( this, + response.results[i].netName, + shareType, + ATTR_READONLY | ATTR_DIRECTORY, + 0L, + 0L ); + } + return ret; + } + } else { + return listFiles( getUncPath0(), wildcard ); + } + } catch( UnknownHostException uhe ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRunknownHost, url.toString() ); + } catch( MalformedURLException mue ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRlistFiles, url.toString() ); + } + } + SmbFile[] listFiles( String dirPath, String wildcard ) throws SmbException { + int sid, count, i, j; + SmbFile[] results; + String base, filename; + + Log.println( Log.WARNINGS, "smb find warning", + " find with path=" + dirPath ); + + Trans2FindFirst2Response response = new Trans2FindFirst2Response(); + if( dirPath.equals( "\\" )) { + filename = "\\" + wildcard; + } else { + filename = dirPath + "\\" + wildcard; + } + sendTransaction( new Trans2FindFirst2( filename ), response ); + + sid = response.sid; + count = response.searchCount; + j = 0; + + results = new SmbFile[Math.max( 16, count )]; + + int h1 = new String( "." ).hashCode(); + int h2 = new String( ".." ).hashCode(); + i = 0; + try { + while( j < count ) { + filename = response.results[i].filename; + if( filename.length() < 3 ) { + int h = filename.hashCode(); + if( h == h1 || h == h2 ) { + count--; + i++; + continue; + } + } + results[j++] = new SmbFile( this, + filename, + TYPE_FILESYSTEM, + response.results[i].extFileAttributes, + response.results[i].lastWriteTime, + response.results[i].endOfFile ); + i++; + } + + /* only difference between first2 and next2 + * responses is subCommand so let's recycle + */ + response.subCommand = SmbComTransaction.TRANS2_FIND_NEXT2; + + while( response.isEndOfSearch == false && response.searchCount > 0 ) { + sendTransaction( new Trans2FindNext2( sid, response.resumeKey, + response.lastName ), response ); + count += response.searchCount; + + if( count > results.length ) { + SmbFile[] tmp = results; + results = new SmbFile[Math.max( results.length * 2, count )]; + System.arraycopy( tmp, 0, results, 0, j ); + } + i = 0; + while( j < count ) { + filename = response.results[i].filename; + if( filename.length() < 3 ) { + int h = filename.hashCode(); + if( h == h1 || h == h2 ) { + count--; + continue; + } + } + results[j++] = new SmbFile( this, + filename, + TYPE_FILESYSTEM, + response.results[i].extFileAttributes, + response.results[i].lastWriteTime, + response.results[i].endOfFile ); + i++; + } + } + } catch( UnknownHostException uhe ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRunknownHost, url.toString() ); + } catch( MalformedURLException mue ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRlistFiles, "Malformed URL: " + url.toString() ); + } + + send( new SmbComFindClose2( sid ), blank_resp ); + + if( results.length != count ) { + SmbFile[] tmp = results; + results = new SmbFile[count]; + System.arraycopy( tmp, 0, results, 0, count ); + } + + return results; + } +/** * Changes the name of the file this SmbFile represents to the name * designated by the SmbFile argument(Remember: * SmbFiles are immutible @@ -988,82 +1474,305 @@ public class SmbFile { */ public void renameTo( SmbFile dest ) throws SmbException { - if( canonicalPath == null || dest.canonicalPath == null ) { + if( getUncPath0().length() == 1 || dest.getUncPath0().length() == 1 ) { throw new SmbException( SmbException.ERRDOS, - SmbException.ERRnoaccess ); + SmbException.ERRnoaccess, + "Cannot rename shares, servers, workgroups, or domains" ); + } + connect0(); + dest.connect0(); + if( tree != dest.tree ) { + throw new SmbException( SmbException.ERRDOS, + SmbException.ERRnoaccess, + "Cannot rename file to a different share" ); } Log.println( Log.WARNINGS, "smb rename warning", - " oldFileName=" + uncPath + - ",newFileName=" + dest.uncPath ); + " oldFileName=" + unc + + ",newFileName=" + dest.unc ); - attrExpiration = 0; + attrExpiration = sizeExpiration = 0; /* * Rename Request / Response */ - SmbComBlankResponse response = new SmbComBlankResponse(); - send( new SmbComRename( uncPath, dest.uncPath ), response ); + send( new SmbComRename( unc, dest.unc ), blank_resp ); + } + + class WriterThread extends Thread { + byte[] b; + int n, off; + boolean ready = true; + SmbFile dest; + SmbException e = null; + SmbComWriteAndX req = new SmbComWriteAndX(); + SmbComWriteAndXResponse resp = new SmbComWriteAndXResponse(); + + WriterThread() { + super( "JCIFS-WriterThread" ); + } + + synchronized void write( byte[] b, int n, SmbFile dest, int off ) { + this.b = b; + this.n = n; + this.dest = dest; + this.off = off; + ready = false; + notify(); + } + + public void run() { + synchronized( this ) { + try { + for( ;; ) { + ready = true; + while( ready ) { + wait(); + } + if( n == -1 ) { + return; + } + req.setParam( dest.fid, off, n, b, 0, n ); + dest.send( req, resp ); + notify(); + } + } catch( SmbException e ) { + this.e = e; + } catch( Exception x ) { + this.e = new SmbException( SmbException.ERRCLI, + SmbException.ERRioe, x.getMessage() ); + } + notify(); + } + } + } + void copyTo0( SmbFile dest, byte[][] b, int bsize, WriterThread w, + SmbComReadAndX req, SmbComReadAndXResponse resp ) throws SmbException { + int i; + + if( attrExpiration < System.currentTimeMillis() ) { + attributes = ATTR_READONLY | ATTR_DIRECTORY; + lastModified = 0L; + isExists = false; + + Info info = queryPath( getUncPath0(), + Trans2QueryPathInformationResponse.SMB_QUERY_FILE_BASIC_INFO ); + attributes = info.getAttributes(); + lastModified = info.getLastWriteTime(); + + /* If any of the above fails, isExists will not be set true + */ + + isExists = true; + attrExpiration = System.currentTimeMillis() + attrExpirationPeriod; + } + + if( isDirectory() ) { + SmbFile[] files; + SmbFile ndest; + + try { + dest.mkdir(); + } catch( SmbException se ) { + if( se.getErrorCode() != SmbException.ERRnoaccess && + se.getErrorCode() != SmbException.ERRexists ) { + throw se; + } + } + + files = listFiles(); + try { + for( i = 0; i < files.length; i++ ) { + ndest = new SmbFile( dest, + files[i].getName(), + files[i].type, + files[i].attributes, + files[i].lastModified, + files[i].size ); + files[i].copyTo0( ndest, b, bsize, w, req, resp ); + } + } catch( UnknownHostException uhe ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRunknownHost, url.toString() ); + } catch( MalformedURLException mue ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRlistFiles, url.toString() ); + } + } else { + int off; + + open( SmbFile.O_RDONLY ); + dest.open( SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_TRUNC ); + + i = off = 0; + for( ;; ) { + req.setParam( fid, off, bsize ); + resp.setParam( b[i], 0 ); + send( req, resp ); + + synchronized( w ) { + while( !w.ready ) { + try { + w.wait(); + } catch( InterruptedException ie ) { + throw new SmbException( SmbException.ERRCLI, + SmbException.ERRioe, ie.getMessage() ); + } + } + if( w.e != null ) { + throw w.e; + } + if( resp.dataLength <= 0 ) { + break; + } + w.write( b[i], resp.dataLength, dest, off ); + } + + i = i == 1 ? 0 : 1; + off += resp.dataLength; + } + dest.close( lastModified - tree.session.transport.server.serverTimeZone * 60 * 1000 ); + close(); + } + } +/** + * This method will copy the file or directory and it's subcontents represented by this SmbFile to the location specified by the dest parameter. This file and the destination file do not need to be on the same host. This operation does not copy extended file attibutes and files copied to NT 4.0 will not preserve file modification times. +*/ + public void copyTo( SmbFile dest ) throws SmbException { + SmbComReadAndX req; + SmbComReadAndXResponse resp; + WriterThread w; + int bsize; + byte[][] b; + + /* Should be able to copy an entire share actually + */ + if( getUncPath0().length() == 1 || dest.getUncPath0().length() == 1 ) { + throw new SmbException( SmbException.ERRDOS, + SmbException.ERRnoaccess, + "Cannot copyTo workgroups, servers, or shares" ); + } + + req = new SmbComReadAndX(); + resp = new SmbComReadAndXResponse(); + w = new WriterThread(); + w.setDaemon( true ); + w.start(); + + connect0(); + dest.connect0(); + + bsize = Math.min( Math.min( tree.session.transport.rcv_buf_size - 70, + dest.tree.session.transport.server.maxBufferSize - 70 ), + Math.min( tree.session.transport.snd_buf_size - 70, + dest.tree.session.transport.server.maxBufferSize - 70 )); + b = new byte[2][bsize]; + + copyTo0( dest, b, bsize, w, req, resp ); + w.write( null, -1, null, 0 ); } /** * This method will delete the file or directory specified by this * SmbFile. If the target is a directory, the contents of - * the directory will be deleted as well. + * the directory will be deleted as well. If the resource or sub-resource + * is marked read-only or is locked the operation will fail. There is currently no functionality to set the attributes of a file, break locks, or disconnect users. * - * @return true if the delete operation was successfull and - * false otherwise + * @throws SmbException */ public void delete() throws SmbException { - delete( uncPath ); + delete( getUncPath0() ); } void delete( String fileName ) throws SmbException { - if( canonicalPath == null ) { + if( getUncPath0().length() == 1 ) { throw new SmbException( SmbException.ERRDOS, SmbException.ERRnoaccess ); } - attrExpiration = 0; - - Log.println( Log.WARNINGS, "smb delete warning", - " fileName=" + fileName ); - /* * Delete or Delete Directory Request / Response */ - ServerMessageBlock request = new SmbComDelete( fileName ); - try { - send( request, new SmbComBlankResponse() ); - return; - } catch( SmbException se ) { - } + if( isDirectory() ) { - /* Recursively delete directory contents using post order DFS - */ + /* Recursively delete directory contents + */ + + SmbFile[] l = listFiles( fileName, "*" ); + + for( int i = 0; i < l.length; i++ ) { + l[i].delete(); + } + + Log.println( Log.WARNINGS, "smb delete directory warning", + " fileName=" + fileName ); - String[] ls = list( fileName ); - for( int i = 0; i < ls.length; i++ ) { - delete( fileName + "\\" + ls[i] ); + send( new SmbComDeleteDirectory( fileName ), blank_resp ); + } else { + + Log.println( Log.WARNINGS, "smb delete warning", + " fileName=" + fileName ); + + send( new SmbComDelete( fileName ), blank_resp ); } - request = new SmbComDeleteDirectory( fileName ); - send( request, new SmbComBlankResponse() ); + attrExpiration = sizeExpiration = 0; } /** - * Returns the length in bytes of this file represented by this - * SmbFile. The SmbFile must not be a directory. + * Returns the length of this SmbFile in bytes. + * If this object is a TYPE_SHARE the total capacity of the disk shared in bytes is returned. + * If this object is a directory or a type other than TYPE_SHARE, 0L is returned. * - * @return The length of the file in bytes + * @return The length of the file in bytes or 0 if this SmbFile is not a file. */ public long length() throws SmbException { - if( canonicalPath != null ) { - Info info = queryPath( Trans2QueryPathInformationResponse.SMB_QUERY_FILE_STANDARD_INFO ); - return info.getSize(); + if( sizeExpiration > System.currentTimeMillis() ) { + return size; + } + + if( getType() == TYPE_SHARE ) { + Trans2QueryFSInformationResponse response; + int level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION; + + response = new Trans2QueryFSInformationResponse( level ); + sendTransaction( new Trans2QueryFSInformation( level ), response ); + + size = response.info.getCapacity(); + } else if( getUncPath0().length() > 1 && type != TYPE_NAMED_PIPE ) { + Info info = queryPath( getUncPath0(), + Trans2QueryPathInformationResponse.SMB_QUERY_FILE_STANDARD_INFO ); + size = info.getSize(); + } else { + size = 0L; + } + sizeExpiration = System.currentTimeMillis() + attrExpirationPeriod; + return size; + } + +/** + * This method returns the free disk space in bytes of the drive this share + * represents or the drive on which the directory or file resides. Objects + * other than TYPE_SHARE or TYPE_FILESYSTEM will result + * in 0L being returned. + */ + public long getDiskFreeSpace() throws SmbException { + if( getType() == TYPE_SHARE || type == TYPE_FILESYSTEM ) { + Trans2QueryFSInformationResponse response; + int level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION; + + response = new Trans2QueryFSInformationResponse( level ); + sendTransaction( new Trans2QueryFSInformation( level ), response ); + + if( type == TYPE_SHARE ) { + size = response.info.getCapacity(); + sizeExpiration = System.currentTimeMillis() + attrExpirationPeriod; + } + + return response.info.getFree(); } return 0L; } @@ -1071,42 +1780,68 @@ public class SmbFile { /** * Creates a directory with the path specified by this * SmbFile. For this method to be successfull, the target - * must not already exist. This method will return false when + * must not already exist. This method will fail when * used with smb://, smb://workgroup, * smb://server, or smb://server/share URLs * because workgroups, servers, and shares cannot be dynamically created. * - * @return true if the file was successfully created or - * false otherwise + * @throws SmbException */ public void mkdir() throws SmbException { - if( canonicalPath == null ) { + if( getUncPath0().length() == 1 ) { throw new SmbException( SmbException.ERRDOS, SmbException.ERRnoaccess ); } + Log.println( Log.WARNINGS, "smb create directory warning", - " directoryName=" + uncPath ); + " directoryName=" + getUncPath0() ); /* * Create Directory Request / Response */ - send( new SmbComCreateDirectory( uncPath ), - new SmbComBlankResponse() ); + send( new SmbComCreateDirectory( getUncPath0() ), blank_resp ); + + attrExpiration = sizeExpiration = 0; + } +/** + * Creates a directory with the path specified by this SmbFile and any parent directories if necessary. + * For this method to be successfull, the target + * must not already exist. This method will fail when + * used with smb://, smb://workgroup, + * smb://server, or smb://server/share URLs + * because workgroups, servers, and shares cannot be dynamically created. + * + * @throws SmbException + */ + public void mkdirs() throws SmbException { + SmbFile parent; + + try { + parent = new SmbFile( new URL( null, getParent(), Handler.SMB_HANDLER )); + } catch( IOException ioe ) { + return; + } + if( parent.exists() == false ) { + parent.mkdirs(); + } + mkdir(); } /** * Returns a {@link java.net.URL} for this SmbFile. The * URL may be used as any other URL might to - * access an smb resource. Currently only retrieving data and information + * access an SMB resource. Currently only retrieving data and information * is supported. * - * @return A new URL for this SmbFile + * @depricated Use getURL() instead + * + * @return A new {@link java.net.URL} for this SmbFile */ public URL toURL() throws MalformedURLException { - return new URL( getCanonicalPath() ); + return url; } /** @@ -1122,19 +1857,7 @@ public class SmbFile { */ public int hashCode() { - if( hash == 0 ) { - hash = address.hashCode(); - if( port != 0 && port != 139 ) { - hash += 65621 * port; - } - if( share != null ) { - hash += 65521 * share.toUpperCase().hashCode(); - if( canonicalPath != null ) { - hash += 65521 * canonicalPath.toUpperCase().hashCode(); - } - } - } - return hash; + return url.hashCode(); } /** @@ -1159,19 +1882,47 @@ public class SmbFile { */ public boolean equals( Object obj ) { +//HERE return obj instanceof SmbFile && obj.hashCode() == hashCode(); } /** * Returns the string representation of this SmbFile object. This will - * be the same as the URL used to construct this SmbFile. The - * path will not be canonicalized. This method will return the same value + * be the same as the URL used to construct this SmbFile. + * This method will return the same value * as getPath. * - * @return The URL representation of this SMB resource + * @return The original URL representation of this SMB resource */ public String toString() { - return url; + return url.toString(); + } + +/* URLConnection implementation */ + + public int getContentLength() { + try { + return (int)(length() & 0xFFFFFFFFL); + } catch( SmbException se ) { + } + return 0; + } + public long getDate() { + try { + return lastModified(); + } catch( SmbException se ) { + } + return 0L; + } + public long getLastModified() { + try { + return lastModified(); + } catch( SmbException se ) { + } + return 0L; + } + public InputStream getInputStream() throws IOException { + return new SmbFileInputStream( this ); } } diff --git a/src/jcifs/smb/SmbFileInputStream.java b/src/jcifs/smb/SmbFileInputStream.java index 9a3faa5..e0cf1a5 100644 --- a/src/jcifs/smb/SmbFileInputStream.java +++ b/src/jcifs/smb/SmbFileInputStream.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,19 +18,21 @@ package jcifs.smb; -import java.io.InputStream; -import java.io.IOException; +import java.net.URL; import java.net.UnknownHostException; import java.net.MalformedURLException; +import java.io.InputStream; +import java.io.IOException; /** - * This InputStream can read bytes from a file on an SMB file server. + * This InputStream can read bytes from a file on an SMB file server. Offsets are 64 bits. */ public class SmbFileInputStream extends InputStream { private SmbFile file; - private int fp, off, readSize, openFlags; + private long fp; + private int off, readSize, openFlags; private byte[] tmp = new byte[1]; /** @@ -113,7 +115,7 @@ public class SmbFileInputStream extends InputStream { if( len <= 0 ) { return 0; } - int start = fp; + long start = fp; // ensure file is open file.open( openFlags ); @@ -127,7 +129,7 @@ public class SmbFileInputStream extends InputStream { SmbComReadAndXResponse response = new SmbComReadAndXResponse( b, off ); - if( file.isPipe ) { + if( file.type == SmbFile.TYPE_NAMED_PIPE ) { response.responseTimeout = 0; } @@ -138,21 +140,45 @@ public class SmbFileInputStream extends InputStream { try { file.send( new SmbComReadAndX( file.fid, fp, r, null ), response ); } catch( SmbException se ) { - if( file.isPipe && se.errorClass == SmbException.ERRDOS && - se.errorCode == SmbException.ERRbrokenpipe ) { + if( file.type == SmbFile.TYPE_NAMED_PIPE && + se.errorClass == SmbException.ERRDOS && + se.errorCode == SmbException.ERRbrokenpipe ) { return -1; } throw se; } if(( n = response.dataLength ) <= 0 ) { - return -1; + return (int)((fp - start) > 0L ? fp - start : -1); } -//System.out.println( "n=" + n ); fp += n; len -= n; response.off += n; } while( len > 0 && n == r ); - return fp - start; + return (int)(fp - start); + } + public int available() throws IOException { + SmbNamedPipe pipe; + TransPeekNamedPipe req; + TransPeekNamedPipeResponse resp; + + if( file.type != SmbFile.TYPE_NAMED_PIPE ) { + return 0; + } + + pipe = (SmbNamedPipe)file; + file.open(( pipe.pipeType & 0xFF0000 ) | SmbFile.O_EXCL ); + + req = new TransPeekNamedPipe( file.unc, file.fid ); + resp = new TransPeekNamedPipeResponse( pipe ); + + pipe.sendTransaction( req, resp ); + if( resp.status == TransPeekNamedPipeResponse.STATUS_DISCONNECTED || + resp.status == TransPeekNamedPipeResponse.STATUS_SERVER_END_CLOSED ) { + file.opened = false; + return 0; + } + return resp.available; } } + diff --git a/src/jcifs/smb/SmbFileOutputStream.java b/src/jcifs/smb/SmbFileOutputStream.java index 2726835..5f2d285 100644 --- a/src/jcifs/smb/SmbFileOutputStream.java +++ b/src/jcifs/smb/SmbFileOutputStream.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,6 +18,7 @@ package jcifs.smb; +import java.net.URL; import java.io.OutputStream; import java.io.IOException; import java.net.UnknownHostException; @@ -31,7 +32,8 @@ public class SmbFileOutputStream extends OutputStream { private SmbFile file; private boolean append; - private int openFlags, fp, writeSize; + private int openFlags, writeSize; + private long fp; private byte[] tmp = new byte[1]; /** @@ -92,13 +94,39 @@ public class SmbFileOutputStream extends OutputStream { this( file, append, append ? SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_APPEND : SmbFile.O_CREAT | SmbFile.O_WRONLY | SmbFile.O_TRUNC ); } +/** + * Creates an {@link java.io.OutputStream} for writing bytes to a file + * on an SMB server addressed by the SmbFile parameter. See + * {@link jcifs.smb.SmbFile} for a detailed description and examples of + * the smb URL syntax. +

+The second parameter specifies how the file should be shared. If +SmbFile.FILE_NO_SHARE is specified the client will +have exclusive access to the file. An additional open command +from jCIFS or another application will fail with the "file is being +accessed by another process" error. The FILE_SHARE_READ, +FILE_SHARE_WRITE, and FILE_SHARE_DELETE may be +combined with the bitwise OR '|' to specify that other peocesses may read, +write, and/or delete the file while the jCIFS user has the file open. + * + * @param url An SmbFile representing the file to write to + * @return A new OutputStream for the specified SmbFile + */ + + public SmbFileOutputStream( String url, int shareAccess ) throws SmbException, MalformedURLException, UnknownHostException { + this( new SmbFile( url, "", null, shareAccess ), false ); + } SmbFileOutputStream( SmbFile file, boolean append, int openFlags ) throws SmbException, MalformedURLException, UnknownHostException { this.file = file; this.append = append; this.openFlags = openFlags; if( append ) { - fp = (int)file.length(); + try { + fp = file.length(); + } catch( SmbException se ) { + fp = 0L; + } } file.open( openFlags ); writeSize = Math.min( file.tree.session.transport.snd_buf_size - 70, @@ -155,12 +183,14 @@ public class SmbFileOutputStream extends OutputStream { if( file.isOpen() == false ) { file.open( openFlags ); if( append ) { - fp = (int)file.length(); + fp = file.length(); } } +/* Log.println( Log.WARNINGS, "smb write warning", " fid=" + file.fid + ",off=" + off + ",len=" + len ); +*/ int w; do { w = len > writeSize ? writeSize : len; diff --git a/src/jcifs/smb/SmbNamedPipe.java b/src/jcifs/smb/SmbNamedPipe.java index 796aad2..9289853 100644 --- a/src/jcifs/smb/SmbNamedPipe.java +++ b/src/jcifs/smb/SmbNamedPipe.java @@ -1,6 +1,6 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" - * "Paul Walker" + * Copyright (C) 2000 "Michael B. Allen" + * "Paul Walker" * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,7 @@ package jcifs.smb; +import java.net.URL; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -81,7 +82,6 @@ import java.net.UnknownHostException; * Named Pipes for a detailed description of how to use jCIFS with * Win32 Named Pipe server processes. * - * @since jcifs-0.5 */ public class SmbNamedPipe extends SmbFile { @@ -131,7 +131,19 @@ public class SmbNamedPipe extends SmbFile { throws MalformedURLException, UnknownHostException { super( url ); this.pipeType = pipeType; - isPipe = true; + type = TYPE_NAMED_PIPE; + } + public SmbNamedPipe( String url, int pipeType, NtlmPasswordAuthentication auth ) + throws MalformedURLException, UnknownHostException { + super( url, auth ); + this.pipeType = pipeType; + type = TYPE_NAMED_PIPE; + } + public SmbNamedPipe( URL url, int pipeType, NtlmPasswordAuthentication auth ) + throws MalformedURLException, UnknownHostException { + super( url, auth ); + this.pipeType = pipeType; + type = TYPE_NAMED_PIPE; } /** @@ -149,7 +161,7 @@ public class SmbNamedPipe extends SmbFile { if( pipeIn == null ) { if(( pipeType & PIPE_TYPE_CALL ) == PIPE_TYPE_CALL || ( pipeType & PIPE_TYPE_TRANSACT ) == PIPE_TYPE_TRANSACT ) { - pipeIn = new TransactNamedPipeInputStream(); + pipeIn = new TransactNamedPipeInputStream( this ); } else { pipeIn = new SmbFileInputStream( this, ( pipeType & 0xFF0000 ) | SmbFile.O_EXCL ); diff --git a/src/jcifs/smb/SmbSession.java b/src/jcifs/smb/SmbSession.java index a015461..9981daf 100644 --- a/src/jcifs/smb/SmbSession.java +++ b/src/jcifs/smb/SmbSession.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -18,78 +18,62 @@ package jcifs.smb; -import jcifs.util.DES; -import jcifs.util.MD4; -import java.io.UnsupportedEncodingException; -import java.util.Hashtable; import java.util.Vector; import java.util.Enumeration; import java.net.InetAddress; +import java.net.UnknownHostException; +import jcifs.UniAddress; + +/** + * 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 logon 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. + */ -class SmbSession { - - // KGS!@#$% - static final byte[] S8 = { - (byte)0x4b, (byte)0x47, (byte)0x53, (byte)0x21, - (byte)0x40, (byte)0x23, (byte)0x24, (byte)0x25 - }; - static void E( byte[] key, byte[] data, byte[] e ) { - byte[] key7 = new byte[7]; - byte[] e8 = new byte[8]; - - for( int i = 0; i < key.length / 7; i++ ) { - System.arraycopy( key, i * 7, key7, 0, 7 ); - DES des = new DES( key7 ); - des.encrypt( data, e8 ); - System.arraycopy( e8, 0, e, i * 8, 8 ); - } - } - static byte[] getPreNTLMResponse( String password, byte[] challenge ) { - byte[] p14 = new byte[14]; - byte[] p21 = new byte[21]; - byte[] p24 = new byte[24]; - - System.arraycopy( password.toUpperCase().getBytes(), 0, p14, 0, password.length() ); - E( p14, S8, p21); - E( p21, challenge, p24); - return p24; +public final class SmbSession { + + public static byte[] getChallenge( UniAddress dc ) throws SmbException, UnknownHostException { + SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 ); + trans.negotiate(); + return trans.server.encryptionKey; } - static byte[] getNTLMResponse( String password, byte[] challenge ) { - byte[] uni = null; - byte[] p21 = new byte[21]; - byte[] p24 = new byte[24]; - - try { - uni = password.getBytes( "UnicodeLittleUnmarked" ); - } catch( UnsupportedEncodingException uee ) { - Log.printStackTrace( "password encryption exception", uee ); - } - MD4 md4 = new MD4(); - md4.update( uni ); - System.arraycopy( md4.digest(), 0, p21, 0, 16 ); - E( p21, challenge, p24 ); - return p24; +/** + * Authenticate arbitrary credentials represented by the + * NtlmPasswordAuthentication object against the domain controller + * specified by the UniAddress parameter. If the credentials are + * not accepted, an SmbAuthException will be thrown. If an error + * occurs an SmbException will be thrown. If the credentials are + * valid, the method will return without throwing an exception. See the + * last FAQ question. + */ + public static void logon( UniAddress dc, + NtlmPasswordAuthentication auth ) throws SmbException { + SmbTransport.getSmbTransport( dc, 0 ).getSmbSession( auth ).getSmbTree( "IPC$", null ).treeConnect( null, null ); } int uid; - String username, password, domain; + NtlmPasswordAuthentication auth; SmbTransport transport; Vector trees; boolean sessionSetup; - String passwordString = "*****"; - SmbSession( SmbTransport transport, String username, - String password, String domain ) { + SmbSession( SmbTransport transport, NtlmPasswordAuthentication auth ) { this.transport = transport; - this.username = username.toUpperCase(); - this.password = password; - this.domain = domain.toUpperCase(); + this.auth = auth; trees = new Vector(); - passwordString = password == null ? "null" : ""; } 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 )) { @@ -100,13 +84,11 @@ class SmbSession { trees.addElement( t ); return t; } - boolean matches( String username, String password, String domain ) { - return this.username.equals( username.toUpperCase() ) && - this.password.equals( password ) && - this.domain.equals( domain.toUpperCase() ); + boolean matches( NtlmPasswordAuthentication auth ) { + return this.auth == auth || this.auth.equals( auth ); } void sendTransaction( SmbComTransaction request, - SmbComTransactionResponse response ) throws SmbException { + SmbComTransactionResponse response ) throws SmbException { // transactions are not batchable sessionSetup( null, null ); request.uid = uid; @@ -133,9 +115,8 @@ class SmbSession { } Log.println( Log.WARNINGS, "smb session setup warning", - " requesting session with accountName=" + username + - ",accountPassword=" + passwordString + - ",primaryDomain=" + domain ); + " requesting session with accountName=" + auth.username + + ",primaryDomain=" + auth.domain ); /* * Session Setup And X Request / Response @@ -147,33 +128,39 @@ class SmbSession { uid = response.uid; sessionSetup = true; } - synchronized void logoff() throws SmbException { + synchronized void logoff( boolean inError ) { if( sessionSetup == false ) { return; } for( Enumeration e = trees.elements(); e.hasMoreElements(); ) { SmbTree t = (SmbTree)e.nextElement(); - t.treeDisconnect(); + t.treeDisconnect( inError ); } - sessionSetup = false; if( transport.server.security == ServerMessageBlock.SECURITY_SHARE ) { return; } - /* - * Logoff And X Request / Response - */ + if( !inError ) { - SmbComLogoffAndX request = new SmbComLogoffAndX( null ); - request.uid = uid; - transport.send( request, null ); + /* + * Logoff And X Request / Response + */ + + try { + SmbComLogoffAndX request = new SmbComLogoffAndX( null ); + request.uid = uid; + transport.send( request, null ); + } catch( SmbException se ) { + } + } + sessionSetup = false; } public String toString() { - return "SmbSession[accountName=" + username + - ",accountPassword=" + passwordString + - ",primaryDomain=" + domain + - ",uid=" + uid + "]"; + return "SmbSession[accountName=" + auth.username + + ",primaryDomain=" + auth.domain + + ",uid=" + uid + + ",sessionSetup=" + sessionSetup + "]"; } } diff --git a/src/jcifs/smb/SmbTransport.java b/src/jcifs/smb/SmbTransport.java index 641a5aa..cf47e66 100644 --- a/src/jcifs/smb/SmbTransport.java +++ b/src/jcifs/smb/SmbTransport.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * Copyright (C) 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 @@ -41,16 +41,14 @@ class SmbTransport implements Runnable { private static final int DEFAULT_RESPONSE_TIMEOUT = 10000; private static final int DEFAULT_SO_TIMEOUT = 15000; private static final int PUSHBACK_BUF_SIZE = 64; - private static final int DEFAULT_RCV_BUF_SIZE = 4096; - private static final int DEFAULT_SND_BUF_SIZE = 1300; + private static final int DEFAULT_RCV_BUF_SIZE = 60416; + private static final int DEFAULT_SND_BUF_SIZE = 5000; static final int MID_OFFSET = 30; static final int HEADER_LENGTH = 32; static final int FLAGS_OFFSET = 9; static final int FLAGS_RESPONSE = 0x80; - private byte[] rcv_buf, snd_buf; - private NbtSocket socket; // should become UniSocket? private InputStream in; private OutputStream out; @@ -64,6 +62,9 @@ class SmbTransport implements Runnable { private static Vector connections = new Vector(); private static MpxControl mpxCtrl = new MpxControl(); +private static byte[] snd_buf = new byte[0xFFFF]; +private static byte[] rcv_buf = new byte[0xFFFF]; + Vector sessions; boolean negotiated, useUnicode; @@ -95,7 +96,7 @@ class SmbTransport implements Runnable { ServerMessageBlock.CAP_UNICODE | ServerMessageBlock.CAP_NT_SMBS ); String nativeOs = Config.getProperty( "jcifs.smb.client.nativeOs", System.getProperty( "os.name" )); - String nativeLanMan = Config.getProperty( "jcifs.smb.client.nativeLanMan", "foo" ); + String nativeLanMan = Config.getProperty( "jcifs.smb.client.nativeLanMan", "jCIFS" ); int vcNumber = 1; } class ServerProperties { @@ -140,6 +141,7 @@ class SmbTransport implements Runnable { return conn; } } + conn = new SmbTransport( address, port, localAddr, localPort ); connections.addElement( conn ); return conn; @@ -161,8 +163,7 @@ class SmbTransport implements Runnable { } soTimeout = Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT ); - responseTimeout = Config.getInt( "jcifs.smb.client.responseTimeout", - DEFAULT_RESPONSE_TIMEOUT ); + responseTimeout = Config.getInt( "jcifs.smb.client.responseTimeout", DEFAULT_RESPONSE_TIMEOUT ); rcv_buf_size = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE ); snd_buf_size = client.maxBufferSize; sessions = new Vector(); @@ -172,26 +173,20 @@ class SmbTransport implements Runnable { } synchronized SmbSession getSmbSession() { - return getSmbSession( null, null, null ); + return getSmbSession( new NtlmPasswordAuthentication( null, null, null )); } - synchronized SmbSession getSmbSession( String username, String password, String domain ) { - if( username == null ) { - username = Config.getProperty( "jcifs.smb.client.username", "guest" ); - } - if( password == null ) { - password = Config.getProperty( "jcifs.smb.client.password", "" ); - } - if( domain == null ) { - domain = Config.getProperty( "jcifs.smb.client.domain", "?" ); - } + synchronized SmbSession getSmbSession( NtlmPasswordAuthentication auth ) { SmbSession ssn; + for( Enumeration e = sessions.elements(); e.hasMoreElements(); ) { ssn = (SmbSession)e.nextElement(); - if( ssn.matches( username, password, domain )) { + if( ssn.matches( auth )) { + ssn.auth = auth; return ssn; } } - ssn = new SmbSession( this, username, password, domain ); + ssn = new SmbSession( this, auth ); +//System.err.println( "SESSION+: " + ssn + "\n " + sessions.toString() ); sessions.addElement( ssn ); return ssn; } @@ -210,6 +205,10 @@ class SmbTransport implements Runnable { la1.equals( la2 ) && localPort == this.localPort; } + boolean hasCapability( int cap ) throws SmbException { + negotiate(); + return (negotiatedCapabilities & cap) == cap; + } void ensureOpen() throws IOException { if( socket == null ) { Object obj; @@ -263,51 +262,64 @@ class SmbTransport implements Runnable { } in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE ); out = socket.getOutputStream(); - rcv_buf = BufferCache.getBuffer(); - snd_buf = BufferCache.getBuffer(); - thread = new Thread( this ); + thread = new Thread( this, "JCIFS-SmbTransport" ); thread.setDaemon( true ); thread.start(); } } - void tryClose() { - synchronized( outLock ) { - if( socket != null ) { - try { - for( Enumeration e = sessions.elements(); e.hasMoreElements(); ) { - ((SmbSession)e.nextElement()).logoff(); - } - socket.close(); - } catch( IOException ioe ) { - } + void tryClose( boolean inError ) { + SmbSession ssn; + + if( socket == null ) { + inError = true; + } + for( Enumeration e = sessions.elements(); e.hasMoreElements(); ) { + ssn = (SmbSession)e.nextElement(); + ssn.logoff( inError ); + } + if( socket != null ) { + try { + socket.close(); + } catch( IOException ioe ) { } - in = null; - out = null; - socket = null; - negotiated = false; - thread = null; - responseTable.clear(); - BufferCache.releaseBuffer( rcv_buf ); - BufferCache.releaseBuffer( snd_buf ); } + in = null; + out = null; + socket = null; + negotiated = false; + thread = null; + responseTable.clear(); } public void run() { - int mid, l, b, n; + int mid, l, i, n, m; ServerMessageBlock response; + int magic[] = { 0xFF, 'S', 'M', 'B' }; while( thread == Thread.currentThread() ) { try { socket.setSoTimeout( soTimeout ); - if(( b = in.read() ) == -1) { - break; - } - if(( b & 0xFF ) != 0xFF ) { - continue; + m = 0; + while( m < 4 ) { + if(( i = in.read() ) < 0 ) { + return; + } + if(( i & 0xFF ) == magic[m] ) { + m++; + } else if(( i & 0xFF ) == 0xFF ) { + m = 1; + } else { + m = 0; + } } + +synchronized( rcv_buf ) { rcv_buf[0] = (byte)0xFF; + rcv_buf[1] = (byte)'S'; + rcv_buf[2] = (byte)'M'; + rcv_buf[3] = (byte)'B'; - if( in.read( rcv_buf, 1, HEADER_LENGTH - 1 ) != HEADER_LENGTH - 1 ) { + if( in.read( rcv_buf, 4, HEADER_LENGTH - 4 ) != ( HEADER_LENGTH - 4 )) { /* Read on a netbios SocketInputStream does not * return until len bytes have been read or the stream is * closed. This must be the latter case. @@ -336,7 +348,7 @@ class SmbTransport implements Runnable { } synchronized( response ) { response.useUnicode = useUnicode; - Log.println( Log.DEBUGGING, "smb debugging", + Log.println( Log.WARNINGS, "smb transport warning", " new data read from socket" ); if( response instanceof SmbComTransactionResponse ) { @@ -376,17 +388,18 @@ class SmbTransport implements Runnable { } else { // it's a request(break oplock) } +} } catch( InterruptedIOException iioe ) { if( responseTable.size() == 0 ) { - tryClose(); + tryClose( false ); } else { Log.println( Log.WARNINGS, "smb warning", " soTimeout has occured but there are " + responseTable.size() + " pending requests" ); } } catch( IOException ioe ) { - Log.printStackTrace( "exception reading from socket input", ioe ); - tryClose(); + tryClose( true ); + Log.printStackTrace( "exception reading from socket input: " + address, ioe ); } } } @@ -404,6 +417,7 @@ class SmbTransport implements Runnable { try { synchronized( outLock ) { ensureOpen(); +synchronized( snd_buf ) { out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 )); out.flush(); @@ -414,8 +428,10 @@ class SmbTransport implements Runnable { Log.printMessageData( "smb andx data", smb ); } Log.printHexDump( "smb sent", snd_buf, 0, request.length ); +} } } catch( IOException ioe ) { + tryClose( true ); throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, ioe.getMessage() ); } finally { releaseMid( request.mid ); @@ -435,6 +451,7 @@ class SmbTransport implements Runnable { synchronized( outLock ) { ensureOpen(); +synchronized( snd_buf ) { out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 )); out.flush(); @@ -445,6 +462,7 @@ class SmbTransport implements Runnable { Log.printMessageData( "smb andx data", smb ); } Log.printHexDump( "smb sent", snd_buf, 0, request.length ); +} } // default it 1 so that 0 can be used as forever @@ -452,7 +470,9 @@ class SmbTransport implements Runnable { responseTimeout : response.responseTimeout ); } } catch( InterruptedException ie ) { + tryClose( true ); } catch( IOException ioe ) { + tryClose( true ); throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, ioe.getMessage() ); } finally { responseTable.remove( mid ); @@ -460,6 +480,7 @@ class SmbTransport implements Runnable { } if( response.received == false ) { + tryClose( true ); throw new SmbException( SmbException.ERRCLI, SmbException.ERRserverTimeout, address ); @@ -502,10 +523,10 @@ class SmbTransport implements Runnable { response.hasMore = true; response.isPrimary = true; - request.txn_buf = BufferCache.getBuffer(); - response.txn_buf = BufferCache.getBuffer(); - try { + request.txn_buf = BufferCache.getBuffer(); + response.txn_buf = BufferCache.getBuffer(); + request.nextElement(); if( request.hasMoreElements() ) { // multi-part request @@ -518,11 +539,13 @@ class SmbTransport implements Runnable { synchronized( outLock ) { ensureOpen(); +synchronized(snd_buf) { out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 )); out.flush(); Log.printMessageData( "smb sent", request ); Log.printHexDump( "smb sent", snd_buf, 0, request.length ); +} } interimResponse.wait( responseTimeout ); @@ -534,11 +557,11 @@ class SmbTransport implements Runnable { case SmbException.SUCCESS: break; case SmbException.ERRDOS: - switch(( interimResponse.errorCode >> 16 ) & 0xFFFF ) { + switch(( response.errorCode >> 16 ) & 0xFFFF ) { case SmbException.ERRnoaccess: - throw new SmbAuthException( interimResponse.errorCode ); + throw new SmbAuthException( response.errorCode ); } - throw new SmbException( interimResponse.errorCode ); + throw new SmbException( response.errorCode ); case SmbException.ERRSRV: switch(( interimResponse.errorCode >> 16 ) & 0xFFFF ) { case SmbException.ERRbadpw: @@ -561,11 +584,13 @@ class SmbTransport implements Runnable { do { synchronized( outLock ) { ensureOpen(); +synchronized( snd_buf ) { out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 )); out.flush(); Log.printMessageData( "smb sent", request ); Log.printHexDump( "smb sent", snd_buf, 0, request.length ); +} } } while( request.hasMoreElements() && request.nextElement() != null ); @@ -576,7 +601,9 @@ class SmbTransport implements Runnable { } while( response.received && response.hasMoreElements() ); } } catch( InterruptedException ie ) { + tryClose( true ); } catch( IOException ioe ) { + tryClose( true ); throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, ioe.getMessage() ); } finally { responseTable.remove( mid ); @@ -586,6 +613,7 @@ class SmbTransport implements Runnable { } if( response.received == false ) { + tryClose( true ); throw new SmbException( SmbException.ERRCLI, SmbException.ERRserverTimeout, address ); @@ -619,7 +647,7 @@ class SmbTransport implements Runnable { return; } /* we must set this here rather than later because this - * calls send which calls negotiate so we don't want to + * calls send() which calls negotiate so we don't want to * end up in a loop. The alternative would be to inline * the send routine here but this seems okay for now */ @@ -636,6 +664,7 @@ class SmbTransport implements Runnable { send( new SmbComNegotiate(), response ); if( response.dialectIndex > 10 ) { + tryClose( true ); throw new SmbException( SmbException.ERRCLI, SmbException.ERRbadDialect ); } @@ -676,10 +705,15 @@ class SmbTransport implements Runnable { server.oemDomainName = response.oemDomainName; } public String toString() { - return "SmbTransport[address=" + address + - ",port=" + socket.getPort() + + String ret = "SmbTransport[address=" + address; + if( socket == null ) { + ret += ",port=,localAddr=,localPort=]"; + } else { + ret += ",port=" + socket.getPort() + ",localAddr=" + socket.getLocalAddress() + ",localPort=" + socket.getLocalPort() + "]"; + } + return ret; } static int aquireMid() throws SmbException { @@ -764,11 +798,13 @@ class SmbTransport implements Runnable { if( tmp.i == i ) { if( tmp == first ) { first = first.next; - } - if( tmp == last ) { + } else if( tmp == last ) { last = prev; last.next = null; + } else { + prev.next = tmp.next; } + return; } prev = tmp; } diff --git a/src/jcifs/smb/SmbTree.java b/src/jcifs/smb/SmbTree.java index e3b32a3..63f1179 100644 --- a/src/jcifs/smb/SmbTree.java +++ b/src/jcifs/smb/SmbTree.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -33,21 +33,35 @@ class SmbTree { SmbTree( SmbSession session, String share, String service ) { this.session = session; - this.share = share; + this.share = share.toUpperCase(); if( service != null && service.startsWith( "??" ) == false ) { this.service = service; } } boolean matches( String share, String service ) { - return this.share.equals( share ) && + return this.share.equalsIgnoreCase( share ) && ( service == null || service.startsWith( "??" ) || - this.service.equals( service )); + this.service.equalsIgnoreCase( service )); } void sendTransaction( SmbComTransaction request, SmbComTransactionResponse response ) throws SmbException { // transactions are not batchable treeConnect( null, null ); + if( service.equals( "A:" ) == false ) { + switch( ((SmbComTransaction)request).subCommand ) { + case SmbComTransaction.NET_SHARE_ENUM: + case SmbComTransaction.NET_SERVER_ENUM2: + case SmbComTransaction.TRANS_PEEK_NAMED_PIPE: + case SmbComTransaction.TRANS_WAIT_NAMED_PIPE: + case SmbComTransaction.TRANS_CALL_NAMED_PIPE: + case SmbComTransaction.TRANS_TRANSACT_NAMED_PIPE: + break; + default: + throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, + "Invalid operation for " + service + " service"); + } + } request.tid = tid; session.sendTransaction( request, response ); } @@ -60,12 +74,35 @@ class SmbTree { if( request == null || (response != null && response.received )) { return; } + if( service.equals( "A:" ) == false ) { + switch( request.command ) { + case ServerMessageBlock.SMB_COM_OPEN_ANDX: + case ServerMessageBlock.SMB_COM_NT_CREATE_ANDX: + case ServerMessageBlock.SMB_COM_READ_ANDX: + case ServerMessageBlock.SMB_COM_WRITE_ANDX: + case ServerMessageBlock.SMB_COM_CLOSE: + case ServerMessageBlock.SMB_COM_TREE_DISCONNECT: + break; + default: + throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, + "Invalid operation for " + service + " service"); + } + } request.tid = tid; session.send( request, response ); } - synchronized void treeConnect( ServerMessageBlock andx, + void treeConnect( ServerMessageBlock andx, ServerMessageBlock andxResponse ) throws SmbException { String unc; +/* + * We must lock the session and *then* this tree because there is a small + * possibilty that the session could be trying to disconnect the tree at + * the same time. In this case it will have the session locked and wait + * indefinately trying to acquire the tree which would be locked trying to + * aquire the session resulting in deadlock. + */ +synchronized( session ) { + synchronized( this ) { if( treeConnected ) { return; @@ -97,18 +134,20 @@ class SmbTree { tid = response.tid; service = response.service; treeConnected = true; + } +} } - synchronized void treeDisconnect() { + synchronized void treeDisconnect( boolean inError ) { if( treeConnected == false ) { return; } - try { - send( new SmbComTreeDisconnect(), null ); - } catch( IOException ioe ) { - Log.printStackTrace( "smb tree disconnect exception", ioe ); - } finally { - treeConnected = false; + if( !inError ) { + try { + send( new SmbComTreeDisconnect(), null ); + } catch( SmbException ioe ) { + } } + treeConnected = false; } public String toString() { diff --git a/src/jcifs/smb/SmbURL.java b/src/jcifs/smb/SmbURL.java deleted file mode 100644 index cefb30a..0000000 --- a/src/jcifs/smb/SmbURL.java +++ /dev/null @@ -1,219 +0,0 @@ -/* 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.netbios.NbtAddress; -import jcifs.UniAddress; -import java.net.MalformedURLException; -import java.net.UnknownHostException; -import java.util.Vector; -import java.util.Enumeration; - -final class SmbURL { - - static void parseSmbURL( SmbFile file, String url, String name ) - throws MalformedURLException, UnknownHostException { - parseSmbURL( file, url, name, 4, url.length() ); - } - static void parseSmbURL( SmbFile file, String url, String name, - int start, int limit ) - throws MalformedURLException, UnknownHostException { - int beg, end, c, at, srv, pat; - - try { - if( name != null ) { - if( name.regionMatches( true, 0, "smb://", 0, 6 )) { - - /* If the secondard argument begins with - * 'smb://' then we simply replace the - * primary url argument with it and proceed - * as usuall. - */ - - url = name; - name = null; - start = 4; - limit = url.length(); - } else if( url.equalsIgnoreCase( "smb://" )) { - url = "smb://" + name; - name = null; - start = 4; - limit = url.length(); - } - } - - beg = start + 2; - end = limit; - if( end > beg ) { - while( end > beg && url.charAt( end - 1 ) == '/' ) { - end--; // trim trailing slashes - } - while( beg < end && url.charAt( beg ) != '/' && url.charAt( beg ) != '@' ) { - beg++; - } - if( beg == end && Character.isDigit( url.charAt( start + 2 )) == false ) { - int type; - // Could be a workgroup. Need to query the network to find out. - file.address = UniAddress.getByName( url.substring( 6, end ), true ); - type = ((NbtAddress)file.address.getAddress()).getNameType(); - if( type == 0x1d || type == 0x1b ) { - if( name != null ) { - url = "smb://" + name; - name = null; - start = 4; - limit = url.length(); - } else { - file.isWorkgroup = true; - } - } - } - } - - if( url.startsWith( "smb://" ) == false ) { - throw new MalformedURLException(); - } - - /* The java.net.URL parsing model always provides - * a start point of right after the ':'. So in the - * case of 'smb://' this would always be position - * 4. Because smb:// URLs always have 2 following - * slashes we can just bump-up start by 2 here - */ - - start += 2; - srv = start; - - at = url.lastIndexOf( '@' ); - if( at != -1 ) { - // server right after '@' - srv = at + 1; - - // parse authentication info - int u = start; - int i = start; - for( i = start; i < at; i++ ) { - c = url.charAt( i ); - if( c == ';' ) { - file.authInfo.domain = url.substring( start, i ); - u = i + 1; - } else if( c == ':' ) { - file.authInfo.password = url.substring( i + 1, at ); - break; - } - } - file.authInfo.username = url.substring( u, i ); - } - - file.server = url.substring( srv ); - - /* For the moment the server variable will - * contain everything that follows as well for - * feeding to the canonicalization via make-shift - * stack routine below. After that, the server, - * share, path, etc will be isolated. - */ - - if( name != null && name.length() != 0 ) { - - /* A secondary argument was provided. If - * it begins with '/' then we replace - * everything after the server with - * name. Otherwise we simply concatonate - * it onto the current path. - */ - - if( name.charAt( 0 ) == '/' ) { - int sha = url.indexOf( '/', srv ); - if( sha < srv ) { - sha = limit; - } - file.server = url.substring( srv, sha ); - if( name.equals( "/" ) == false ) { - file.server += name; - } - } else { - if( file.server.length() == 0 || file.server.endsWith( "/" )) { - file.server += name; - } else { - file.server = file.server + '/' + name; - } - } - } - file.url = url.substring( 0, srv ) + file.server; - limit = file.server.length(); - - /* The path must preserve all that was provided in - * the primary url argument and possibly secondary - * argument such that it could be fed back into the - * constructor of an SmbURL and the results would - * be equal. - */ - - Vector stk = new Vector(); - String str; - for( int i = 0, s = 0; i <= limit; i++ ) { - if( i == limit || file.server.charAt( i ) == '/' ) { - if( i > s ) { - str = file.server.substring( s, i ); - if( str.equals( ".." )) { - if( stk.isEmpty() == false ) { - stk.removeElementAt( stk.size() - 1 ); - } - } else if( str.equals( "." )) { - } else { - stk.addElement( str ); - } - } - s = i + 1; - } - } - - file.server = null; - if( stk.isEmpty() == false ) { - Enumeration e = stk.elements(); - file.server = (String)e.nextElement(); - - int p = file.server.indexOf( ':' ); - if( p > 0 ) { - file.port = Integer.parseInt( file.server.substring( p + 1 )); - file.server = file.server.substring( 0, p ); - } - - if( e.hasMoreElements() ) { - StringBuffer sb = new StringBuffer(); - - file.share = (String)e.nextElement(); - - while( e.hasMoreElements() ) { - sb.append( '/' ).append( e.nextElement() ); - } - - if( sb.length() > 0 ) { - file.canonicalPath = sb.toString(); - } - } - } - } catch( UnknownHostException uhe ) { - throw uhe; - } catch( Exception e ) { - throw new MalformedURLException( url + ", " + name ); - } - } -} - diff --git a/src/jcifs/smb/SmbURLConnection.java b/src/jcifs/smb/SmbURLConnection.java deleted file mode 100644 index 42512cf..0000000 --- a/src/jcifs/smb/SmbURLConnection.java +++ /dev/null @@ -1,132 +0,0 @@ -/* 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 java.net.URLConnection; -import java.net.URL; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * This class represents a communications link between an application and - * an SMB resource represented by a {@link java.net.URL}. An object of this type will be - * returned by the java.net.URL openConnection method when an SMB URL is - * used. See the {@link jcifs.smb.SmbFile} class for a detailed decription of - * the smb URL syntax with examples. - * - * Before referencing a java.net.URL or code that uses one - * with SMB URLs, the jcifs.Config class must be loaded. It - * contains a static initializer that installs the SMB specific protocol - * handler. If this protocol handler is not loaded the following Exception - * will occur: - * - *

- * java.net.MalformedURLException: unknown protocol: smb
- * 
- * - * It may be loaded by simply using the jcifs.Config class - * or if for no other reason the following code will do: - * - *
- * Class.forName( "jcifs.Config" );
- * 
- * - * In general this class is deficient; it only supports downloading - * via an InputStream. Adding more functionality is strait - * forward. If you require more functionality please express your intrest - * to the jcifs@samba.org mailing list. - */ - -public class SmbURLConnection extends URLConnection { - - SmbFile f; - - SmbURLConnection( URL u, SmbFile f ) { - super( u ); - this.f = f; - } - -/** - * Issue the actual socket IO necesary to open a connection with the server - * hosting the target resource. - */ - - public void connect() throws IOException { - if( connected ) { - return; - } - f.exists(); - } - -/** - * Return the length in bytes of the resource specified by the URL. - */ - - public int getContentLength() { - try { - return (int)f.length(); - } catch( SmbException se ) { - } - return 0; - } - -/** - * Retrieves the last modified time of the file or directory specified by - * the URL for this connection. - */ - - public long getDate() { - try { - return f.lastModified(); - } catch( SmbException se ) { - } - return 0L; - } - -/** - * Retrieves the last modified time of the file or directory specified by - * the URL for this connection. - */ - - public long getLastModified() { - try { - return f.lastModified(); - } catch( SmbException se ) { - } - return 0L; - } - -/** - * Create an InputStream from which bytes may be read from - * the taget specified by the URL of this connection. - */ - - public InputStream getInputStream() throws IOException { - return new SmbFileInputStream( f ); - } - -/** - * Return a String representing this object. - */ - - public String toString() { - return new String( "SmbURLConnection[url=" + f.toString() + "]" ); - } -} diff --git a/src/jcifs/smb/Trans2FindFirst2.java b/src/jcifs/smb/Trans2FindFirst2.java index 6422401..24cd0ee 100644 --- a/src/jcifs/smb/Trans2FindFirst2.java +++ b/src/jcifs/smb/Trans2FindFirst2.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/Trans2FindFirst2Response.java b/src/jcifs/smb/Trans2FindFirst2Response.java index 8aa860c..1f3c819 100644 --- a/src/jcifs/smb/Trans2FindFirst2Response.java +++ b/src/jcifs/smb/Trans2FindFirst2Response.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -85,31 +85,31 @@ class Trans2FindFirst2Response extends SmbComTransactionResponse { String readString( byte[] src, int srcIndex, int len ) { String str = null; - if( useUnicode ) { - // should Unicode alignment be corrected for here? - try { + try { + if( useUnicode ) { + // should Unicode alignment be corrected for here? str = new String( src, srcIndex, len, "UnicodeLittle" ); - } catch( UnsupportedEncodingException uee ) { - Log.printStackTrace( "smb exception", uee ); + } else { + + /* On NT without Unicode the fileNameLength + * includes the '\0' whereas on win98 it doesn't. I + * guess most clients only support non-unicode so + * they don't run into this. + */ + + /* UPDATE: Maybe not! Could this be a Unicode alignment issue. I hope + * so. We cannot just comment out this method and use readString of + * ServerMessageBlock.java because the arguments are different, however + * one might be able to reduce this. + */ + + if( len > 0 && src[srcIndex + len - 1] == '\0' ) { + len--; + } + str = new String( src, srcIndex, len, ServerMessageBlock.encoding ); } - } else { - - /* On NT without Unicode the fileNameLength - * includes the '\0' whereas on win98 it doesn't. I - * guess most clients only support non-unicode so - * they don't run into this. - */ - -/* UPDATE: Maybe not! Could this be a Unicode alignment issue. I hope - * so. We cannot just comment out this method and use readString of - * ServerMessageBlock.java because the arguments are different, however - * one might be able to reduce this. - */ - - if( len > 0 && src[srcIndex + len - 1] == '\0' ) { - len--; - } - str = new String( src, srcIndex, len ); + } catch( UnsupportedEncodingException uee ) { + Log.printStackTrace( "smb exception", uee ); } return str; } @@ -155,22 +155,22 @@ class Trans2FindFirst2Response extends SmbComTransactionResponse { results[i].nextEntryOffset = readInt4( buffer, bufferIndex ); results[i].fileIndex = readInt4( buffer, bufferIndex + 4 ); - results[i].creationTime = readTime( buffer, bufferIndex + 8 ); - results[i].lastAccessTime = readTime( buffer, bufferIndex + 16 ); + // results[i].creationTime = readTime( buffer, bufferIndex + 8 ); + // results[i].lastAccessTime = readTime( buffer, bufferIndex + 16 ); results[i].lastWriteTime = readTime( buffer, bufferIndex + 24 ); - results[i].changeTime = readTime( buffer, bufferIndex + 32 ); + // results[i].changeTime = readTime( buffer, bufferIndex + 32 ); results[i].endOfFile = readLong( buffer, bufferIndex + 40 ); - results[i].allocationSize = readLong( buffer, bufferIndex + 48 ); + // results[i].allocationSize = readLong( buffer, bufferIndex + 48 ); results[i].extFileAttributes = readInt4( buffer, bufferIndex + 56 ); results[i].fileNameLength = readInt4( buffer, bufferIndex + 60 ); - results[i].eaSize = readInt4( buffer, bufferIndex + 64 ); - results[i].shortNameLength = buffer[bufferIndex + 68] & 0xFF; + // results[i].eaSize = readInt4( buffer, bufferIndex + 64 ); + // results[i].shortNameLength = buffer[bufferIndex + 68] & 0xFF; /* With NT, the shortName is in Unicode regardless of what is negotiated. */ - results[i].shortName = readString( buffer, bufferIndex + 70, - results[i].shortNameLength ); + // results[i].shortName = readString( buffer, bufferIndex + 70, + // results[i].shortNameLength ); results[i].filename = readString( buffer, bufferIndex + 94, results[i].fileNameLength ); @@ -198,8 +198,8 @@ class Trans2FindFirst2Response extends SmbComTransactionResponse { if( lastName == null ) { - Log.println( Log.DEBUGGING, "Trans2FindFirst2/Next2Response debugging", - "lastName was null!" ); + Log.println( Log.WARNINGS, "Trans2FindFirst2/Next2Response debugging", + "lastName was null" ); } /* last nextEntryOffset for NT 4(but not 98) is 0 so we must diff --git a/src/jcifs/smb/Trans2FindNext2.java b/src/jcifs/smb/Trans2FindNext2.java index 23902fd..27425a3 100644 --- a/src/jcifs/smb/Trans2FindNext2.java +++ b/src/jcifs/smb/Trans2FindNext2.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/Trans2QueryFSInformation.jav b/src/jcifs/smb/Trans2QueryFSInformation.java similarity index 92% rename from src/jcifs/smb/Trans2QueryFSInformation.jav rename to src/jcifs/smb/Trans2QueryFSInformation.java index f3c2db3..0c860f3 100644 --- a/src/jcifs/smb/Trans2QueryFSInformation.jav +++ b/src/jcifs/smb/Trans2QueryFSInformation.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -22,10 +22,10 @@ class Trans2QueryFSInformation extends SmbComTransaction { int informationLevel; - Trans2QueryFSInformation() { + Trans2QueryFSInformation( int informationLevel ) { command = SMB_COM_TRANSACTION2; subCommand = TRANS2_QUERY_FS_INFORMATION; - informationLevel = Trans2QueryFSInformationResponse.SMB_QUERY_FS_ATTRIBUTE_INFO; + this.informationLevel = informationLevel; totalParameterCount = 2; totalDataCount = 0; maxParameterCount = 0; diff --git a/src/jcifs/smb/Trans2QueryFSInformationResponse.jav b/src/jcifs/smb/Trans2QueryFSInformationResponse.jav deleted file mode 100644 index db30391..0000000 --- a/src/jcifs/smb/Trans2QueryFSInformationResponse.jav +++ /dev/null @@ -1,96 +0,0 @@ -/* 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 java.io.UnsupportedEncodingException; - -class Trans2QueryFSInformationResponse extends SmbComTransactionResponse { - - // information levels - static final int SMB_QUERY_FS_ATTRIBUTE_INFO = 0x105; - - class SmbQueryFSAttributeInfo implements Info { - int attributes; - int maxNameLength; - String name; - - public int getAttributes() { - return attributes; - } - public long getLastWriteTime() { - return 0; - } - public long getSize() { - return 0; - } - public String toString() { - return new String( "SmbQueryFSAttributeInfo[" + - "attributes=0x" + Log.getHexString( attributes, 4 ) + - ",maxNameLength=" + maxNameLength + - ",name=" + name + "]" ); - } - } - - Info info; - - Trans2QueryFSInformationResponse() { - command = SMB_COM_TRANSACTION2; - subCommand = SmbComTransaction.TRANS2_QUERY_FS_INFORMATION; - } - - int writeSetupWireFormat( byte[] dst, int dstIndex ) { - return 0; - } - int writeParametersWireFormat( byte[] dst, int dstIndex ) { - return 0; - } - int writeDataWireFormat( byte[] dst, int dstIndex ) { - return 0; - } - int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) { - return 0; - } - int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) { - return 0; - } - int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) { - int start = bufferIndex; - - SmbQueryFSAttributeInfo info = new SmbQueryFSAttributeInfo(); - info.attributes = readInt4( buffer, bufferIndex ); - bufferIndex += 4; - info.maxNameLength = readInt2( buffer, bufferIndex ); - bufferIndex += 4; - int nameLength = readInt2( buffer, bufferIndex ); - bufferIndex += 4; - try { - info.name = new String( buffer, bufferIndex, nameLength, "UnicodeLittle" ); - } catch( UnsupportedEncodingException uee ) { - Log.printStackTrace( "", uee ); - } - bufferIndex += nameLength; - this.info = info; - - return bufferIndex - start; - } - public String toString() { - return new String( "Trans2QueryFSInformationResponse[" + - super.toString() + "]" ); - } -} diff --git a/src/jcifs/smb/Trans2QueryFSInformationResponse.java b/src/jcifs/smb/Trans2QueryFSInformationResponse.java new file mode 100644 index 0000000..5f31222 --- /dev/null +++ b/src/jcifs/smb/Trans2QueryFSInformationResponse.java @@ -0,0 +1,136 @@ +/* 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 java.io.UnsupportedEncodingException; + +class Trans2QueryFSInformationResponse extends SmbComTransactionResponse { + + // information levels + static final int SMB_INFO_ALLOCATION = 1; + static final int SMB_QUERY_FS_SIZE_INFO = 0x103; + + class SmbInfoAllocation implements AllocInfo { + long alloc; // Also handles SmbQueryFSSizeInfo + long free; + int sectPerAlloc; + int bytesPerSect; + + public long getCapacity() { + return alloc * sectPerAlloc * bytesPerSect; + } + public long getFree() { + return free * sectPerAlloc * bytesPerSect; + } + public String toString() { + return new String( "SmbInfoAllocation[" + + "alloc=" + alloc + ",free=" + free + + ",sectPerAlloc=" + sectPerAlloc + + ",bytesPerSect=" + bytesPerSect + "]" ); + } + } + + int informationLevel; + AllocInfo info; + + Trans2QueryFSInformationResponse( int informationLevel ) { + this.informationLevel = informationLevel; + command = SMB_COM_TRANSACTION2; + subCommand = SmbComTransaction.TRANS2_QUERY_FS_INFORMATION; + } + + int writeSetupWireFormat( byte[] dst, int dstIndex ) { + return 0; + } + int writeParametersWireFormat( byte[] dst, int dstIndex ) { + return 0; + } + int writeDataWireFormat( byte[] dst, int dstIndex ) { + return 0; + } + int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) { + return 0; + } + int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) { + return 0; + } + int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) { + switch( informationLevel ) { + case SMB_INFO_ALLOCATION: + return readSmbInfoAllocationWireFormat( buffer, bufferIndex ); + case SMB_QUERY_FS_SIZE_INFO: + return readSmbQueryFSSizeInfoWireFormat( buffer, bufferIndex ); + default: + return 0; + } + } + + int readSmbInfoAllocationWireFormat( byte[] buffer, int bufferIndex ) { + int start = bufferIndex; + + SmbInfoAllocation info = new SmbInfoAllocation(); + + bufferIndex += 4; // skip idFileSystem + + info.sectPerAlloc = readInt4( buffer, bufferIndex ); + bufferIndex += 4; + + info.alloc = readInt4( buffer, bufferIndex ); + bufferIndex += 4; + + info.free = readInt4( buffer, bufferIndex ); + bufferIndex += 4; + + info.bytesPerSect = readInt2( buffer, bufferIndex ); + bufferIndex += 4; + + this.info = info; + + return bufferIndex - start; + } + int readSmbQueryFSSizeInfoWireFormat( byte[] buffer, int bufferIndex ) { + int start = bufferIndex; + + SmbInfoAllocation info = new SmbInfoAllocation(); + + info.alloc = readInt4( buffer, bufferIndex ); + bufferIndex += 4; + info.alloc |= readInt4( buffer, bufferIndex ) << 32L; + bufferIndex += 4; + + info.free = readInt4( buffer, bufferIndex ); + bufferIndex += 4; + info.free |= readInt4( buffer, bufferIndex ) << 32L; + bufferIndex += 4; + + info.sectPerAlloc = readInt4( buffer, bufferIndex ); + bufferIndex += 4; + + info.bytesPerSect = readInt4( buffer, bufferIndex ); + bufferIndex += 4; + + this.info = info; + + return bufferIndex - start; + } + public String toString() { + return new String( "Trans2QueryFSInformationResponse[" + + super.toString() + "]" ); + } +} diff --git a/src/jcifs/smb/Trans2QueryPathInformation.java b/src/jcifs/smb/Trans2QueryPathInformation.java index a6739e2..ded6b14 100644 --- a/src/jcifs/smb/Trans2QueryPathInformation.java +++ b/src/jcifs/smb/Trans2QueryPathInformation.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/Trans2QueryPathInformationResponse.java b/src/jcifs/smb/Trans2QueryPathInformationResponse.java index be4b9a7..3d33ebb 100644 --- a/src/jcifs/smb/Trans2QueryPathInformationResponse.java +++ b/src/jcifs/smb/Trans2QueryPathInformationResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/TransCallNamedPipe.java b/src/jcifs/smb/TransCallNamedPipe.java index 2549cda..daaec80 100644 --- a/src/jcifs/smb/TransCallNamedPipe.java +++ b/src/jcifs/smb/TransCallNamedPipe.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/TransCallNamedPipeResponse.java b/src/jcifs/smb/TransCallNamedPipeResponse.java index 1b8fbe6..661ff77 100644 --- a/src/jcifs/smb/TransCallNamedPipeResponse.java +++ b/src/jcifs/smb/TransCallNamedPipeResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/TransPeekNamedPipe.java b/src/jcifs/smb/TransPeekNamedPipe.java new file mode 100644 index 0000000..fb712fb --- /dev/null +++ b/src/jcifs/smb/TransPeekNamedPipe.java @@ -0,0 +1,63 @@ +/* jcifs smb client library in Java + * Copyright (C) 2002 "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; + +class TransPeekNamedPipe extends SmbComTransaction { + + int fid; + + TransPeekNamedPipe( String pipeName, int fid ) { + name = pipeName; + this.fid = fid; + command = SMB_COM_TRANSACTION; + subCommand = TRANS_PEEK_NAMED_PIPE; + timeout = 0xFFFFFFFF; + maxParameterCount = 6; + maxDataCount = 1; + maxSetupCount = (byte)0x00; + setupCount = 2; + } + + int writeSetupWireFormat( byte[] dst, int dstIndex ) { + dst[dstIndex++] = subCommand; + dst[dstIndex++] = (byte)0x00; + // this says "Transaction priority" in netmon + writeInt2( fid, dst, dstIndex ); + return 4; + } + int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) { + return 0; + } + int writeParametersWireFormat( byte[] dst, int dstIndex ) { + return 0; + } + int writeDataWireFormat( byte[] dst, int dstIndex ) { + return 0; + } + int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) { + return 0; + } + int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) { + return 0; + } + public String toString() { + return new String( "TransPeekNamedPipe[" + super.toString() + + ",pipeName=" + name + "]" ); + } +} diff --git a/src/jcifs/smb/TransPeekNamedPipeResponse.java b/src/jcifs/smb/TransPeekNamedPipeResponse.java new file mode 100644 index 0000000..5e59af0 --- /dev/null +++ b/src/jcifs/smb/TransPeekNamedPipeResponse.java @@ -0,0 +1,59 @@ +/* jcifs smb client library in Java + * Copyright (C) 2002 "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; + +class TransPeekNamedPipeResponse extends SmbComTransactionResponse { + + static final int STATUS_DISCONNECTED = 1; + static final int STATUS_LISTENING = 2; + static final int STATUS_CONNECTION_OK = 3; + static final int STATUS_SERVER_END_CLOSED = 4; + + SmbNamedPipe pipe; + int available, head, status; + + TransPeekNamedPipeResponse( SmbNamedPipe pipe ) { + this.pipe = pipe; + } + + int writeSetupWireFormat( byte[] dst, int dstIndex ) { + return 0; + } + int writeParametersWireFormat( byte[] dst, int dstIndex ) { + return 0; + } + int writeDataWireFormat( byte[] dst, int dstIndex ) { + return 0; + } + int readSetupWireFormat( byte[] buffer, int bufferIndex, int len ) { + return 0; + } + int readParametersWireFormat( byte[] buffer, int bufferIndex, int len ) { + available = readInt2( buffer, bufferIndex ); bufferIndex += 2; + head = readInt2( buffer, bufferIndex ); bufferIndex += 2; + status = readInt2( buffer, bufferIndex ); + return 6; + } + int readDataWireFormat( byte[] buffer, int bufferIndex, int len ) { + return 0; + } + public String toString() { + return new String( "TransPeekNamedPipeResponse[" + super.toString() + "]" ); + } +} diff --git a/src/jcifs/smb/TransTransactNamedPipe.java b/src/jcifs/smb/TransTransactNamedPipe.java index 2c5cebc..378658f 100644 --- a/src/jcifs/smb/TransTransactNamedPipe.java +++ b/src/jcifs/smb/TransTransactNamedPipe.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/TransTransactNamedPipeResponse.java b/src/jcifs/smb/TransTransactNamedPipeResponse.java index ef5715d..9d91c6c 100644 --- a/src/jcifs/smb/TransTransactNamedPipeResponse.java +++ b/src/jcifs/smb/TransTransactNamedPipeResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/TransWaitNamedPipe.java b/src/jcifs/smb/TransWaitNamedPipe.java index 27a8e60..365221e 100644 --- a/src/jcifs/smb/TransWaitNamedPipe.java +++ b/src/jcifs/smb/TransWaitNamedPipe.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/TransWaitNamedPipeResponse.java b/src/jcifs/smb/TransWaitNamedPipeResponse.java index 47e30a0..1ab947a 100644 --- a/src/jcifs/smb/TransWaitNamedPipeResponse.java +++ b/src/jcifs/smb/TransWaitNamedPipeResponse.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/smb/TransactNamedPipeInputStream.java b/src/jcifs/smb/TransactNamedPipeInputStream.java index 364e4b8..367f14c 100644 --- a/src/jcifs/smb/TransactNamedPipeInputStream.java +++ b/src/jcifs/smb/TransactNamedPipeInputStream.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -25,14 +25,17 @@ class TransactNamedPipeInputStream extends InputStream { static final int INIT_PIPE_SIZE = 4096; + SmbNamedPipe pipe; byte[] pipe_buf = new byte[INIT_PIPE_SIZE]; int beg_idx, nxt_idx, used; Object lock; - TransactNamedPipeInputStream() { + TransactNamedPipeInputStream( SmbNamedPipe pipe ) { + this.pipe = pipe; lock = new Object(); } public void close() throws IOException { + pipe.close(); } public int read() throws IOException { int result = -1; @@ -73,7 +76,7 @@ class TransactNamedPipeInputStream extends InputStream { if( used > i && result > i ) { System.arraycopy( pipe_buf, beg_idx, b, off, i ); off += i; - System.arraycopy( pipe_buf, 0, b, off, result ); + System.arraycopy( pipe_buf, 0, b, off, result - i ); } else { System.arraycopy( pipe_buf, beg_idx, b, off, result ); } @@ -82,7 +85,11 @@ class TransactNamedPipeInputStream extends InputStream { } return result; } - + public int available() throws IOException { + Log.println( Log.WARNINGS, "Named Pipe warning", + "available does not apply to TRANSACT Named Pipes" ); + return 0; + } int receive( byte[] b, int off, int len ) { int i; @@ -96,10 +103,11 @@ class TransactNamedPipeInputStream extends InputStream { } tmp = pipe_buf; pipe_buf = new byte[new_size]; - i = pipe_buf.length - beg_idx; + i = tmp.length - beg_idx; if( used > i ) { System.arraycopy( tmp, beg_idx, pipe_buf, 0, i ); System.arraycopy( tmp, 0, pipe_buf, i, used - i ); + nxt_idx = used; } else { System.arraycopy( tmp, beg_idx, pipe_buf, 0, used ); } diff --git a/src/jcifs/smb/TransactNamedPipeOutputStream.java b/src/jcifs/smb/TransactNamedPipeOutputStream.java index e4af4f4..ef01ba9 100644 --- a/src/jcifs/smb/TransactNamedPipeOutputStream.java +++ b/src/jcifs/smb/TransactNamedPipeOutputStream.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 @@ -29,10 +29,11 @@ class TransactNamedPipeOutputStream extends OutputStream { TransactNamedPipeOutputStream( SmbNamedPipe pipe ) throws IOException { this.pipe = pipe; - path = pipe.uncPath; + path = pipe.unc; } public void close() throws IOException { + pipe.close(); } public void write( int b ) throws IOException { tmp[0] = (byte)b; @@ -48,14 +49,14 @@ class TransactNamedPipeOutputStream extends OutputStream { if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_CALL ) == SmbNamedPipe.PIPE_TYPE_CALL ) { - pipe.tree.sendTransaction( new TransWaitNamedPipe( path ), + pipe.sendTransaction( new TransWaitNamedPipe( path ), new TransWaitNamedPipeResponse() ); - pipe.tree.sendTransaction( new TransCallNamedPipe( path, b, off, len ), + pipe.sendTransaction( new TransCallNamedPipe( path, b, off, len ), new TransCallNamedPipeResponse( pipe )); } else if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_TRANSACT ) == SmbNamedPipe.PIPE_TYPE_TRANSACT ) { pipe.open(( pipe.pipeType & 0xFF0000 ) | SmbFile.O_EXCL ); - pipe.tree.sendTransaction( new TransTransactNamedPipe( pipe.fid, b, off, len ), + pipe.sendTransaction( new TransTransactNamedPipe( pipe.fid, b, off, len ), new TransTransactNamedPipeResponse( pipe )); } } diff --git a/src/jcifs/util/Base64.java b/src/jcifs/util/Base64.java new file mode 100644 index 0000000..297604d --- /dev/null +++ b/src/jcifs/util/Base64.java @@ -0,0 +1,549 @@ +package jcifs.util; + +import java.io.UnsupportedEncodingException; + +/** + * Encodes and decodes to and from Base64 notation. + * + *

+ * Change Log: + *

+ *
    + *
  • Trimmed object and stream releated methods for inclusion into jcifs.util package. + *
  • v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream + * where last buffer being read, if not completely full, was not returned.
  • + *
  • v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.
  • + *
  • v1.3.3 - Fixed I/O streams which were totally messed up.
  • + *
+ * + *

+ * I am placing this code in the Public Domain. Do with it as you will. + * This software comes with no guarantees or warranties but with + * plenty of well-wishing instead! + * Please visit http://iharder.net/xmlizable + * periodically to check for updates or to contribute improvements. + *

+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 1.3.4 + */ +public class Base64 +{ + + /** Specify encoding (value is true). */ + public final static boolean ENCODE = true; + + + /** Specify decoding (value is false). */ + public final static boolean DECODE = false; + + + /** Maximum line length (76) of Base64 output. */ + private final static int MAX_LINE_LENGTH = 76; + + + /** The equals sign (=) as a byte. */ + private final static byte EQUALS_SIGN = (byte)'='; + + + /** The new line character (\n) as a byte. */ + private final static byte NEW_LINE = (byte)'\n'; + + + /** The 64 valid Base64 values. */ + private final static byte[] ALPHABET = + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', + (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' + }; + + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + **/ + private final static byte[] DECODABET = + { + -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8 + -5,-5, // Whitespace: Tab and Linefeed + -9,-9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26 + -9,-9,-9,-9,-9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9,-9,-9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine + -9,-9,-9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9,-9,-9, // Decimal 62 - 64 + 0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N' + 14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z' + -9,-9,-9,-9,-9,-9, // Decimal 91 - 96 + 26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm' + 39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z' + -9,-9,-9,-9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + private final static byte BAD_ENCODING = -9; // Indicates error in encoding + private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding + private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding + + + /** Defeats instantiation. */ + private Base64(){} + +/* ******** E N C O D I N G M E T H O D S ******** */ + + + /** + * Encodes the first three bytes of array threeBytes + * and returns a four-byte array in Base64 notation. + * + * @param threeBytes the array to convert + * @return four byte array in Base64 notation. + * @since 1.3 + */ + private static byte[] encode3to4( byte[] threeBytes ) + { return encode3to4( threeBytes, 3 ); + } // end encodeToBytes + + + + /** + * Encodes up to the first three bytes of array threeBytes + * and returns a four-byte array in Base64 notation. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * The array threeBytes needs only be as big as + * numSigBytes. + * + * @param threeBytes the array to convert + * @param numSigBytes the number of significant bytes in your array + * @return four byte array in Base64 notation. + * @since 1.3 + */ + private static byte[] encode3to4( byte[] threeBytes, int numSigBytes ) + { byte[] dest = new byte[4]; + encode3to4( threeBytes, 0, numSigBytes, dest, 0 ); + return dest; + } + + + + /** + * Encodes up to three bytes of the array source + * and writes the resulting four Base64 bytes to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 3 for + * the source array or destOffset + 4 for + * the destination array. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4( + byte[] source, int srcOffset, int numSigBytes, + byte[] destination, int destOffset ) + { + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 ) + | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 ) + | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 ); + + switch( numSigBytes ) + { + case 3: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ]; + return destination; + + case 2: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ]; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + case 1: + destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ]; + destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ]; + destination[ destOffset + 2 ] = EQUALS_SIGN; + destination[ destOffset + 3 ] = EQUALS_SIGN; + return destination; + + default: + return destination; + } // end switch + } // end encode3to4 + + /** + * Encodes a byte array into Base64 notation. + * Equivalen to calling + * encodeBytes( source, 0, source.length ) + * + * @param source The data to convert + * @since 1.4 + */ + public static String encodeBytes( byte[] source ) + { + return encodeBytes( source, true ); + } // end encodeBytes + + /** + * Encodes a byte array into Base64 notation. + * Equivalen to calling + * encodeBytes( source, 0, source.length ) + * + * @param source The data to convert + * @param breakLines Break lines at 80 characters or less. + * @since 1.4 + */ + public static String encodeBytes( byte[] source, boolean breakLines ) + { + return encodeBytes( source, 0, source.length, breakLines ); + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @since 1.4 + */ + public static String encodeBytes( byte[] source, int off, int len ) + { + return encodeBytes( source, off, len, true ); + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param breakLines Break lines at 80 characters or less. + * @since 1.4 + */ + public static String encodeBytes( byte[] source, int off, int len, boolean breakLines ) + { + int len43 = len * 4 / 3; + byte[] outBuff = new byte[ ( len43 ) // Main 4:3 + + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding + + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines + int d = 0; + int e = 0; + int len2 = len - 2; + int lineLength = 0; + for( ; d < len2; d+=3, e+=4 ) + { + encode3to4( source, d+off, 3, outBuff, e ); + + lineLength += 4; + if( breakLines && lineLength == MAX_LINE_LENGTH ) + { + outBuff[e+4] = NEW_LINE; + e++; + lineLength = 0; + } // end if: end of line + } // en dfor: each piece of array + + if( d < len ) + { + encode3to4( source, d+off, len - d, outBuff, e ); + e += 4; + } // end if: some padding needed + + try { + return new String( outBuff, 0, e, "ASCII" ); + } catch( UnsupportedEncodingException uee ) { + } + return null; + } // end encodeBytes + + + /** + * Encodes a string in Base64 notation with line breaks + * after every 75 Base64 characters. + * + * @param s the string to encode + * @return the encoded string + * @since 1.3 + */ + public static String encodeString( String s ) + { + return encodeString( s, true ); + } // end encodeString + + /** + * Encodes a string in Base64 notation with line breaks + * after every 75 Base64 characters. + * + * @param s the string to encode + * @param breakLines Break lines at 80 characters or less. + * @return the encoded string + * @since 1.3 + */ + public static String encodeString( String s, boolean breakLines ) + { + try { + return encodeBytes( s.getBytes( "ASCII" ), breakLines ); + } catch( UnsupportedEncodingException uee ) { + } + return null; + } // end encodeString + + + + +/* ******** D E C O D I N G M E T H O D S ******** */ + + + /** + * Decodes the first four bytes of array fourBytes + * and returns an array up to three bytes long with the + * decoded values. + * + * @param fourBytes the array with Base64 content + * @return array with decoded values + * @since 1.3 + */ + private static byte[] decode4to3( byte[] fourBytes ) + { + byte[] outBuff1 = new byte[3]; + int count = decode4to3( fourBytes, 0, outBuff1, 0 ); + byte[] outBuff2 = new byte[ count ]; + + for( int i = 0; i < count; i++ ) + outBuff2[i] = outBuff1[i]; + + return outBuff2; + } + + + + + /** + * Decodes four bytes from array source + * and writes the resulting bytes (up to three of them) + * to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 4 for + * the source array or destOffset + 3 for + * the destination array. + * This method returns the actual number of bytes that + * were converted from the Base64 encoding. + * + * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the number of decoded bytes converted + * @since 1.3 + */ + private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset ) + { + // Example: Dk== + if( source[ srcOffset + 2] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + return 1; + } + + // Example: DkL= + else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) + { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 ); + + destination[ destOffset ] = (byte)( outBuff >>> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 ); + return 2; + } + + // Example: DkLE + else + { + try{ + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 ) + | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 ) + | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6) + | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) ); + + + destination[ destOffset ] = (byte)( outBuff >> 16 ); + destination[ destOffset + 1 ] = (byte)( outBuff >> 8 ); + destination[ destOffset + 2 ] = (byte)( outBuff ); + + return 3; + }catch( Exception e){ + jcifs.util.Log.println( jcifs.util.Log.WARNINGS, "Base64", ""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) ); + jcifs.util.Log.println( jcifs.util.Log.WARNINGS, "Base64", ""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) ); + jcifs.util.Log.println( jcifs.util.Log.WARNINGS, "Base64", ""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) ); + jcifs.util.Log.println( jcifs.util.Log.WARNINGS, "Base64", ""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) ); + return -1; + } //e nd catch + } + } // end decodeToBytes + + + + /** + * Decodes data from Base64 notation. + * + * @param s the string to decode + * @return the decoded data + * @since 1.4 + */ + public static byte[] decode( String s ) + { + try { + byte[] bytes = s.getBytes( "ASCII" ); + return decode( bytes, 0, bytes.length ); + } catch( UnsupportedEncodingException uee ) { + } + return null; + } // end decode + + + /** + * Decodes data from Base64 notation and + * returns it as a string. + * Equivlaent to calling + * new String( decode( s ) ) + * + * @param s the strind to decode + * @return The data as a string + * @since 1.4 + */ + public static String decodeToString( String s ) + { + try { + return new String( decode( s ), "ISO8859_1" ); + } catch( UnsupportedEncodingException uee ) { + } + return null; + } // end decodeToString + + + /** + * Decodes Base64 content in byte array format and returns + * the decoded byte array. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @return decoded data + * @since 1.3 + */ + public static byte[] decode( byte[] source, int off, int len ) + { + int len34 = len * 3 / 4; + byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output + int outBuffPosn = 0; + + byte[] b4 = new byte[4]; + int b4Posn = 0; + int i = 0; + byte sbiCrop = 0; + byte sbiDecode = 0; + for( i = 0; i < len; i++ ) + { + sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits + sbiDecode = DECODABET[ sbiCrop ]; + + if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better + { + if( sbiDecode >= EQUALS_SIGN_ENC ) + { + b4[ b4Posn++ ] = sbiCrop; + if( b4Posn > 3 ) + { + outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn ); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if( sbiCrop == EQUALS_SIGN ) + break; + } // end if: quartet built + + } // end if: equals sign or better + + } // end if: white space, equals sign or better + else + { + System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" ); + return null; + } // end else: + } // each input character + + byte[] out = new byte[ outBuffPosn ]; + System.arraycopy( outBuff, 0, out, 0, outBuffPosn ); + return out; + } // end decode +} // end class Base64 diff --git a/src/jcifs/util/Config.java b/src/jcifs/util/Config.java index 63e358f..cd75b40 100644 --- a/src/jcifs/util/Config.java +++ b/src/jcifs/util/Config.java @@ -1,5 +1,5 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" + * 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 diff --git a/src/jcifs/util/Log.java b/src/jcifs/util/Log.java index 483277c..c672bce 100644 --- a/src/jcifs/util/Log.java +++ b/src/jcifs/util/Log.java @@ -1,6 +1,6 @@ /* jcifs smb client library in Java - * Copyright (C) 2000 "Michael B. Allen" - * "Christopher R. Hertel" + * Copyright (C) 2000 "Michael B. Allen" + * "Christopher R. Hertel" * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,6 +21,7 @@ package jcifs.util; import java.io.Writer; import java.io.OutputStream; +import java.io.PrintStream; import java.util.Properties; /** @@ -91,7 +92,6 @@ import java.util.Properties; * @see jcifs.util.LogWriter * @see jcifs.netbios.Log * @see jcifs.smb.Log - * @since jcifs-0.1 */ public class Log { @@ -147,6 +147,11 @@ public class Log { public static final int EXCEPTIONS = 0x10000001; /** + * Depricated The jCIFS package no longer uses the + * CRITICAL_EXCEPTIONS mask. It was invented to compensate + * for a deficiency in jCIFS that has since been resolved. It will be + * removed in the next release. + *

* Log only critical exceptions. All exceptions logged with * printStackTrace are considered critical. Exceptions are not * critical if they are logged with the NON_CRITICAL_EXCEPTIONS @@ -156,6 +161,11 @@ public class Log { public static final int CRITICAL_EXCEPTIONS = 0x00000001; /** + * Depricated The jCIFS package no longer uses the + * NON_CRITICAL_EXCEPTIONS mask. It was invented to compensate + * for a deficiency in jCIFS that has since been resolved. It will be + * removed in the next release. + *

* Log non-critical exceptions. The EXCEPTIONS mask consists of both critical and non-critical exceptions. */ @@ -184,10 +194,12 @@ public class Log { /** * The shared output stream of all Log classes. The - * defualt is System.out. + * defualt is System.err. + *

+ * This was changed from System.out in jcifs-0.7.0b */ - protected static LogWriter out = new LogWriter( System.out ); + protected static LogWriter out = new LogWriter( System.err ); /** * This is the integer mask that controls what is logged. It is shared @@ -202,9 +214,12 @@ public class Log { /** * Specify an {@link java.io.OutputStream} to be used as the underlying - * stream. + * stream. The default OutputStream is + * System.out. Specify a different stream such as a + * FileOutputStream perhaps to divert all logging + * output to a different stream. * - * @param out the output stream + * @param out the stream to which logging messages are written */ public static void setPrintWriter( OutputStream out ) { @@ -228,7 +243,7 @@ public class Log { /** * Set the mask used to screen all calls to logging methods. The idea * here is that the mask can be specified as an arithmetic expression - * to perovide a crude but effective syslog style way to dictate what it + * to provide a crude but effective syslog style way to dictate what is * logged. For example: *

  *  setMask( Log.EXCEPTIONS +
@@ -286,6 +301,47 @@ public class Log {
 	public static void printHexDump( String desc, byte[] src ) {
 		printHexDump( desc, src, 0, src.length );
 	}
+    public static void printHexDump( PrintStream ps, byte[] src, int srcIndex, int length ) {
+        int s = length % 16;
+        int r = ( s == 0 ) ? length / 16 : length / 16 + 1;
+        char[] c = new char[r * (74 + NL_LENGTH)];
+        char[] d = new char[16];
+        int i;
+        int si = 0;
+        int ci = 0;
+        do {
+            toHexChars( si, c, ci, 5 );
+            ci += 5;
+            c[ci++] = ':';
+            do {
+                if( si == length ) {
+                    int n = 16 - s;
+                    System.arraycopy( spaceChars, 0, c, ci, n * 3 );
+                    ci += n * 3;
+                    System.arraycopy( spaceChars, 0, d, s, n );
+                    break;
+                }
+                c[ci++] = ' ';
+                i = src[srcIndex + si] & 0xFF;
+                toHexChars( i, c, ci, 2 );
+                ci += 2; 
+                if( i < 0 || Character.isISOControl( (char)i )) {
+                    d[si % 16] = '.';
+                } else {
+                    d[si % 16] = (char)i;
+                }
+            } while(( ++si % 16 ) != 0 );
+            c[ci++] = ' ';
+            c[ci++] = ' ';
+            c[ci++] = '|';
+            System.arraycopy( d, 0, c, ci, 16 );
+            ci += 16;
+            c[ci++] = '|';
+            NL.getChars( 0, NL_LENGTH, c, ci );
+            ci += NL_LENGTH;
+        } while( si < length );
+        ps.println( c );
+	}
     public static void printHexDump( String desc, byte[] src, int srcIndex, int length ) {
         if(( HEX_DUMPS & mask ) == 0 || length == 0 ) {
             return;
diff --git a/src/jcifs/util/LogWriter.java b/src/jcifs/util/LogWriter.java
index b495c70..c232b57 100644
--- a/src/jcifs/util/LogWriter.java
+++ b/src/jcifs/util/LogWriter.java
@@ -1,5 +1,5 @@
 /* jcifs smb client library in Java
- * Copyright (C) 2000  "Michael B. Allen" 
+ * 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
@@ -231,8 +231,10 @@ public class LogWriter {
                 out.write( " - " );
                 out.write( desc );
                 out.write( lineSeparator );
-                out.write( s );
-                out.write( lineSeparator );
+				if( s != null ) {
+                	out.write( s );
+                	out.write( lineSeparator );
+				}
                 out.flush();
             }
         } catch( InterruptedIOException x ) {
@@ -257,8 +259,10 @@ public class LogWriter {
                 out.write( " - " );
                 out.write( desc );
                 out.write( lineSeparator );
-                out.write( String.valueOf( o ));
-                out.write( lineSeparator );
+				if (o != null ) {
+                	out.write( String.valueOf( o ));
+                	out.write( lineSeparator );
+				}
                 out.flush();
             }
         } catch( InterruptedIOException x ) {
diff --git a/src/jcifs/util/MimeMap.java b/src/jcifs/util/MimeMap.java
new file mode 100644
index 0000000..3eff0b2
--- /dev/null
+++ b/src/jcifs/util/MimeMap.java
@@ -0,0 +1,123 @@
+/* jcifs smb client library in Java
+ * Copyright (C) 2002  "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.util;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+public class MimeMap {
+
+	static final int IN_SIZE = 7000;
+
+	static final int ST_START = 1;
+	static final int ST_COMM = 2;
+	static final int ST_TYPE = 3;
+	static final int ST_GAP = 4;
+	static final int ST_EXT = 5;
+
+	byte[] in;
+	int inLen;
+
+	public MimeMap() throws IOException {
+		int n;
+
+		in = new byte[IN_SIZE];
+		InputStream is = getClass().getClassLoader().getResourceAsStream( "jcifs/util/mime.map" );
+
+		inLen = 0;
+		while(( n = is.read( in, inLen, IN_SIZE - inLen )) != -1 ) {
+			inLen += n;
+		}
+		if( inLen < 100 || inLen == IN_SIZE ) {
+			throw new IOException( "Error reading jcifs/util/mime.map resource" );
+		}
+		is.close();
+	}
+
+	public String getMimeType( String extension ) throws IOException {
+		return getMimeType( extension, "application/octet-stream" );
+	}
+	public String getMimeType( String extension, String def ) throws IOException {
+		int state, t, x, i, off;
+		byte ch;
+		byte[] type = new byte[128];
+		byte[] buf = new byte[16];
+		byte[] ext = extension.toLowerCase().getBytes( "ASCII" );
+
+		state = ST_START;
+		t = x = i = 0;
+		for( off = 0; off < inLen; off++ ) {
+			ch = in[off];
+			switch( state ) {
+				case ST_START:
+					if( ch == ' ' || ch == '\t' ) {
+						break;
+					} else if( ch == '#' ) {
+						state = ST_COMM;
+						break;
+					}
+					state = ST_TYPE;
+				case ST_TYPE:
+					if( ch == ' ' || ch == '\t' ) {
+						state = ST_GAP;
+					} else {
+						type[t++] = ch;
+					}
+					break;
+				case ST_COMM:
+					if( ch == '\n' ) {
+						t = x = i = 0;
+						state = ST_START;
+					}
+					break;
+				case ST_GAP:
+					if( ch == ' ' || ch == '\t' ) {
+						break;
+					}
+					state = ST_EXT;
+				case ST_EXT:
+					switch( ch ) {
+						case ' ':
+						case '\t':
+						case '\n':
+						case '#':
+							for( i = 0; i < x && x == ext.length && buf[i] == ext[i]; i++ ) {
+								;
+							}
+							if( i == ext.length ) {
+								return new String( type, 0, t, "ASCII" );
+							}
+							if( ch == '#' ) {
+								state = ST_COMM;
+							} else if( ch == '\n' ) {
+								t = x = i = 0;
+								state = ST_START;
+							}
+							x = 0;
+							break;
+						default:
+							buf[x++] = ch;
+					}
+					break;
+			}
+		}
+		return def;
+	}
+}
+
diff --git a/src/jcifs/util/PropertiesTree.java b/src/jcifs/util/PropertiesTree.java
index 481efb0..eb41629 100644
--- a/src/jcifs/util/PropertiesTree.java
+++ b/src/jcifs/util/PropertiesTree.java
@@ -1,5 +1,5 @@
 /* jcifs smb client library in Java
- * Copyright (C) 2000  "Michael B. Allen" 
+ * 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
@@ -95,7 +95,7 @@ import java.util.Date;
  * It might also be thought of as overloading net.username
  * with net.smb.username but only for the smb branch.
  *
- * 

See the More About PropertiesTree and it's File Format for details. + *

See the PropertiesTree document for details. */ public class PropertiesTree extends Properties { @@ -206,7 +206,7 @@ public class PropertiesTree extends Properties { out.write('\n'); out.flush(); } else { - System.out.println( "error: " + key + "=" + value ); + System.err.println( "error: " + key + "=" + value ); } } for( Enumeration e1 = sections.elements(); e1.hasMoreElements(); ) { @@ -319,6 +319,7 @@ public class PropertiesTree extends Properties { } return p.put( s.substring( d + 1 ), value ); } else { + Object x; o = super.get( s ); if( o != null && o instanceof PropertiesTree ) { throw new IllegalArgumentException( "property tree exists: " + s ); @@ -327,7 +328,8 @@ public class PropertiesTree extends Properties { ((PropertiesTree)value).label = (String)key; ((PropertiesTree)value).parent = this; } - return super.put( key, value ); + x = super.put( key, value ); + return x; } } diff --git a/src/jcifs/util/URLDecoder.jav b/src/jcifs/util/URLDecoder.jav new file mode 100644 index 0000000..3c4e719 --- /dev/null +++ b/src/jcifs/util/URLDecoder.jav @@ -0,0 +1,81 @@ +/* + * @(#)URLDecoder.java 1.9 00/02/02 + * + * Copyright 1998-2000 Sun Microsystems, Inc. All Rights Reserved. + * + * This software is the proprietary information of Sun Microsystems, Inc. + * Use is subject to license terms. + * + */ + +package jcifs.util; + +import java.io.*; + +/** + * The class contains a utility method for converting from + * a MIME format called "x-www-form-urlencoded" + * to a String + *

+ * To convert to a String, each character is examined in turn: + *

    + *
  • The ASCII characters 'a' through 'z', + * 'A' through 'Z', and '0' + * through '9' remain the same. + *
  • The plus sign '+'is converted into a + * space character ' '. + *
  • The remaining characters are represented by 3-character + * strings which begin with the percent sign, + * "%xy", where xy is the two-digit + * hexadecimal representation of the lower 8-bits of the character. + *
+ * + * @author Mark Chamness + * @author Michael McCloskey + * @version 1.9, 02/02/00 + * @since 1.2 + */ + +public class URLDecoder { + +/** + * Decodes a "x-www-form-urlencoded" + * to a String. + * @param s the String to decode + * @return the newly decoded String + */ + public static String decode(String s) { + StringBuffer sb = new StringBuffer(); + for(int i=0; i