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