+Thu Oct 23 01:18:29 EDT 2003
+
+jcifs-0.7.15 released
+
+The name service code has been modified to return a different response with
+each 0x1C domain controller query. The range of servers is limited to the
+top jcifs.netbios.lookupRespLimit entries in the NetBIOS response. The
+effect that this will have is that the NtlmHttpFilter and NtlmServlet will
+rotate through domain controllers when authenticating WWW clients. Also,
+because different transports are used, fewer sessions will be multiplexed
+over each resulting in an increase in scalability proportional to the
+number of domain controllers used. This behavior can be turned off by
+setting the jcifs.http.loadBalance property to false (the default is true).
+
+The jcifs.smb.client.ssnLimit property default value has been changed to
+250 from 100.
+
+Mon Oct 6 23:53:28 EDT 2003
+
+jcifs-0.7.14 released
+
+Eric's LMv2 patch has been merged. There is some uncertainty surrounding
+the signing of SMBs if GUEST credentials are negotiated. On a related note;
+the "Concurrent modification" issue has been resolved. The oversight with
+this one was that it was believed that only a thead calling into the
+transport should ever trigger tryClose() which is not exactly true. The
+transport thread can call tryClose but prior to adding verify() calls it
+was rare and only happend when the transport reached a state where no
+further operations could move forward anyway. So rather than syncronize
+tryClose, I have changed verify to simply return a boolean value which
+set's the new ServerMessageBlock.verifyFailed member. This is then examined
+by the calling thread who will tryClose (with the transport locked) and
+throw the "Unverifyable signature" if verifyFailed. Finally there has been
+a straight forward but potentially dangerous change in SmbFile. All list
+operations now build a list of names or files using an ArrayList. This
+assisted in fixing another problem where NetServerEnum2 responses were
+observed to return server names of 0 length. This caused
+ArrayIndexOutOfBounds exceptions. These entries are now ignored.
+
Wed Sep 17 21:21:31 EDT 2003
JCIFS now supports SMB signing. If a server requires SMB signing (Windows
+Thu Oct 23 01:18:29 EDT 2003
+
+jcifs-0.7.15 released
+
+The NTLM HTTP Authentication behavoir has been modified to permit load
+balancing between many domain controllers. The jcifs.smb.client.ssnLimit
+property default value has also been changed to 250 from 100.
+
+Mon Oct 6 23:53:28 EDT 2003
+
+jcifs-0.7.14 released
+
+Eric's latest signing patch has been merged, a few adjustments have been
+made to eliminate a concurrency issue, and a fix for browse servers that
+return zero length server names has been incorporated.
+
Wed Sep 17 21:21:31 EDT 2003
SMB signing is now supported and there have been some adjustments to
<target name="jar" depends="smb">
<copy file="src/jcifs/util/mime.map" tofile="build/jcifs/util/mime.map" overwrite="yes"/>
<copy file="src/jcifs/http/ne.css" tofile="build/jcifs/http/ne.css" overwrite="yes"/>
- <jar jarfile="jcifs-0.7.13.jar" basedir="build"/>
+ <jar jarfile="jcifs-0.7.15.jar" basedir="build"/>
</target>
<target name="tgz">
- <copy todir="dist_tmp/jcifs_0.7.13">
+ <copy todir="dist_tmp/jcifs_0.7.15">
<fileset dir="." excludes="ant,**/.*,build,jcifs.prp,**/*.tgz,**/*.zip"/>
</copy>
- <tar tarfile="jcifs-0.7.13.tar" basedir="dist_tmp"/>
- <gzip src="jcifs-0.7.13.tar" zipfile="jcifs-0.7.13.tgz"/>
- <delete file="jcifs-0.7.13.tar"/>
+ <tar tarfile="jcifs-0.7.15.tar" basedir="dist_tmp"/>
+ <gzip src="jcifs-0.7.15.tar" zipfile="jcifs-0.7.15.tgz"/>
+ <delete file="jcifs-0.7.15.tar"/>
<delete dir="dist_tmp"/>
</target>
<target name="zip">
- <copy todir="dist_tmp/jcifs_0.7.13">
+ <copy todir="dist_tmp/jcifs_0.7.15">
<fileset dir="." excludes="ant,**/.*,build,jcifs.prp,**/*.tgz,**/*.zip"/>
</copy>
<fixcrlf srcdir="dist_tmp" cr="add" tab="remove" tablength="4" excludes="**/*.jar,**/*.exe"/>
- <zip zipfile="jcifs-0.7.13.zip" basedir="dist_tmp"/>
+ <zip zipfile="jcifs-0.7.15.zip" basedir="dist_tmp"/>
<delete dir="dist_tmp"/>
</target>
--- /dev/null
+import jcifs.netbios.NbtAddress;
+import jcifs.smb.*;
+import jcifs.util.Log;
+import java.util.Date;
+
+public class VerifyGuest {
+
+ public static void list( SmbFile dir ) {
+ try {
+ long t1 = System.currentTimeMillis();
+ SmbFile[] files = dir.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" );
+ } catch( Exception e ) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void main( String[] argv ) throws Exception {
+ list( new SmbFile( "smb://miallen2/" ));
+ list( new SmbFile( "smb://miallen2/pub/", new NtlmPasswordAuthentication( "dom", "user", "pass" )));
+ }
+}
Object addr;
String calledName;
- UniAddress( Object addr ) {
+ /**
+ * Wrap an <tt>InetAddress</tt> or <tt>NbtAddress</tt>.
+ */
+ public UniAddress( Object addr ) {
+ if( addr == null ) {
+ throw new IllegalArgumentException();
+ }
this.addr = addr;
}
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbAuthException;
import jcifs.util.Base64;
+import jcifs.netbios.NbtAddress;
/**
* This servlet Filter can be used to negotiate password hashes with
private String domainController;
+ private boolean loadBalance;
+
private boolean enableBasic;
private boolean insecureBasic;
}
defaultDomain = Config.getProperty("jcifs.smb.client.domain");
domainController = Config.getProperty( "jcifs.http.domainController" );
- if( domainController == null ) domainController = defaultDomain;
+ if( domainController == null ) {
+ domainController = defaultDomain;
+ loadBalance = Config.getBoolean( "jcifs.http.loadBalance", true );
+ }
enableBasic = Boolean.valueOf(
Config.getProperty("jcifs.http.enableBasic")).booleanValue();
insecureBasic = Boolean.valueOf(
if( msg != null && (msg.startsWith( "NTLM " ) ||
(offerBasic && msg.startsWith("Basic ")))) {
- dc = UniAddress.getByName( domainController, true );
+ if( loadBalance ) {
+ dc = new UniAddress( NbtAddress.getByName( domainController, 0x1C, null ));
+ } else {
+ dc = UniAddress.getByName( domainController, true );
+ }
if (msg.startsWith("NTLM ")) {
byte[] challenge = SmbSession.getChallenge( dc );
if(( ntlm = NtlmSsp.authenticate( req, resp, challenge )) == null ) {
import jcifs.util.Base64;
+import jcifs.netbios.NbtAddress;
+
/**
* This servlet may be used with pre-2.3 servlet containers
* to protect content with NTLM HTTP Authentication. Servlets that
private String domainController;
+ private boolean loadBalance;
+
private boolean enableBasic;
private boolean insecureBasic;
}
defaultDomain = Config.getProperty("jcifs.smb.client.domain");
domainController = Config.getProperty("jcifs.http.domainController");
- if (domainController == null) domainController = defaultDomain;
+ if( domainController == null ) {
+ domainController = defaultDomain;
+ loadBalance = Config.getBoolean( "jcifs.http.loadBalance", true );
+ }
enableBasic = Boolean.valueOf(
Config.getProperty("jcifs.http.enableBasic")).booleanValue();
insecureBasic = Boolean.valueOf(
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
+ UniAddress dc;
boolean offerBasic = enableBasic &&
(insecureBasic || request.isSecure());
String msg = request.getHeader("Authorization");
if (msg != null && (msg.startsWith("NTLM ") ||
(offerBasic && msg.startsWith("Basic ")))) {
- UniAddress dc = UniAddress.getByName(domainController, true);
+ if( loadBalance ) {
+ dc = new UniAddress( NbtAddress.getByName( domainController, 0x1C, null ));
+ } else {
+ dc = UniAddress.getByName( domainController, true );
+ }
NtlmPasswordAuthentication ntlm;
if (msg.startsWith("NTLM ")) {
byte[] challenge = SmbSession.getChallenge(dc);
static final int AUTHORITY_OFFSET = 8;
static final int ADDITIONAL_OFFSET = 10;
+ static final int LOOKUP_RESP_LIMIT = jcifs.Config.getInt( "jcifs.netbios.lookupRespLimit", 5 );
+
+ static int addrIndex = 0;
+
static void writeInt2( int val, byte[] dst, int dstIndex ) {
dst[dstIndex++] = (byte)(( val >> 8 ) & 0xFF );
dst[dstIndex] = (byte)( val & 0xFF );
}
int readResourceRecordWireFormat( byte[] src, int srcIndex ) {
int start = srcIndex;
+ int end;
+
if(( src[srcIndex] & 0xC0 ) == 0xC0 ) {
recordName = questionName; // label string pointer to questionName
srcIndex += 2;
srcIndex += 4;
rDataLength = readInt2( src, srcIndex );
srcIndex += 2;
- readRDataWireFormat( src, srcIndex );
- srcIndex += rDataLength;
+
+ end = srcIndex + rDataLength;
+ for( int i = 0; srcIndex < end; i++ ) {
+ srcIndex += readRDataWireFormat( src, srcIndex );
+ if( i == addrIndex ) {
+ addrIndex++;
+ if( addrIndex == LOOKUP_RESP_LIMIT ) {
+ addrIndex = 0;
+ }
+ return end - start;
+ }
+ }
+ addrIndex = 0;
+
return srcIndex - start;
}
boolean useUnicode, received;
long responseTimeout = 1;
int verifySequence;
+ boolean verifyFailed;
ServerMessageBlock() {
flags = (byte)( FLAGS_PATH_NAMES_CASELESS | FLAGS_PATH_NAMES_CANONICALIZED );
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.ArrayList;
import jcifs.util.Config;
import jcifs.UniAddress;
import jcifs.netbios.NbtAddress;
*/
public String[] list() throws SmbException {
+ ArrayList list = new ArrayList();
connect0();
response.status, response.toString() );
}
- String[] ret = new String[response.entriesReturned];
for( int i = 0; i < response.entriesReturned; i++ ) {
- ret[i] = response.results[i].name;
+ if( response.results[i].name.length() > 0 ) {
+ list.add( response.results[i].name );
+ }
}
- return ret;
+ return (String[])list.toArray( new String[list.size()] );
} else if( share == null ) {
if( getType() == TYPE_WORKGROUP ) {
NetServerEnum2Response response = new NetServerEnum2Response();
throw new SmbException( SmbException.ERRRAP, response.status );
}
- String[] ret = new String[response.entriesReturned];
for( int i = 0; i < response.entriesReturned; i++ ) {
- ret[i] = response.results[i].name;
+ if( response.results[i].name.length() > 0 ) {
+ list.add( response.results[i].name );
+ }
}
- return ret;
+ return (String[])list.toArray( new String[list.size()] );
} else {
NetShareEnumResponse response = new NetShareEnumResponse();
sendTransaction( new NetShareEnum(), response );
throw new SmbException( SmbException.ERRRAP, response.status );
}
- String[] ret = new String[response.entriesReturned];
for( int i = 0; i < response.entriesReturned; i++ ) {
- ret[i] = response.results[i].netName;
+ list.add( response.results[i].netName );
}
- return ret;
+ return (String[])list.toArray( new String[list.size()] );
}
} else {
return list( unc );
}
}
String[] list( String dirPath ) throws SmbException {
- int sid, count, i, j;
- String[] results;
+ int sid, count, i;
String filename;
+ ArrayList list = new ArrayList();
Log.println( Log.WARNINGS, "smb find warning",
" find with path=" + dirPath );
sid = response.sid;
count = response.searchCount;
- j = 0;
-
- results = new String[Math.max( 16, count )];
int h1 = new String( "." ).hashCode();
int h2 = new String( ".." ).hashCode();
- i = 0;
- while( j < count ) {
- filename = response.results[i++].filename;
+
+ for( i = 0; i < count; i++ ) {
+ filename = response.results[i].filename;
if( filename.length() < 3 ) {
int h = filename.hashCode();
if( h == h1 || h == h2 ) {
- count--;
continue;
}
}
- results[j++] = filename;
+ list.add( filename );
}
/* only difference between first2 and next2
response.reset();
sendTransaction( new Trans2FindNext2( sid, response.resumeKey,
response.lastName ), response );
- count += response.searchCount;
+ count = response.searchCount;
- if( count > results.length ) {
- String[] tmp = results;
- results = new String[Math.max( results.length * 2, count )];
- System.arraycopy( tmp, 0, results, 0, j );
- }
- i = 0;
- while( j < count ) {
- filename = response.results[i++].filename;
+ for( i = 0; i < count; i++ ) {
+ filename = response.results[i].filename;
if( filename.length() < 3 ) {
int h = filename.hashCode();
if( h == h1 || h == h2 ) {
- count--;
continue;
}
}
- results[j++] = filename;
+ list.add( filename );
}
}
send( new SmbComFindClose2( sid ), blank_resp );
- if( results.length != count ) {
- String[] tmp = results;
- results = new String[count];
- System.arraycopy( tmp, 0, results, 0, count );
- }
-
- return results;
+ return (String[])list.toArray( new String[list.size()] );
}
/**
*/
public SmbFile[] listFiles( String wildcard ) throws SmbException {
+ ArrayList list = new ArrayList();
+
if( url.toString().lastIndexOf( '/' ) != ( url.toString().length() - 1 )) {
throw new SmbException( SmbException.ERRCLI,
SmbException.ERRlistFiles, url.toString() + " directory must end with '/'" );
response.status, response.toString() );
}
- SmbFile[] ret = new SmbFile[response.entriesReturned];
for( int i = 0; i < response.entriesReturned; i++ ) {
- ret[i] = new SmbFile( this,
+ if( response.results[i].name.length() > 0 ) {
+ list.add( new SmbFile( this,
response.results[i].name,
TYPE_WORKGROUP,
ATTR_READONLY | ATTR_DIRECTORY,
0L,
- 0L );
+ 0L ));
+ }
}
//System.err.println( "ret=" + ret.length + ",ret[0]=" + ret[0] + ",name=" + response.results[0].name );
- return ret;
+ return (SmbFile[])list.toArray(new SmbFile[list.size()]);
} else if( share == null ) {
if( getType() == TYPE_WORKGROUP ) {
NetServerEnum2Response response = new NetServerEnum2Response();
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,
+ if( response.results[i].name.length() > 0 ) {
+ list.add( new SmbFile( this,
response.results[i].name,
TYPE_SERVER,
ATTR_READONLY | ATTR_DIRECTORY,
0L,
- 0L );
+ 0L ));
+ }
}
- return ret;
+ return (SmbFile[])list.toArray(new SmbFile[list.size()]);
} else {
NetShareEnumResponse response = new NetShareEnumResponse();
sendTransaction( new NetShareEnum(), response );
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 ) {
shareType = TYPE_SHARE;
break;
}
- ret[i] = new SmbFile( this,
+ list.add( new SmbFile( this,
response.results[i].netName,
shareType,
ATTR_READONLY | ATTR_DIRECTORY,
0L,
- 0L );
+ 0L ));
}
- return ret;
+ return (SmbFile[])list.toArray(new SmbFile[list.size()]);
}
} else {
return listFiles( getUncPath0(), wildcard );
}
}
SmbFile[] listFiles( String dirPath, String wildcard ) throws SmbException {
- int sid, count, i, j;
- SmbFile[] results;
+ int sid, count, i;
String base, filename;
+ ArrayList list = new ArrayList();
Log.println( Log.WARNINGS, "smb find warning",
" find with path=" + dirPath );
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 ) {
+ for( i = 0; i < count; i++ ) {
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,
+ list.add( new SmbFile( this,
filename,
TYPE_FILESYSTEM,
response.results[i].extFileAttributes,
response.results[i].lastWriteTime,
- response.results[i].endOfFile );
- i++;
+ response.results[i].endOfFile ));
}
-
+
/* 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 ) {
response.reset();
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 ) {
+ count = response.searchCount;
+
+ for( i = 0; i < count; i++ ) {
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,
+ list.add( new SmbFile( this,
filename,
TYPE_FILESYSTEM,
response.results[i].extFileAttributes,
response.results[i].lastWriteTime,
- response.results[i].endOfFile );
- i++;
+ response.results[i].endOfFile ));
}
}
} catch( UnknownHostException uhe ) {
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;
+ return (SmbFile[])list.toArray(new SmbFile[list.size()]);
}
/**
* Changes the name of the file this <code>SmbFile</code> represents to the name
transport.negotiate();
- if( transport.useSigning && transport.macSigningKey == null ) {
- /* The first SMB_COM_SESSION_SETUP_ANX
- * generates the signing key */
+ if( transport.useSigning && transport.macSigningKey == null &&
+ NtlmPasswordAuthentication.NULL != auth &&
+ NtlmPasswordAuthentication.NULL.equals( auth ) == false ) {
+ // NtlmPasswordAuthentication.GUEST.equals( auth ) == false ) {
+ /* The first SMB_COM_SESSION_SETUP_ANX with creds other than
+ * null or guest generates the signing key */
transport.initSigning( auth );
}
/* jcifs smb client library in Java
* Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
+ * "Eric Glass" <jcifs at samba dot org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
import java.security.MessageDigest;
+import java.util.Arrays;
import java.util.Vector;
import java.util.LinkedList;
import java.util.ListIterator;
class SmbTransport implements Runnable {
+ private static final byte[] LMV2_CROSSDOMAIN_KEY = new byte[16];
+
private static final int DEFAULT_MAX_MPX_COUNT = 10;
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_SO_TIMEOUT = 15000;
+ private static final int PUSHBACK_BUF_SIZE = 64;
private static final int DEFAULT_RCV_BUF_SIZE = 60416;
private static final int DEFAULT_SND_BUF_SIZE = 5000;
- private static final int DEFAULT_SSN_LIMIT = 100;
+ private static final int DEFAULT_SSN_LIMIT = 250;
private static final int LM_COMPATIBILITY =
Config.getInt("jcifs.smb.lmCompatibility", 0);
- static final int MID_OFFSET = 30;
+ static final int MID_OFFSET = 30;
static final int HEADER_LENGTH = 32;
- static final int FLAGS_OFFSET = 9;
+ static final int FLAGS_OFFSET = 9;
static final int FLAGS_RESPONSE = 0x80;
private NbtSocket socket; // should become UniSocket?
private Thread thread;
private Object outLock;
- private MessageDigest signingDigest;
+ private MessageDigest signingDigest;
private static Vector connections = new Vector();
private static MpxControl mpxCtrl = new MpxControl();
UniAddress address;
- byte[] macSigningKey;
- int signSequence;
+ byte[] macSigningKey;
+ int signSequence;
int port, rcv_buf_size, snd_buf_size;
}
useSigning = Config.getBoolean("jcifs.smb.client.signingPreferred", false);
if( useSigning ) {
- client.flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
+ client.flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
}
soTimeout = Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT );
if( response.errorCode != 0 || e.hasMoreElements() == false ) {
((SmbComTransactionResponse)response).hasMore = false;
if( useSigning ) {
- verify(rcv_buf, 0, response.length, response.verifySequence);
+ response.verifyFailed = verify(rcv_buf, 0, response.length, response.verifySequence);
}
response.notify();
} else {
}
Log.printHexDump( "smb received", rcv_buf, 0, response.length );
if( useSigning ) {
- verify(rcv_buf, 0, response.length, response.verifySequence);
+ response.verifyFailed = verify(rcv_buf, 0, response.length, response.verifySequence);
}
response.notify();
responseTable.size() + " pending requests" );
}
} catch( IOException ioe ) {
- tryClose( true );
+ synchronized( this ) {
+ tryClose( true );
+ }
Log.printStackTrace( "exception reading from socket input: " + address, ioe );
}
}
}
- void initSigning(NtlmPasswordAuthentication auth) throws SmbException {
+ void initSigning(NtlmPasswordAuthentication auth) throws SmbException {
if( auth.hashesExternal ) {
if( server.signaturesRequired ) {
throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe,
case 3:
case 4:
case 5:
- // NTLMv2 will have a key; LMv2 doesn't (just uses an
- // empty user session key). So if/when we start doing
- // NTLMv2, this will change.
macSigningKey = new byte[16];
+ try {
+ auth.getUserSessionKey(server.encryptionKey, macSigningKey, 0);
+ } catch (Exception ex) {
+ Log.printStackTrace("Unable to calculate MAC signing key.", ex);
+ macSigningKey = null;
+ }
break;
default:
macSigningKey = new byte[40];
}
}
- /**
- * Performs MAC signing of the SMB. This is done as follows.
- * The signature field of the SMB is overwritted with the sequence number;
- * The MD5 digest of the MAC signing key + the entire SMB is taken;
- * The first 8 bytes of this are placed in the signature field.
- *
- * @param data The data.
- * @param offset The starting offset at which the SMB header begins.
- * @param length The length of the SMB data starting at offset.
- */
- private void sign(byte[] data, int offset, int length) {
+ /**
+ * Performs MAC signing of the SMB. This is done as follows.
+ * The signature field of the SMB is overwritted with the sequence number;
+ * The MD5 digest of the MAC signing key + the entire SMB is taken;
+ * The first 8 bytes of this are placed in the signature field.
+ *
+ * @param data The data.
+ * @param offset The starting offset at which the SMB header begins.
+ * @param length The length of the SMB data starting at offset.
+ */
+ private void sign(byte[] data, int offset, int length) {
if (macSigningKey == null) return;
try {
signingDigest.update(macSigningKey);
} finally {
signSequence += 2;
}
- }
-
- /**
- * Performs MAC signature verification. This calculates the signature
- * of the SMB and compares it to the signature field on the SMB itself.
- *
- * @param data The data.
- * @param offset The starting offset at which the SMB header begins.
- * @param length The length of the SMB data starting at offset.
- */
- private void verify(byte[] data, int offset, int length, int verifySequence) throws IOException {
- if (macSigningKey == null) return;
+ }
+
+ /**
+ * Performs MAC signature verification. This calculates the signature
+ * of the SMB and compares it to the signature field on the SMB itself.
+ *
+ * @param data The data.
+ * @param offset The starting offset at which the SMB header begins.
+ * @param length The length of the SMB data starting at offset.
+ */
+ private boolean verify(byte[] data, int offset, int length, int verifySequence) throws IOException {
+ if (macSigningKey == null) return false;
signingDigest.update(macSigningKey);
int index = offset;
signingDigest.update(data, index, ServerMessageBlock.SIGNATURE_OFFSET);
byte[] signature = signingDigest.digest();
for (int i = 0; i < 8; i++) {
if (signature[i] != data[offset + ServerMessageBlock.SIGNATURE_OFFSET + i]) {
- throw new IOException("Unverifiable signature.");
+ // can this just use == ?
+ if (Arrays.equals(LMV2_CROSSDOMAIN_KEY, macSigningKey)) return true;
+ signingDigest.update(LMV2_CROSSDOMAIN_KEY);
+ index = offset;
+ signingDigest.update(data, index, ServerMessageBlock.SIGNATURE_OFFSET);
+ index += ServerMessageBlock.SIGNATURE_OFFSET;
+ ServerMessageBlock.writeInt4(verifySequence, sequence, 0);
+ signingDigest.update(sequence);
+ index += 8;
+ signingDigest.update(data, index, length - ServerMessageBlock.SIGNATURE_OFFSET - 8);
+ signature = signingDigest.digest();
+ for (i = 0; i < 8; i++) {
+ if (signature[i] != data[offset + ServerMessageBlock.SIGNATURE_OFFSET + i]) {
+ return true;
+ }
+ }
+ // verified using LMv2 cross-domain MAC key; start using that.
+ macSigningKey = LMV2_CROSSDOMAIN_KEY;
+ break;
}
}
- }
+
+ return false;
+ }
void send( ServerMessageBlock request,
ServerMessageBlock response ) throws SmbException {
synchronized( outLock ) {
ensureOpen();
synchronized( snd_buf ) {
- int length = request.writeWireFormat(snd_buf, 0);
- if( useSigning ) {
- sign(snd_buf, 0, length);
- }
- out.write(snd_buf, 0, length);
+ int length = request.writeWireFormat(snd_buf, 0);
+ if( useSigning ) {
+ sign(snd_buf, 0, length);
+ }
+ out.write(snd_buf, 0, length);
out.flush();
Log.printMessageData( "smb sent", request );
synchronized( outLock ) {
ensureOpen();
synchronized( snd_buf ) {
- int length = request.writeWireFormat(snd_buf, 0);
- if( useSigning ) {
+ int length = request.writeWireFormat(snd_buf, 0);
+ if( useSigning ) {
response.verifySequence = signSequence + 1;
sign(snd_buf, 0, length);
- }
- out.write(snd_buf, 0, length);
+ }
+ out.write(snd_buf, 0, length);
out.flush();
Log.printMessageData( "smb sent", request );
throw new SmbException( SmbException.ERRCLI,
SmbException.ERRserverTimeout,
address );
+ } else if( response.verifyFailed ) {
+ tryClose( true );
+ throw new SmbException( SmbException.ERRCLI,
+ SmbException.ERRioe,
+ "Unverifiable signature." );
}
switch( response.errorCode & 0xFF ) {
case SmbException.SUCCESS:
synchronized( outLock ) {
ensureOpen();
synchronized(snd_buf) {
- int length = request.writeWireFormat(snd_buf, 0);
- if( useSigning ) {
+ int length = request.writeWireFormat(snd_buf, 0);
+ if( useSigning ) {
response.verifySequence = signSequence + 1;
- sign(snd_buf, 0, length);
- }
- out.write(snd_buf, 0, length);
+ sign(snd_buf, 0, length);
+ }
+ out.write(snd_buf, 0, length);
out.flush();
Log.printMessageData( "smb sent", request );
synchronized( outLock ) {
ensureOpen();
synchronized( snd_buf ) {
- int length = request.writeWireFormat(snd_buf, 0);
- if( useSigning ) {
+ int length = request.writeWireFormat(snd_buf, 0);
+ if( useSigning ) {
response.verifySequence = signSequence + 1;
- sign(snd_buf, 0, length);
- }
- out.write(snd_buf, 0, length);
+ sign(snd_buf, 0, length);
+ }
+ out.write(snd_buf, 0, length);
out.flush();
Log.printMessageData( "smb sent", request );
throw new SmbException( SmbException.ERRCLI,
SmbException.ERRserverTimeout,
address );
+ } else if( response.verifyFailed ) {
+ tryClose( true );
+ throw new SmbException( SmbException.ERRCLI,
+ SmbException.ERRioe,
+ "Unverifiable signature." );
}
switch( response.errorCode & 0xFF ) {
case SmbException.SUCCESS:
* Negotiate Protocol Request / Response
*/
- // reset MAC signing
- macSigningKey = null;
+ // reset MAC signing
+ macSigningKey = null;
SmbComNegotiateResponse response = new SmbComNegotiateResponse();
send( new SmbComNegotiate(), response );
throw new SmbException( SmbException.ERRCLI, SmbException.ERRbadDialect );
}
- server.securityMode = response.securityMode;
- server.security = response.security;
+ server.securityMode = response.securityMode;
+ server.security = response.security;
server.encryptedPasswords = response.encryptedPasswords;
server.signaturesEnabled = response.signaturesEnabled;
server.signaturesRequired = response.signaturesRequired;
- if (server.signaturesRequired || (server.signaturesEnabled && useSigning)) {
+ if (server.signaturesRequired || (server.signaturesEnabled && useSigning)) {
useSigning = true;
- client.flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
+ client.flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
if (signingDigest == null) {
try {
return;
}
}
- } else {
+ } else {
useSigning = false;
- client.flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
+ client.flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
}
- negotiatedDialectIndex = response.dialectIndex;;
- server.maxMpxCount = response.maxMpxCount;
- negotiatedMaxMpxCount = client.maxMpxCount < server.maxMpxCount ?
+ negotiatedDialectIndex = response.dialectIndex;;
+ server.maxMpxCount = response.maxMpxCount;
+ negotiatedMaxMpxCount = client.maxMpxCount < server.maxMpxCount ?
client.maxMpxCount : server.maxMpxCount;
- mpxCtrl.maxMpxCount = negotiatedMaxMpxCount < 1 ?
+ mpxCtrl.maxMpxCount = negotiatedMaxMpxCount < 1 ?
1 : negotiatedMaxMpxCount;
- server.maxNumberVcs = response.maxNumberVcs;
- server.maxBufferSize = response.maxBufferSize;
- negotiatedMaxBufferSize = client.maxBufferSize < server.maxBufferSize ?
+ server.maxNumberVcs = response.maxNumberVcs;
+ server.maxBufferSize = response.maxBufferSize;
+ negotiatedMaxBufferSize = client.maxBufferSize < server.maxBufferSize ?
client.maxBufferSize : server.maxBufferSize;
- server.maxRawSize = response.maxRawSize;
- server.sessionKey = response.sessionKey;
- server.capabilities = response.capabilities;
- negotiatedCapabilities = client.capabilities & server.capabilities;
+ server.maxRawSize = response.maxRawSize;
+ server.sessionKey = response.sessionKey;
+ server.capabilities = response.capabilities;
+ negotiatedCapabilities = client.capabilities & server.capabilities;
if(( negotiatedCapabilities & ServerMessageBlock.CAP_UNICODE ) == 0 ) {
// server doesn't want unicode
if( Config.getBoolean( "jcifs.smb.client.useUnicode", false )) {
client.flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
}
}
- server.serverTime = response.serverTime;
- server.serverTimeZone = response.serverTimeZone;
+ server.serverTime = response.serverTime;
+ server.serverTimeZone = response.serverTimeZone;
server.encryptionKeyLength = response.encryptionKeyLength;
- server.encryptionKey = response.encryptionKey;
- server.oemDomainName = response.oemDomainName;
+ server.encryptionKey = response.encryptionKey;
+ server.oemDomainName = response.oemDomainName;
}
public String toString() {
String ret = "SmbTransport[address=" + address;
mpxCtrl.releaseMid( mid );
}
- static class MpxControl {
+ static class MpxControl {
MpxListNode first, last;
- class MpxListNode {
- int i;
- MpxListNode next;
+ class MpxListNode {
+ int i;
+ MpxListNode next;
MpxListNode( int id ) {
i = id;
next = null;
}
- }
+ }
int nextMid, mpxCount, maxMpxCount;
MpxControl() {
mpxCount--;
notify();
}
- synchronized boolean contains( int i ) {
+ synchronized boolean contains( int i ) {
for( MpxListNode tmp = first; tmp != null; tmp = tmp.next ) {
if( tmp.i == i ) {
return true;
}
}
return false;
- }
- synchronized void add( int i ) {
+ }
+ synchronized void add( int i ) {
if( contains( i )) {
return;
}
} else {
last = last.next = new MpxListNode( i );
}
- }
- synchronized void remove( int i ) {
+ }
+ synchronized void remove( int i ) {
if( first == null ) {
return;
} else if( first == last && first.i == i ) {
}
prev = tmp;
}
- }
- }
+ }
+ }
}
+++ /dev/null
-/* jcifs smb client library in Java
- * Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-package jcifs.smb;
-
-import jcifs.netbios.NbtSocket;
-import jcifs.netbios.NbtException;
-import jcifs.netbios.NbtAddress;
-import jcifs.UniAddress;
-import jcifs.Config;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PushbackInputStream;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Vector;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.Enumeration;
-import java.util.Hashtable;
-
-class SmbTransport implements Runnable {
-
- private static final int DEFAULT_MAX_MPX_COUNT = 10;
- 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 = 60416;
- private static final int DEFAULT_SND_BUF_SIZE = 5000;
- private static final int DEFAULT_SSN_LIMIT = 100;
-
- 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 NbtSocket socket; // should become UniSocket?
- private InputStream in;
- private OutputStream out;
- private int localPort, soTimeout, responseTimeout;
- private long closeTime;
- private InetAddress localAddr;
- private Hashtable responseTable;
- private Thread thread;
- private Object outLock;
-
- 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];
-
- LinkedList sessions;
- boolean negotiated, useUnicode;
-
- UniAddress address;
- int port, rcv_buf_size, snd_buf_size;
-
- int negotiatedDialectIndex;
- int negotiatedMaxMpxCount;
- int negotiatedMaxBufferSize;
- int negotiatedCapabilities;
-
- int ssnLimit = Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT );
-
- ClientProperties client = new ClientProperties();
- ServerProperties server = new ServerProperties();
-
- class ClientProperties {
- int maxMpxCount = Config.getInt( "jcifs.smb.client.maxMpxCount",
- DEFAULT_MAX_MPX_COUNT );
- int maxBufferSize = Config.getInt( "jcifs.smb.client.snd_buf_size",
- DEFAULT_SND_BUF_SIZE );
- int sessionKey = 0x00000000;
- /* NT 4 Workstation client capabilities 0x00D4
- * we don't do NT Status Codes or Level II oplocks
- * but we could do raw and mpx
- */
- int flags2 = Config.getInt( "jcifs.smb.client.flags2",
- ServerMessageBlock.FLAGS2_LONG_FILENAMES |
- ServerMessageBlock.FLAGS2_UNICODE );
- int capabilities = Config.getInt( "jcifs.smb.client.capabilities",
- 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", "jCIFS" );
- int vcNumber = 1;
- }
- class ServerProperties {
- String tconHostName;
-
- byte flags;
- int flags2;
- int maxMpxCount;
- int maxBufferSize;
- int sessionKey;
- // NT 4 Workstation is 0x43FD
- int capabilities;
- String oemDomainName;
- String primaryDomain;
- String nativeOs;
- String nativeLanMan;
-
- int securityMode;
- int security;
- boolean encryptedPasswords;
- boolean signaturesEnabled;
- boolean signaturesRequired;
- int maxNumberVcs;
- int maxRawSize;
- long serverTime;
- int serverTimeZone;
- int encryptionKeyLength;
- byte[] encryptionKey;
- }
-
- static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
- return getSmbTransport( address, port,
- Config.getInetAddress( "jcifs.smb.client.laddr", null ),
- Config.getInt( "jcifs.smb.client.lport", 0 ));
- }
- static synchronized SmbTransport getSmbTransport( UniAddress address, int port,
- InetAddress localAddr, int localPort ) {
- SmbTransport conn;
- for( Enumeration e = connections.elements(); e.hasMoreElements(); ) {
- conn = (SmbTransport)e.nextElement();
- if( conn.matches( address, port, localAddr, localPort )) {
- return conn;
- }
- }
-
- conn = new SmbTransport( address, port, localAddr, localPort );
- connections.addElement( conn );
- return conn;
- }
-
- SmbTransport( UniAddress address, int port, InetAddress localAddr, int localPort ) {
- this.address = address;
- this.port = port;
- this.localAddr = localAddr;
- this.localPort = localPort;
-
- useUnicode = Config.getBoolean( "jcifs.smb.client.useUnicode", true );
- if( useUnicode == false ) {
- client.flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
- client.capabilities &= 0xFFFF ^ ServerMessageBlock.CAP_UNICODE;
- }
- if( Config.getBoolean( "jcifs.smb.client.useNTSmbs", false ) == true ) {
- client.capabilities |= ServerMessageBlock.CAP_NT_SMBS;
- }
-
- soTimeout = Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_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 LinkedList();
- responseTable = new Hashtable();
- outLock = new Object();
- negotiated = false;
- }
-
- synchronized SmbSession getSmbSession() {
- return getSmbSession( new NtlmPasswordAuthentication( null, null, null ));
- }
- synchronized SmbSession getSmbSession( NtlmPasswordAuthentication auth ) {
- SmbSession ssn;
-
- ListIterator iter = sessions.listIterator();
- while( iter.hasNext() ) {
- ssn = (SmbSession)iter.next();
- if( ssn.matches( auth )) {
- ssn.auth = auth;
- return ssn;
- }
- }
- ssn = new SmbSession( this, auth );
- sessions.add( ssn );
-
- if( sessions.size() > ssnLimit ) {
- int nclose = sessions.size() / 10;
- SmbSession s;
-
- while( nclose-- > 0 ) {
- s = (SmbSession)sessions.removeFirst();
- s.logoff( false );
- }
- }
-
- return ssn;
- }
- boolean matches( UniAddress address, int port, InetAddress localAddr, int localPort ) {
- InetAddress defaultLocal = null;
- try {
- defaultLocal = InetAddress.getLocalHost();
- } catch( UnknownHostException uhe ) {
- }
- int p1 = ( port == 0 || port == 139 ) ? 0 : port;
- int p2 = ( this.port == 0 || this.port == 139 ) ? 0 : this.port;
- InetAddress la1 = localAddr == null ? defaultLocal : localAddr;
- InetAddress la2 = this.localAddr == null ? defaultLocal : this.localAddr;
- return address.equals( this.address ) &&
- p1 == p2 &&
- 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;
- NbtAddress naddr;
- String calledName;
-
- /* Hack to convert InetAddress to NbtAddress until we properly
- * abstract NetBIOSless transport with some kind of "UniSocket".
- */
- obj = address.getAddress();
- if( obj instanceof NbtAddress ) {
- naddr = (NbtAddress)obj;
- } else {
- try {
- naddr = NbtAddress.getByName( ((InetAddress)obj).getHostAddress() );
- } catch( UnknownHostException uhe ) {
- naddr = null; // never happen
- }
- }
-
- calledName = address.firstCalledName();
- do {
- try {
- socket = new NbtSocket( naddr, calledName, port, localAddr, localPort );
- break;
- } catch( NbtException ne ) {
- if( ne.errorClass == NbtException.ERR_SSN_SRVC &&
- ( ne.errorCode == NbtException.CALLED_NOT_PRESENT ||
- ne.errorCode == NbtException.NOT_LISTENING_CALLED )) {
- Log.println( Log.WARNINGS, "smb warning", ne.getMessage() );
- } else {
- throw ne;
- }
- }
- } while(( calledName = address.nextCalledName()) != null );
-
- if( calledName == null ) {
- throw new IOException( "Failed to establish session with " + address );
- }
-
- /* Save the calledName for using on SMB_COM_TREE_CONNECT
- */
- if( calledName == NbtAddress.SMBSERVER_NAME ) {
- server.tconHostName = address.getHostAddress();
- } else {
- server.tconHostName = calledName;
- }
-
- if( Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false )) {
- socket.setTcpNoDelay( true );
- }
- in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE );
- out = socket.getOutputStream();
- thread = new Thread( this, "JCIFS-SmbTransport" );
- thread.setDaemon( true );
- thread.start();
- }
- }
- void tryClose( boolean inError ) {
- SmbSession ssn;
-
- if( socket == null ) {
- inError = true;
- }
-
- ListIterator iter = sessions.listIterator();
- while( iter.hasNext() ) {
- ssn = (SmbSession)iter.next();
- ssn.logoff( inError );
- }
- if( socket != null ) {
- try {
- socket.close();
- } catch( IOException ioe ) {
- }
- }
- in = null;
- out = null;
- socket = null;
- negotiated = false;
- thread = null;
- responseTable.clear();
- }
- public void run() {
- int mid, l, i, n, m;
- ServerMessageBlock response;
- int magic[] = { 0xFF, 'S', 'M', 'B' };
-
- while( thread == Thread.currentThread() ) {
- try {
- socket.setSoTimeout( soTimeout );
-
- 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, 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.
- */
- break;
- }
- ((PushbackInputStream)in).unread( rcv_buf, 0, HEADER_LENGTH );
- if( rcv_buf[0] != (byte)0xFF ||
- rcv_buf[1] != (byte)'S' ||
- rcv_buf[2] != (byte)'M' ||
- rcv_buf[3] != (byte)'B' ) {
- Log.println( Log.WARNINGS, "smb warning",
- "bad smb header, purging session message" );
- in.skip( in.available() );
- continue;
- }
- if(( rcv_buf[FLAGS_OFFSET] & FLAGS_RESPONSE ) == FLAGS_RESPONSE ) {
- mid = ServerMessageBlock.readInt2( rcv_buf, MID_OFFSET );
-
- response = (ServerMessageBlock)responseTable.get( new Integer( mid ));
- if( response == null ) {
- Log.println( Log.WARNINGS, "smb warning",
- " no handler for mid=" + mid + ", purging session message" );
- in.skip( in.available() );
- continue;
- }
- synchronized( response ) {
- response.useUnicode = useUnicode;
- Log.println( Log.DEBUGGING, "smb transport warning",
- " new data read from socket" );
-
- if( response instanceof SmbComTransactionResponse ) {
- Enumeration e = (Enumeration)response;
- if( e.hasMoreElements() ) {
- e.nextElement();
- } else {
- Log.println( Log.WARNINGS, "smb warning",
- "more responses to transaction than expected" );
- continue;
- }
- response.readWireFormat( in, rcv_buf, 0 );
- response.received = true;
- Log.printMessageData( "smb received", response );
-
- if( response.errorCode != 0 || e.hasMoreElements() == false ) {
- ((SmbComTransactionResponse)response).hasMore = false;
- response.notify();
- } else {
- ensureOpen();
- }
- } else {
- response.readWireFormat( in, rcv_buf, 0 );
- response.received = true;
-
- Log.printMessageData( "smb received", response );
- ServerMessageBlock smb = response;
- while( smb instanceof AndXServerMessageBlock &&
- ( smb = ((AndXServerMessageBlock)smb).andx ) != null ) {
- Log.printMessageData( "smb andx data", smb );
- }
- Log.printHexDump( "smb received", rcv_buf, 0, response.length );
-
- response.notify();
- }
- }
- } else {
- // it's a request(break oplock)
- }
-}
- } catch( InterruptedIOException iioe ) {
- if( responseTable.size() == 0 ) {
- tryClose( false );
- } else {
- Log.println( Log.WARNINGS, "smb warning",
- " soTimeout has occured but there are " +
- responseTable.size() + " pending requests" );
- }
- } catch( IOException ioe ) {
- tryClose( true );
- Log.printStackTrace( "exception reading from socket input: " + address, ioe );
- }
- }
- }
- void send( ServerMessageBlock request,
- ServerMessageBlock response ) throws SmbException {
- Integer mid = null;
-
- negotiate();
-
- request.flags2 = client.flags2;
- request.mid = aquireMid();
- request.useUnicode = useUnicode;
-
- if( response == null ) {
- try {
- synchronized( outLock ) {
- ensureOpen();
-synchronized( snd_buf ) {
- out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 ));
- out.flush();
-
- Log.printMessageData( "smb sent", request );
- ServerMessageBlock smb = request;
- while( smb instanceof AndXServerMessageBlock &&
- ( smb = ((AndXServerMessageBlock)smb).andx ) != null ) {
- 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 );
- }
-
- return;
- }
-
- // now for the normal case where response is not null
-
- try {
- synchronized( response ) {
-
- response.received = false;
- mid = new Integer( request.mid );
- responseTable.put( mid, response );
-
- synchronized( outLock ) {
- ensureOpen();
-synchronized( snd_buf ) {
- out.write( snd_buf, 0, request.writeWireFormat( snd_buf, 0 ));
- out.flush();
-
- Log.printMessageData( "smb sent", request );
- ServerMessageBlock smb = request;
- while( smb instanceof AndXServerMessageBlock &&
- ( smb = ((AndXServerMessageBlock)smb).andx ) != null ) {
- 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
- response.wait( response.responseTimeout == 1 ?
- 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 );
- releaseMid( request.mid );
- }
-
- if( response.received == false ) {
- tryClose( true );
- throw new SmbException( SmbException.ERRCLI,
- SmbException.ERRserverTimeout,
- address );
- }
- switch( response.errorCode & 0xFF ) {
- case SmbException.SUCCESS:
- break;
- case SmbException.ERRDOS:
- switch(( response.errorCode >> 16 ) & 0xFFFF ) {
- case SmbException.ERRnoaccess:
- throw new SmbAuthException( response.errorCode );
- }
- throw new SmbException( response.errorCode );
- case SmbException.ERRSRV:
- switch(( response.errorCode >> 16 ) & 0xFFFF ) {
- case SmbException.ERRbadpw:
- case SmbException.ERRaccess:
- case SmbException.ERRaccountExpired:
- case SmbException.ERRbadClient:
- case SmbException.ERRbadLogonTime:
- case SmbException.ERRpasswordExpired:
- throw new SmbAuthException( response.errorCode );
- }
- default:
- throw new SmbException( response.errorCode );
- }
-
- }
- void sendTransaction( SmbComTransaction request,
- SmbComTransactionResponse response ) throws SmbException {
- Integer mid = null;
-
- negotiate();
-
- request.flags2 = client.flags2;
- request.mid = aquireMid();
- mid = new Integer( request.mid );
- request.useUnicode = useUnicode;
- request.maxBufferSize = negotiatedMaxBufferSize;
- response.received = false;
- response.hasMore = true;
- response.isPrimary = true;
-
- try {
- request.txn_buf = BufferCache.getBuffer();
- response.txn_buf = BufferCache.getBuffer();
-
- request.nextElement();
- if( request.hasMoreElements() ) {
- // multi-part request
-
- SmbComBlankResponse interimResponse = new SmbComBlankResponse();
-
- synchronized( interimResponse ) {
-
- responseTable.put( mid, interimResponse );
-
- 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 );
-
- if( interimResponse.received == false ) {
- throw new SmbException( SmbException.ERRserverTimeout );
- }
- switch( interimResponse.errorCode & 0xFF ) {
- case SmbException.SUCCESS:
- break;
- case SmbException.ERRDOS:
- switch(( response.errorCode >> 16 ) & 0xFFFF ) {
- case SmbException.ERRnoaccess:
- throw new SmbAuthException( response.errorCode );
- }
- throw new SmbException( response.errorCode );
- case SmbException.ERRSRV:
- switch(( interimResponse.errorCode >> 16 ) & 0xFFFF ) {
- case SmbException.ERRbadpw:
- case SmbException.ERRaccess:
- case SmbException.ERRaccountExpired:
- case SmbException.ERRbadClient:
- case SmbException.ERRbadLogonTime:
- case SmbException.ERRpasswordExpired:
- throw new SmbAuthException( interimResponse.errorCode );
- }
- default:
- throw new SmbException( interimResponse.errorCode );
- }
- }
- request.nextElement();
- }
-
- synchronized( response ) {
- responseTable.put( mid, response );
- 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 );
-
- do {
- // default it 1 so that 0 can be used as forever
- response.received = false;
- response.wait( response.responseTimeout == 1 ? responseTimeout : response.responseTimeout );
- } 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 );
- releaseMid( request.mid );
- BufferCache.releaseBuffer( request.txn_buf );
- BufferCache.releaseBuffer( response.txn_buf );
- }
-
- if( response.received == false ) {
- tryClose( true );
- throw new SmbException( SmbException.ERRCLI,
- SmbException.ERRserverTimeout,
- address );
- }
- switch( response.errorCode & 0xFF ) {
- case SmbException.SUCCESS:
- break;
- case SmbException.ERRDOS:
- switch(( response.errorCode >> 16 ) & 0xFFFF ) {
- case SmbException.ERRnoaccess:
- throw new SmbAuthException( response.errorCode );
- }
- throw new SmbException( response.errorCode );
- case SmbException.ERRSRV:
- switch(( response.errorCode >> 16 ) & 0xFFFF ) {
- case SmbException.ERRbadpw:
- case SmbException.ERRaccess:
- case SmbException.ERRaccountExpired:
- case SmbException.ERRbadClient:
- case SmbException.ERRbadLogonTime:
- case SmbException.ERRpasswordExpired:
- throw new SmbAuthException( response.errorCode );
- }
- default:
- throw new SmbException( response.errorCode );
- }
- }
- synchronized void negotiate() throws SmbException {
-
- if( negotiated ) {
- return;
- }
- /* we must set this here rather than later because this
- * 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
- */
- negotiated = true;
-
- Log.println( Log.WARNINGS, "smb negotiation warning",
- " requesting negotiation with " + address );
-
- /*
- * Negotiate Protocol Request / Response
- */
-
- SmbComNegotiateResponse response = new SmbComNegotiateResponse();
- send( new SmbComNegotiate(), response );
-
- if( response.dialectIndex > 10 ) {
- tryClose( true );
- throw new SmbException( SmbException.ERRCLI, SmbException.ERRbadDialect );
- }
-
- server.securityMode = response.securityMode;
- server.security = response.security;
- server.encryptedPasswords = response.encryptedPasswords;
- server.signaturesEnabled = response.signaturesEnabled;
- server.signaturesRequired = response.signaturesRequired;
- negotiatedDialectIndex = response.dialectIndex;;
- server.maxMpxCount = response.maxMpxCount;
- negotiatedMaxMpxCount = client.maxMpxCount < server.maxMpxCount ?
- client.maxMpxCount : server.maxMpxCount;
- mpxCtrl.maxMpxCount = negotiatedMaxMpxCount < 1 ?
- 1 : negotiatedMaxMpxCount;
- server.maxNumberVcs = response.maxNumberVcs;
- server.maxBufferSize = response.maxBufferSize;
- negotiatedMaxBufferSize = client.maxBufferSize < server.maxBufferSize ?
- client.maxBufferSize : server.maxBufferSize;
- server.maxRawSize = response.maxRawSize;
- server.sessionKey = response.sessionKey;
- server.capabilities = response.capabilities;
- negotiatedCapabilities = client.capabilities & server.capabilities;
- if(( negotiatedCapabilities & ServerMessageBlock.CAP_UNICODE ) == 0 ) {
- // server doesn't want unicode
- if( Config.getBoolean( "jcifs.smb.client.useUnicode", false )) {
- // force unicode
- negotiatedCapabilities |= ServerMessageBlock.CAP_UNICODE;
- } else {
- // not explicitly set to true so flip unicode off as server requests
- useUnicode = false;
- client.flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
- }
- }
- server.serverTime = response.serverTime;
- server.serverTimeZone = response.serverTimeZone;
- server.encryptionKeyLength = response.encryptionKeyLength;
- server.encryptionKey = response.encryptionKey;
- server.oemDomainName = response.oemDomainName;
- }
- public String toString() {
- 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 {
- try {
- return mpxCtrl.aquireMid();
- } catch( InterruptedException ie ) {
- throw new SmbException( SmbException.ERRCLI, SmbException.ERRioe, ie.getMessage() );
- }
- }
- static void releaseMid( int mid ) {
- mpxCtrl.releaseMid( mid );
- }
-
- static class MpxControl {
- MpxListNode first, last;
- class MpxListNode {
- int i;
- MpxListNode next;
- MpxListNode( int id ) {
- i = id;
- next = null;
- }
- }
- int nextMid, mpxCount, maxMpxCount;
-
- MpxControl() {
- nextMid = 0;
- mpxCount = 0;
- maxMpxCount = 1;
- first = last = null;
- }
-
- synchronized void clear() {
- nextMid = 0;
- mpxCount = 0;
- maxMpxCount = 1;
- first = last = null;
- }
- synchronized int aquireMid() throws InterruptedException {
- while( mpxCount >= maxMpxCount ) {
- wait();
- }
- if(( ++nextMid % 0xFFFF ) == 0 ) {
- nextMid = 1;
- }
- add( nextMid );
- mpxCount++;
- return nextMid;
- }
- synchronized void releaseMid( int i ) {
- remove( i );
- mpxCount--;
- notify();
- }
- synchronized boolean contains( int i ) {
- for( MpxListNode tmp = first; tmp != null; tmp = tmp.next ) {
- if( tmp.i == i ) {
- return true;
- }
- }
- return false;
- }
- synchronized void add( int i ) {
- if( contains( i )) {
- return;
- }
- if( first == null ) {
- first = last = new MpxListNode( i );
- } else {
- last = last.next = new MpxListNode( i );
- }
- }
- synchronized void remove( int i ) {
- if( first == null ) {
- return;
- } else if( first == last && first.i == i ) {
- first = last = null;
- return;
- }
- MpxListNode tmp, prev;
- for( tmp = prev = first; tmp != null; tmp = tmp.next ) {
- if( tmp.i == i ) {
- if( tmp == first ) {
- first = first.next;
- } else if( tmp == last ) {
- last = prev;
- last.next = null;
- } else {
- prev.next = tmp.next;
- }
- return;
- }
- prev = tmp;
- }
- }
- }
-}