-Wed May 4 22:59:32 EDT 2005
-jcifs-1.1.11 released
-
-If a file is opened with SmbFileOutputStream, written to, and then the
-client waits for soTimeout without any communication to the target, a
-subsequent write would zero the contents of the file before the file
-pointer. This file corruption bug has been fixed.
-
-Sun Apr 17 22:37:04 EDT 2005
-jcifs-1.1.10 released
-
-The getChallengeForDomain code has been rewritten. It has been considerably
-simplified. It will now rotate through the first
-jcifs.netbios.lookupRespLimit domain controllers rather than try to grow
-and shrink the list depending on load. The lookupRespLimit property default
-has been reduced to 3. The timeout value for rebuilting the DC list has
-been increased from 20 minutes to 10 hours. This is calculated by
-multiplying jcifs.netvios.cachePolicy by 60 but the default in the
-SmbSession class is 60 * 10 meaning 10 minutes so 10 * 60 is 10 hours.
-Finally the NtlmChallenge class is now Serializeable for servers that are
-pedantic about what can be stored in a session.
+Sun May 22 18:22:32 EDT 2005
+jcifs-1.2.0 released
+
+This release is jcifs-1.1.11trans2 with the following modifications.
+
+Named pipes were broken when DCE transactions where added with 1.x. Call,
+Transact, CreateFile, and DCE named pipe calls should now all work as
+expected. The NetBIOS name resolution code will now use the last resource
+record of a name query response if there are more than one. This appears to
+be more correct in at least one instance (VMWare adapters on my workstation
+at work are appearing first).
+
+Also note the trans releases below.
+
+Mon May 9 18:49:24 EDT 2005
+jcifs-1.1.11trans2 released
+
+Socket exception handling was non-existant and reads would actually not
+read anything but 0's. These issues and other small issues have been fixed.
+
+Wed May 4 22:31:28 EDT 2005
+jcifs-1.1.11trans released
+
+This "transitional" release has all the 1.1.10 and 1.1.11 fixes as well as
+more work on the transport layer. The last trans release had a silly mid
+rollover bug. I have also emiminated a deadlock condition. These issues
+have been fixed. Also the client will not properly try port 445 and
+fallback to 139 as necessary. This *could* be stable enough that I might
+try to promote this to 1.2.0.
+
+Thu Apr 7 23:02:48 EDT 2005
+jcifs-1.1.9trans released
+
+This is a 'transitional' or 'transport rewrite' release. It's stock 1.1.9
+but the transport layer has been refactored and reduced (actually totally
+rewritten - SmbTransport.java is less than half the size of it's previous
+version). It may still not be "correct" because I believe the high-load
+concurrency issue may have to do with how sessions and trees are created.
+That is another step that delves into how Principles will be handled so I
+thought I would release this as is because it seems pretty stable so I
+thought I would put it out there as a reference point. To give people an
+insentive to actually use it I have changed the port to 445, applied the
+share reconnect fix from Darren and the getDiskFreeSpace patch from Thomas.
+Also if you really need the dial to go to 11, preliminary testing indicates
+this transport is a few percent faster.
+
+Feb 28 03:09:31 EST 2005
+jcifs-1.1.9 released
+
+When multiplexing I/O, if socket buffers fill up such that packets can be
+read in fragments (i.e. high load), it was possible for the 4 byte NetBIOS
+header to be read incorrectly resulting in a bogus "unexpected EOF reading
+netbios session header" exception. This problem has been fixed. Also, some
+small javadoc updates have been applied.
Thu Feb 10 22:29:12 EST 2005
jcifs-1.1.8 released
<project name="jcifs" default="usage" basedir=".">
- <property name="version" value="1.1.11"/>
- <property name="reldate" value="May 4, 2005"/>
+ <property name="version" value="1.2.0"/>
+ <property name="reldate" value="May 22, 2005"/>
<target name="usage">
<echo>
traverse( l[i], depth - 1 );
}
} catch( IOException ioe ) {
- System.out.println( l[i] + ": " + ioe.getMessage() );
+ System.out.println( l[i] + ":" );
+ ioe.printStackTrace( System.out );
}
}
}
T2Crawler( String dir, int numThreads, int depth ) throws Exception {
SmbFile top = new SmbFile( dir );
Semaphore sem = new Semaphore( numThreads );
- SmbFile[] l = top.listFiles();
- depth--;
- for( int i = 0; i < l.length; i++ ) {
- try {
- System.out.println( l[i] );
- if( !l[i].isDirectory() || l[i].isHidden() ) {
- continue;
- }
- if( depth > 0 ) {
- sem.P();
- (new CrawlerThread( l[i], sem, depth )).start();
+ SmbFile[] l = null;
+ int i = 0;
+
+ try {
+ l = top.listFiles();
+ depth--;
+ for( i = 0; i < l.length; i++ ) {
+ try {
+ System.out.println( l[i] );
+ if( !l[i].isDirectory() || l[i].isHidden() ) {
+ continue;
+ }
+ if( depth > 0 ) {
+ sem.P();
+ (new CrawlerThread( l[i], sem, depth )).start();
+ }
+ } catch( Exception e ) {
+ e.printStackTrace();
}
- } catch( Exception e ) {
- e.printStackTrace();
}
- }
- for( int i = 0; i < l.length; i++ ) {
- l[i].canRead();
+ for( i = 0; i < l.length; i++ ) {
+ l[i].canRead();
+ }
+ } catch( Exception ex ) {
+ System.err.println( l[i] );
+ ex.printStackTrace();
}
}
public static void main(String[] argv) throws Exception {
}
return def;
}
+ public static InetAddress getLocalHost() {
+ String addr = prp.getProperty( "jcifs.smb.client.laddr" );
+ try {
+ if( addr == null ) {
+ return InetAddress.getLocalHost();
+ }
+ return InetAddress.getByName( addr );
+ } catch( UnknownHostException uhe ) {
+ if( log.level > 0 ) {
+ log.println( addr );
+ uhe.printStackTrace( log );
+ }
+ }
+
+ return null;
+ }
/**
* Retrieve a boolean value. If the property is not found, the value of <code>def</code> is returned.
import jcifs.netbios.NbtAddress;
import jcifs.util.MimeMap;
import jcifs.util.Base64;
+import jcifs.util.LogStream;
/**
* This servlet may be used to "browse" the entire hierarchy of resources
* on an SMB network like one might with Network Neighborhood or Windows
* Explorer. The users credentials with be negotiated using NTLM SSP if
* the client is Microsoft Internet Explorer.
- *
- * Please read <a href="../../../ntlmhttpauth.html">jCIFS NTLM HTTP Authentication and the Network Explorer Servlet</a>.
*/
public class NetworkExplorer extends HttpServlet {
+ private static LogStream log = LogStream.getInstance();
+
private MimeMap mimeMap;
private String style;
private NtlmSsp ntlmSsp;
InputStream is;
StringBuffer sb = new StringBuffer();
byte[] buf = new byte[1024];
- int n;
+ int n, level;
String name;
Config.setProperty( "jcifs.smb.client.soTimeout", "600000" );
realm = Config.getProperty("jcifs.http.basicRealm");
if (realm == null) realm = "jCIFS";
defaultDomain = Config.getProperty("jcifs.smb.client.domain");
+
+ if(( level = Config.getInt( "jcifs.util.loglevel", -1 )) != -1 ) {
+ LogStream.setLevel( level );
+ }
+ if( log.level > 2 ) {
+ try {
+ Config.store( log, "JCIFS PROPERTIES" );
+ } catch( IOException ioe ) {
+ }
+ }
}
protected void doFile( HttpServletRequest req,
sdf.setCalendar( cal );
dirents = dir.listFiles();
+ if( log.level > 2 )
+ log.println( dirents.length + " items listed" );
sorted = new LinkedList();
if(( fmt = req.getParameter( "fmt" )) == null ) {
fmt = "col";
continue;
}
} catch( SmbAuthException sae ) {
+ if( log.level > 2 )
+ sae.printStackTrace( log );
} catch( SmbException se ) {
+ if( log.level > 2 )
+ se.printStackTrace( log );
if( se.getNtStatus() != se.NT_STATUS_UNSUCCESSFUL ) {
throw se;
}
}
name = dirents[i].getName();
+ if( log.level > 3 )
+ log.println( i + ": " + name );
len = name.length();
if( len > maxLen ) {
maxLen = len;
* "Jason Pugsley" <jcifs at samba dot org>
* "skeetz" <jcifs at samba dot org>
* "Eric Glass" <jcifs at samba dot org>
+ * and Marcel, Thomas, ...
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
public void destroy() {
}
+
+ /**
+ * This method simply calls <tt>negotiate( req, resp, false )</tt>
+ * and then <tt>chain.doFilter</tt>. You can override and call
+ * negotiate manually to achive a variety of different behavior.
+ */
public void doFilter( ServletRequest request,
ServletResponse response,
FilterChain chain ) throws IOException, ServletException {
- HttpServletRequest req;
- HttpServletResponse resp;
+ HttpServletRequest req = (HttpServletRequest)request;
+ HttpServletResponse resp = (HttpServletResponse)response;
+ NtlmPasswordAuthentication ntlm;
+
+ if ((ntlm = negotiate( req, resp, false )) == null) {
+ return;
+ }
+
+ chain.doFilter( new NtlmHttpServletRequest( req, ntlm ), response );
+ }
+
+ /**
+ * Negotiate password hashes with MSIE clients using NTLM SSP
+ * @param req The servlet request
+ * @param resp The servlet response
+ * @param skipAuthentication If true the negotiation is only done if it is
+ * initiated by the client (MSIE post requests after successful NTLM SSP
+ * authentication). If false and the user has not been authenticated yet
+ * the client will be forced to send an authentication (server sends
+ * HttpServletResponse.SC_UNAUTHORIZED).
+ * @return True if the negotiation is complete, otherwise false
+ */
+ protected NtlmPasswordAuthentication negotiate( HttpServletRequest req,
+ HttpServletResponse resp,
+ boolean skipAuthentication ) throws IOException, ServletException {
UniAddress dc;
String msg;
-
NtlmPasswordAuthentication ntlm = null;
- req = (HttpServletRequest)request;
- resp = (HttpServletResponse)response;
msg = req.getHeader( "Authorization" );
boolean offerBasic = enableBasic && (insecureBasic || req.isSecure());
}
if(( ntlm = NtlmSsp.authenticate( req, resp, challenge )) == null ) {
- return;
+ return null;
}
/* negotiation complete, remove the challenge object */
ssn.removeAttribute( "NtlmHttpChal" );
resp.addHeader( "WWW-Authenticate", "Basic realm=\"" +
realm + "\"");
}
+ resp.setContentLength(0); /* Marcel Feb-15-2005 */
resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
resp.flushBuffer();
- return;
+ return null;
}
req.getSession().setAttribute( "NtlmHttpAuth", ntlm );
} else {
- HttpSession ssn = req.getSession(false);
- if (ssn == null || (ntlm = (NtlmPasswordAuthentication)
- ssn.getAttribute("NtlmHttpAuth")) == null) {
- resp.setHeader( "WWW-Authenticate", "NTLM" );
- if (offerBasic) {
- resp.addHeader( "WWW-Authenticate", "Basic realm=\"" +
- realm + "\"");
+ if (!skipAuthentication) {
+ HttpSession ssn = req.getSession(false);
+ if (ssn == null || (ntlm = (NtlmPasswordAuthentication)
+ ssn.getAttribute("NtlmHttpAuth")) == null) {
+ resp.setHeader( "WWW-Authenticate", "NTLM" );
+ if (offerBasic) {
+ resp.addHeader( "WWW-Authenticate", "Basic realm=\"" +
+ realm + "\"");
+ }
+ resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
+ resp.flushBuffer();
+ return null;
}
- resp.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
- resp.flushBuffer();
- return;
}
}
- chain.doFilter( new NtlmHttpServletRequest( req, ntlm ), response );
+ return ntlm;
}
// Added by cgross to work with weblogic 6.1.
import jcifs.Config;
import jcifs.util.Hexdump;
-class Name {
+public class Name {
private static final int TYPE_OFFSET = 31;
private static final int SCOPE_OFFSET = 33;
Config.getProperty( "jcifs.encoding",
System.getProperty( "file.encoding" ));
- String name, scope;
- int hexCode;
+ public String name, scope;
+ public int hexCode;
int srcHashCode; /* srcHashCode must be set by name resolution
* routines before entry into addressCache
*/
Name() {
}
- Name( String name, int hexCode, String scope ) {
+ public Name( String name, int hexCode, String scope ) {
if( name.length() > 15 ) {
name = name.substring( 0, 15 );
}
}
if( response.received && response.resultCode == 0 ) {
- response.addrEntry[0].hostName.srcHashCode = addr.hashCode();
- return response.addrEntry[0];
+ int last = response.addrEntry.length - 1;
+ response.addrEntry[last].hostName.srcHashCode = addr.hashCode();
+ return response.addrEntry[last];
}
} while( --n > 0 && request.isBroadcast );
public static NbtAddress getLocalHost() throws UnknownHostException {
return localhost;
}
+ public static Name getLocalName() {
+ return localhost.hostName;
+ }
/**
* Determines the address of a host given it's host name. The name can be a NetBIOS name like
i++;
}
}
- } else if( hostName.hexCode == 0x1D || hostName.hexCode == 0x1C ) {
- calledName = SMBSERVER_NAME;
+ } else {
+ switch (hostName.hexCode) {
+ case 0x1B:
+ case 0x1C:
+ case 0x1D:
+ calledName = SMBSERVER_NAME;
+ }
}
return calledName;
import java.io.IOException;
import java.io.InputStream;
-class SessionRequestPacket extends SessionServicePacket {
+public class SessionRequestPacket extends SessionServicePacket {
private Name calledName, callingName;
calledName = new Name();
callingName = new Name();
}
- SessionRequestPacket( Name calledName, Name callingName ) {
+ public SessionRequestPacket( Name calledName, Name callingName ) {
type = SESSION_REQUEST;
this.calledName = calledName;
this.callingName = callingName;
import java.io.IOException;
import java.io.InputStream;
-abstract class SessionServicePacket {
+public abstract class SessionServicePacket {
// session service packet types
static final int SESSION_MESSAGE = 0x00;
static final int SESSION_REQUEST = 0x81;
- static final int POSITIVE_SESSION_RESPONSE = 0x82;
- static final int NEGATIVE_SESSION_RESPONSE = 0x83;
+ public static final int POSITIVE_SESSION_RESPONSE = 0x82;
+ public static final int NEGATIVE_SESSION_RESPONSE = 0x83;
static final int SESSION_RETARGET_RESPONSE = 0x84;
static final int SESSION_KEEP_ALIVE = 0x85;
int type, length;
- int writeWireFormat( byte[] dst, int dstIndex ) {
+ public int writeWireFormat( byte[] dst, int dstIndex ) {
length = writeTrailerWireFormat( dst, dstIndex + HEADER_LENGTH );
writeHeaderWireFormat( dst, dstIndex );
return HEADER_LENGTH + length;
AndXServerMessageBlock() {
}
AndXServerMessageBlock( ServerMessageBlock andx ) {
- this.andx = andx;
- if( andx != null ) {
+ if (andx != null) {
+ this.andx = andx;
andxCommand = andx.command;
}
}
- /* The SmbComReadAndXResponse can read from the InputStream
- * directly by implementing this method. The default
- * behavior is to arraycopy all bytes into the buffer and call
- * readBytesWireFormat. The alternative would have been to overload
- * the readAndXWireFormat method but that would have resulted in
- * copying a fairly large chunck of code into the subclass.
- */
-
- abstract int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException;
-
int getBatchLimit( byte command ) {
/* the default limit is 0 batched messages before this
* one, meaning this message cannot be batched.
* just recursivly call writeAndXWireFormat.
*/
- int writeWireFormat( byte[] dst, int dstIndex ) {
+ int encode( byte[] dst, int dstIndex ) {
int start = headerStart = dstIndex;
dstIndex += writeHeaderWireFormat( dst, dstIndex );
* readAndXWireFormat without reading the non-existent header.
*/
- int readWireFormat( InputStream in,
- byte[] buffer,
- int bufferIndex )
- throws IOException {
- int start = bufferIndex;
+ int decode( byte[] buffer, int bufferIndex ) {
+ int start = headerStart = bufferIndex;
- if( in.read( buffer, bufferIndex, HEADER_LENGTH ) != HEADER_LENGTH ) {
- throw new IOException( "unexpected EOF reading smb header" );
- }
bufferIndex += readHeaderWireFormat( buffer, bufferIndex );
- bufferIndex += readAndXWireFormat( in, buffer, bufferIndex );
+ bufferIndex += readAndXWireFormat( buffer, bufferIndex );
length = bufferIndex - start;
return length;
int start = dstIndex;
wordCount = writeParameterWordsWireFormat( dst,
- start + ANDX_OFFSET_OFFSET + 2 );
+ start + ANDX_OFFSET_OFFSET + 2 );
wordCount += 4; // for command, reserved, and offset
dstIndex += wordCount + 1;
wordCount /= 2;
* very indirect and simple batching control mechanism.
*/
-
if( andx == null || USE_BATCHING == false ||
batchLevel >= getBatchLimit( andx.command )) {
andxCommand = (byte)0xFF;
return dstIndex - start;
}
- int readAndXWireFormat( InputStream in,
- byte[] buffer,
- int bufferIndex )
- throws IOException {
+ int readAndXWireFormat( byte[] buffer, int bufferIndex ) {
int start = bufferIndex;
- /*
- * read wordCount
- */
-
- if(( wordCount = in.read() ) == -1 ) {
- throw new IOException( "unexpected EOF reading smb wordCount" );
- }
- buffer[bufferIndex++] = (byte)( wordCount & 0xFF );
-
- /*
- * read parameterWords
- */
+ wordCount = buffer[bufferIndex++];
if( wordCount != 0 ) {
- if( in.read( buffer, bufferIndex, wordCount * 2 ) != ( wordCount * 2 )) {
- throw new IOException( "unexpected EOF reading andx parameter words" );
- }
-
/*
* these fields are common to all andx commands
* so let's populate them here
*/
-
- andxCommand = buffer[bufferIndex];
- bufferIndex += 2;
- andxOffset = readInt2( buffer, bufferIndex );
- bufferIndex += 2;
+
+ andxCommand = buffer[bufferIndex]; 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
* parameter words. besides, win98 doesn't return "OptionalSupport" field
*/
-
+
if( wordCount > 2 ) {
bufferIndex += readParameterWordsWireFormat( buffer, bufferIndex );
}
}
- /*
- * read byteCount
- */
+ byteCount = readInt2( buffer, bufferIndex ); bufferIndex += 2;
- if( in.read( buffer, bufferIndex, 2 ) != 2 ) {
- throw new IOException( "unexpected EOF reading smb byteCount" );
- }
- byteCount = readInt2( buffer, bufferIndex );
- bufferIndex += 2;
-
- /*
- * read bytes
- */
-
- if( byteCount != 0 ) {
+ if (byteCount != 0) {
int n;
- n = readBytesDirectWireFormat( in, byteCount, buffer, bufferIndex );
- if( n == 0 ) {
- if( in.read( buffer, bufferIndex, byteCount ) != byteCount ) {
- throw new IOException( "unexpected EOF reading andx bytes" );
- }
- n = readBytesWireFormat( buffer, bufferIndex );
- }
+ n = readBytesWireFormat( buffer, bufferIndex );
bufferIndex += byteCount;
}
andx = null;
} else if( andx == null ) {
andxCommand = (byte)0xFF;
- throw new IOException( "no andx command supplied with response" );
+ throw new RuntimeException( "no andx command supplied with response" );
} else {
/*
- * This is where we take into account andxOffset
- *
- * Before we call readAndXWireFormat on the next andx
- * part we must take into account the andxOffset. The
- * input stream must be positioned at this location. The
- * new location is the just read andxOffset(say 68)
- * minus the current bufferIndex(say 65). But this packet
- * construction/deconstruction technique does not require that
- * the bufferIndex begin at 0. The header might be at another
- * location(say 4). So we must subtract the current buffer
- * index from the real start of the header and substract that
- * from the andxOffset(like 68 - ( 65 - 0 ) if headerStart
- * were 0 or 68 - ( 69 - 4 ) if the headerStart were 4. We
- * also need to communicate to our newly instantiated andx
- * smb the headerStart value so that it may perform the same
- * calculation as this is a recursive process.
+ * Set bufferIndex according to andxOffset
*/
- bufferIndex += in.read( buffer, bufferIndex,
- andxOffset - ( bufferIndex - headerStart ));
+ bufferIndex = headerStart + andxOffset;
andx.headerStart = headerStart;
andx.command = andxCommand;
if( andx instanceof AndXServerMessageBlock ) {
bufferIndex += ((AndXServerMessageBlock)andx).readAndXWireFormat(
- in, buffer, andxOffset - headerStart );
+ buffer, bufferIndex );
} else {
/*
* Just a plain smb. Read it as normal.
*/
- /*
- * read wordCount
- */
-
- if(( andx.wordCount = in.read() ) == -1 ) {
- throw new IOException( "unexpected EOF reading smb wordCount" );
- }
buffer[bufferIndex++] = (byte)( andx.wordCount & 0xFF );
- /*
- * read parameterWords
- */
-
if( andx.wordCount != 0 ) {
- if( in.read( buffer, bufferIndex, andx.wordCount * 2 ) !=
- ( andx.wordCount * 2 )) {
- throw new IOException( "unexpected EOF reading andx parameter words" );
- }
-
/*
* no point in calling readParameterWordsWireFormat if there are no more
* parameter words. besides, win98 doesn't return "OptionalSupport" field
*/
if( andx.wordCount > 2 ) {
- bufferIndex +=
- andx.readParameterWordsWireFormat( buffer, bufferIndex );
+ bufferIndex += andx.readParameterWordsWireFormat( buffer, bufferIndex );
}
}
- /*
- * read byteCount
- */
-
- if( in.read( buffer, bufferIndex, 2 ) != 2 ) {
- throw new IOException( "unexpected EOF reading smb byteCount" );
- }
andx.byteCount = readInt2( buffer, bufferIndex );
bufferIndex += 2;
- /*
- * read bytes
- */
-
if( andx.byteCount != 0 ) {
- if( in.read( buffer, bufferIndex, andx.byteCount ) != andx.byteCount ) {
- throw new IOException( "unexpected EOF reading andx bytes" );
- }
andx.readBytesWireFormat( buffer, bufferIndex );
bufferIndex += andx.byteCount;
}
private static final int MAX_BUFFERS = Config.getInt( "jcifs.smb.maxBuffers", 16 );
- private static Object[] cache = new Object[MAX_BUFFERS];
+ static Object[] cache = new Object[MAX_BUFFERS];
private static int numBuffers = 0;
private static int freeBuffers = 0;
- static byte[] getBuffer() {
+ private static byte[] getBuffer() {
byte[] buf;
- synchronized( cache ) {
- while( freeBuffers == 0 && numBuffers == MAX_BUFFERS ) {
- try {
- cache.wait();
- } catch( InterruptedException ie ) {
- return null;
+ if (freeBuffers > 0) {
+ for (int i = 0; i < MAX_BUFFERS; i++) {
+ if( cache[i] != null ) {
+ buf = (byte[])cache[i];
+ cache[i] = null;
+ freeBuffers--;
+ return buf;
}
}
+ }
+
+ buf = new byte[SmbComTransaction.TRANSACTION_BUF_SIZE];
+ numBuffers++;
+
+ return buf;
+ }
- if( freeBuffers > 0 ) {
- for( int i = 0; i < MAX_BUFFERS; i++ ) {
- if( cache[i] != null ) {
- buf = (byte[])cache[i];
- cache[i] = null;
- freeBuffers--;
- return buf;
- }
+ static void getBuffers( SmbComTransaction req, SmbComTransactionResponse rsp ) {
+ synchronized( cache ) {
+ try {
+ while ((freeBuffers + (MAX_BUFFERS - numBuffers)) < 2) {
+ cache.wait();
}
+ req.txn_buf = getBuffer();
+ rsp.txn_buf = getBuffer();
+ } catch( InterruptedException ie ) {
+ ie.printStackTrace();
}
-
- buf = new byte[SmbComTransaction.TRANSACTION_BUF_SIZE];
- numBuffers++;
}
-
- return buf;
}
static void releaseBuffer( byte[] buf ) {
synchronized( cache ) {
- for( int i = 0; i < MAX_BUFFERS; i++ ) {
- if( cache[i] == null ) {
+ for (int i = 0; i < MAX_BUFFERS; i++) {
+ if (cache[i] == null) {
cache[i] = buf;
freeBuffers++;
cache.notify();
}
protected int getDefaultPort() {
- return 139;
+ return SmbConstants.DEFAULT_PORT;
}
public URLConnection openConnection( URL u ) throws IOException {
return new SmbFile( u );
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_DEVICE = 0xC000000e;
public static final int NT_STATUS_NO_SUCH_FILE = 0xC000000f;
public static final int NT_STATUS_ACCESS_DENIED = 0xC0000022;
public static final int NT_STATUS_OBJECT_NAME_INVALID = 0xC0000033;
public static final int NT_STATUS_PIPE_CLOSING = 0xC00000b1;
public static final int NT_STATUS_PIPE_LISTENING = 0xC00000b3;
public static final int NT_STATUS_FILE_IS_A_DIRECTORY = 0xC00000ba;
+ public static final int NT_STATUS_NETWORK_NAME_DELETED = 0xC00000c9;
public static final int NT_STATUS_BAD_NETWORK_NAME = 0xC00000cc;
public static final int NT_STATUS_NOT_A_DIRECTORY = 0xC0000103;
public static final int NT_STATUS_CANNOT_DELETE = 0xC0000121;
public static final int NT_STATUS_PIPE_BROKEN = 0xC000014b;
public static final int NT_STATUS_LOGON_TYPE_NOT_GRANTED = 0xC000015b;
+ public static final int NT_STATUS_TRUSTED_DOMAIN_FAILURE = 0xC000018c;
public static final int NT_STATUS_ACCOUNT_LOCKED_OUT = 0xC0000234;
public static final int NT_STATUS_PATH_NOT_COVERED = 0xC0000257;
NT_STATUS_INVALID_INFO_CLASS,
NT_STATUS_ACCESS_VIOLATION,
NT_STATUS_INVALID_HANDLE,
+ NT_STATUS_NO_SUCH_DEVICE,
NT_STATUS_NO_SUCH_FILE,
NT_STATUS_ACCESS_DENIED,
NT_STATUS_OBJECT_NAME_INVALID,
NT_STATUS_PIPE_CLOSING,
NT_STATUS_PIPE_LISTENING,
NT_STATUS_FILE_IS_A_DIRECTORY,
+ NT_STATUS_NETWORK_NAME_DELETED,
NT_STATUS_BAD_NETWORK_NAME,
NT_STATUS_NOT_A_DIRECTORY,
NT_STATUS_CANNOT_DELETE,
NT_STATUS_PIPE_BROKEN,
NT_STATUS_LOGON_TYPE_NOT_GRANTED,
+ NT_STATUS_TRUSTED_DOMAIN_FAILURE,
NT_STATUS_ACCOUNT_LOCKED_OUT,
NT_STATUS_PATH_NOT_COVERED,
};
"Invalid access to memory location.",
"The handle is invalid.",
"The system cannot find the file specified.",
+ "The system cannot find the file specified.",
"Access is denied.",
"The filename, directory name, or volume label syntax is incorrect.",
"The system cannot find the file specified.",
"The pipe is being closed.",
"Waiting for a process to open the other end of the pipe.",
"Access is denied.",
+ "The specified network name is no longer available.",
"The network name cannot be found.",
"The directory name is invalid.",
"Access is denied.",
"The pipe has been ended.",
"Logon failure: the user has not been granted the requested logon type at this computer.",
+ "The trust relationship between the primary domain and the trusted domain failed.",
"The referenced account is currently locked out and may not be logged on to.",
"The remote system is not reachable by the transport.",
};
package jcifs.smb;
import java.io.Serializable;
-import jcifs.util.Hexdump;
import jcifs.UniAddress;
+import jcifs.util.Hexdump;
public final class NtlmChallenge implements Serializable {
import java.io.PushbackInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
-import java.util.TimeZone;
import java.util.Calendar;
import java.util.Date;
import jcifs.util.Hexdump;
import jcifs.util.LogStream;
+import jcifs.util.transport.*;
-abstract class ServerMessageBlock {
-
- static final int FLAGS_NONE = 0x00;
- static final int FLAGS_LOCK_AND_READ_WRITE_AND_UNLOCK = 0x01;
- static final int FLAGS_RECEIVE_BUFFER_POSTED = 0x02;
- static final int FLAGS_PATH_NAMES_CASELESS = 0x08;
- static final int FLAGS_PATH_NAMES_CANONICALIZED = 0x10;
- static final int FLAGS_OPLOCK_REQUESTED_OR_GRANTED = 0x20;
- static final int FLAGS_NOTIFY_OF_MODIFY_ACTION = 0x40;
- static final int FLAGS_RESPONSE = 0x80;
-
- static final int FLAGS2_NONE = 0x0000;
- static final int FLAGS2_LONG_FILENAMES = 0x0001;
- static final int FLAGS2_EXTENDED_ATTRIBUTES = 0x0002;
- static final int FLAGS2_SECURITY_SIGNATURES = 0x0004;
- static final int FLAGS2_EXTENDED_SECURITY_NEGOTIATION = 0x0800;
- static final int FLAGS2_RESOLVE_PATHS_IN_DFS = 0x1000;
- static final int FLAGS2_PERMIT_READ_IF_EXECUTE_PERM = 0x2000;
- static final int FLAGS2_STATUS32 = 0x4000;
- static final int FLAGS2_UNICODE = 0x8000;
-
- static final int CAP_NONE = 0x0000;
- static final int CAP_RAW_MODE = 0x0001;
- static final int CAP_MPX_MODE = 0x0002;
- static final int CAP_UNICODE = 0x0004;
- static final int CAP_LARGE_FILES = 0x0008;
- static final int CAP_NT_SMBS = 0x0010;
- static final int CAP_RPC_REMOTE_APIS = 0x0020;
- static final int CAP_STATUS32 = 0x0040;
- static final int CAP_LEVEL_II_OPLOCKS = 0x0080;
- static final int CAP_LOCK_AND_READ = 0x0100;
- static final int CAP_NT_FIND = 0x0200;
- static final int CAP_DFS = 0x1000;
-
- // file attribute encoding
- static final int ATTR_READONLY = 0x01;
- static final int ATTR_HIDDEN = 0x02;
- static final int ATTR_SYSTEM = 0x04;
- static final int ATTR_VOLUME = 0x08;
- static final int ATTR_DIRECTORY = 0x10;
- static final int ATTR_ARCHIVE = 0x20;
-
- // extended file attribute encoding(others same as above)
- static final int ATTR_COMPRESSED = 0x800;
- static final int ATTR_NORMAL = 0x080;
- static final int ATTR_TEMPORARY = 0x100;
-
- // flags for move and copy
- static final int FLAGS_TARGET_MUST_BE_FILE = 0x0001;
- static final int FLAGS_TARGET_MUST_BE_DIRECTORY = 0x0002;
- static final int FLAGS_COPY_TARGET_MODE_ASCII = 0x0004;
- static final int FLAGS_COPY_SOURCE_MODE_ASCII = 0x0008;
- static final int FLAGS_VERIFY_ALL_WRITES = 0x0010;
- static final int FLAGS_TREE_COPY = 0x0020;
-
- // open function
- static final int OPEN_FUNCTION_FAIL_IF_EXISTS = 0x0000;
- static final int OPEN_FUNCTION_OVERWRITE_IF_EXISTS = 0x0020;
-
- static final int PID = (int)( Math.random() * 65536d );
-
- static final int SECURITY_SHARE = 0x00;
- static final int SECURITY_USER = 0x01;
-
- static final int CMD_OFFSET = 4;
- static final int ERROR_CODE_OFFSET = 5;
- static final int FLAGS_OFFSET = 9;
- static final int SIGNATURE_OFFSET = 14;
- static final int TID_OFFSET = 24;
- static final int HEADER_LENGTH = 32;
-
- static final long MILLISECONDS_BETWEEN_1970_AND_1601 = 11644473600000L;
- static final TimeZone TZ = TimeZone.getDefault();
-
- static final boolean USE_BATCHING = Config.getBoolean( "jcifs.smb.client.useBatching", true );
- static final String OEM_ENCODING =
- Config.getProperty( "jcifs.encoding",
- System.getProperty( "file.encoding" ));
+abstract class ServerMessageBlock extends Response implements Request, SmbConstants {
static LogStream log = LogStream.getInstance();
int hi = readInt4( src, srcIndex + 4 );
long t = ((long)hi << 32L ) | (low & 0xFFFFFFFFL);
t = ( t / 10000L - MILLISECONDS_BETWEEN_1970_AND_1601 );
-
-/*
- synchronized( TZ ) {
- if( TZ.inDaylightTime( new Date() )) {
- // in DST
- if( TZ.inDaylightTime( new Date( t ))) {
- // t also in DST so no correction
- return t;
- }
- // t not in DST so add 1 hour
- return t + 3600000;
- } else {
- // not in DST
- if( TZ.inDaylightTime( new Date( t ))) {
- // t is in DST so subtract 1 hour
- return t - 3600000;
- }
- // t isn't in DST either
- return t;
- }
- }
-*/
return t;
}
static void writeTime( long t, byte[] dst, int dstIndex ) {
-
if( t != 0L ) {
-/*
- synchronized( TZ ) {
- if( TZ.inDaylightTime( new Date() )) {
- // in DST
- if( TZ.inDaylightTime( new Date( t ))) {
- // t also in DST so no correction
- } else {
- // t not in DST so subtract 1 hour
- t -= 3600000;
- }
- } else {
- // not in DST
- if( TZ.inDaylightTime( new Date( t ))) {
- // t is in DST so add 1 hour
- t += 3600000;
- } else {
- // t isn't in DST either
- }
- }
- }
-*/
t = (t + MILLISECONDS_BETWEEN_1970_AND_1601) * 10000L;
}
-
writeInt8( t, dst, dstIndex );
}
static long readUTime( byte[] buffer, int bufferIndex ) {
writeInt4( (int)(t / 1000L), dst, dstIndex );
}
-
/*
* These are all the smbs supported by this library. This includes requests
* and well as their responses for each type however the actuall implementations
batchLevel = 0;
}
+ void reset() {
+ }
int writeString( String str, byte[] dst, int dstIndex ) {
return writeString( str, dst, dstIndex, useUnicode );
}
}
return len;
}
- int writeWireFormat( byte[] dst, int dstIndex ) {
+ int encode( byte[] dst, int dstIndex ) {
int start = headerStart = dstIndex;
dstIndex += writeHeaderWireFormat( dst, dstIndex );
return length;
}
- int readWireFormat( InputStream in,
- byte[] buffer,
- int bufferIndex )
- throws IOException {
-
+ int decode( byte[] buffer, int bufferIndex ) {
int start = headerStart = bufferIndex;
- /*
- * read header
- */
-
- if( in.read( buffer, bufferIndex, HEADER_LENGTH ) != HEADER_LENGTH ) {
- throw new IOException( "unexpected EOF reading smb header" );
- }
bufferIndex += readHeaderWireFormat( buffer, bufferIndex );
- /*
- * read wordCount
- */
-
- if(( wordCount = in.read() ) == -1 ) {
- throw new IOException( "unexpected EOF reading smb wordCount" );
- }
- buffer[bufferIndex++] = (byte)( wordCount & 0xFF );
-
- /*
- * read parameter words
- */
-
+ wordCount = buffer[bufferIndex++];
if( wordCount != 0 ) {
- if( in.read( buffer, bufferIndex, wordCount * 2 ) != wordCount * 2 ) {
- throw new IOException( "unexpected EOF reading smb parameter words" );
- }
int n;
if(( n = readParameterWordsWireFormat( buffer, bufferIndex )) != wordCount * 2 ) {
if( log.level > 2 ) {
bufferIndex += wordCount * 2;
}
- /*
- * read byteCount
- */
-
- if( in.read( buffer, bufferIndex, 2 ) != 2 ) {
- throw new IOException( "unexpected EOF reading smb byteCount" );
- }
byteCount = readInt2( buffer, bufferIndex );
bufferIndex += 2;
- /*
- * read bytes
- */
-
if( byteCount != 0 ) {
- if( in.read( buffer, bufferIndex, byteCount ) != byteCount ) {
- throw new IOException( "unexpected EOF reading smb" );
- }
int n;
if(( n = readBytesWireFormat( buffer, bufferIndex )) != byteCount ) {
if( log.level > 2 ) {
writeInt2( mid, dst, dstIndex + 6 );
return HEADER_LENGTH;
}
- int readHeaderWireFormat( byte[] buffer, int bufferIndex ) throws IOException {
+ int readHeaderWireFormat( byte[] buffer, int bufferIndex ) {
command = buffer[bufferIndex + CMD_OFFSET];
errorCode = readInt4( buffer, bufferIndex + ERROR_CODE_OFFSET );
flags = buffer[bufferIndex + FLAGS_OFFSET];
abstract int writeParameterWordsWireFormat( byte[] dst, int dstIndex );
abstract int writeBytesWireFormat( byte[] dst, int dstIndex );
- abstract int readParameterWordsWireFormat( byte[] buffer,
- int bufferIndex )
- throws IOException;
- abstract int readBytesWireFormat( byte[] buffer,
- int bufferIndex )
- throws IOException;
+ abstract int readParameterWordsWireFormat( byte[] buffer, int bufferIndex );
+ abstract int readBytesWireFormat( byte[] buffer, int bufferIndex );
+ public int hashCode() {
+ return mid;
+ }
+ public boolean equals( Object obj ) {
+ return obj instanceof ServerMessageBlock && ((ServerMessageBlock)obj).mid == mid;
+ }
public String toString() {
String c;
switch( command ) {
package jcifs.smb;
-import java.io.IOException;
-import java.io.InputStream;
-
class SmbComLogoffAndX extends AndXServerMessageBlock {
SmbComLogoffAndX( ServerMessageBlock andx ) {
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComLogoffAndX[" +
super.toString() + "]" );
package jcifs.smb;
-import java.io.IOException;
-import java.io.InputStream;
import jcifs.util.Hexdump;
class SmbComNTCreateAndX extends AndXServerMessageBlock {
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComNTCreateAndX[" +
super.toString() +
package jcifs.smb;
import java.util.Date;
-import java.io.IOException;
-import java.io.InputStream;
import jcifs.util.Hexdump;
class SmbComNTCreateAndXResponse extends AndXServerMessageBlock {
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComNTCreateAndXResponse[" +
super.toString() +
SmbComNegotiate() {
command = SMB_COM_NEGOTIATE;
+ flags2 = DEFAULT_FLAGS2;
}
int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
class SmbComNegotiateResponse extends ServerMessageBlock {
- int dialectIndex,
- securityMode,
- security,
- maxMpxCount,
- maxNumberVcs,
- maxBufferSize,
- maxRawSize,
- sessionKey,
- capabilities,
- serverTimeZone,
- encryptionKeyLength;
- boolean encryptedPasswords,
- signaturesEnabled,
- signaturesRequired;
- long serverTime;
- byte[] encryptionKey;
- String oemDomainName;
+ int dialectIndex;
+ SmbTransport.ServerData server;
- SmbComNegotiateResponse() {
+ SmbComNegotiateResponse( SmbTransport.ServerData server ) {
+ this.server = server;
}
int writeParameterWordsWireFormat( byte[] dst, int dstIndex ) {
int readParameterWordsWireFormat( byte[] buffer,
int bufferIndex ) {
int start = bufferIndex;
- dialectIndex = readInt2( buffer, bufferIndex );
- bufferIndex += 2;
+
+ dialectIndex = readInt2( buffer, bufferIndex ); bufferIndex += 2;
if( dialectIndex > 10 ) {
return bufferIndex - start;
}
- securityMode = buffer[bufferIndex++] & 0xFF;
- security = securityMode & 0x01;
- encryptedPasswords = ( securityMode & 0x02 ) == 0x02 ? true : false;
- signaturesEnabled = ( securityMode & 0x04 ) == 0x04 ? true : false;
- signaturesRequired = ( securityMode & 0x08 ) == 0x08 ? true : false;
- maxMpxCount = readInt2( buffer, bufferIndex );
- bufferIndex += 2;
- maxNumberVcs = readInt2( buffer, bufferIndex );
- bufferIndex += 2;
- maxBufferSize = readInt4( buffer, bufferIndex );
- bufferIndex += 4;
- maxRawSize = readInt4( buffer, bufferIndex );
- bufferIndex += 4;
- sessionKey = readInt4( buffer, bufferIndex );
- bufferIndex += 4;
- capabilities = readInt4( buffer, bufferIndex );
- bufferIndex += 4;
- serverTime = readTime( buffer, bufferIndex );
- bufferIndex += 8;
- serverTimeZone = readInt2( buffer, bufferIndex );
- bufferIndex += 2;
- encryptionKeyLength = buffer[bufferIndex++] & 0xFF;
+ server.securityMode = buffer[bufferIndex++] & 0xFF;
+ server.security = server.securityMode & 0x01;
+ server.encryptedPasswords = ( server.securityMode & 0x02 ) == 0x02;
+ server.signaturesEnabled = ( server.securityMode & 0x04 ) == 0x04;
+ server.signaturesRequired = ( server.securityMode & 0x08 ) == 0x08;
+ server.maxMpxCount = readInt2( buffer, bufferIndex ); bufferIndex += 2;
+ server.maxNumberVcs = readInt2( buffer, bufferIndex ); bufferIndex += 2;
+ server.maxBufferSize = readInt4( buffer, bufferIndex ); bufferIndex += 4;
+ server.maxRawSize = readInt4( buffer, bufferIndex ); bufferIndex += 4;
+ server.sessionKey = readInt4( buffer, bufferIndex ); bufferIndex += 4;
+ server.capabilities = readInt4( buffer, bufferIndex ); bufferIndex += 4;
+ server.serverTime = readTime( buffer, bufferIndex ); bufferIndex += 8;
+ server.serverTimeZone = readInt2( buffer, bufferIndex ); bufferIndex += 2;
+ server.encryptionKeyLength = buffer[bufferIndex++] & 0xFF;
+
return bufferIndex - start;
}
int readBytesWireFormat( byte[] buffer,
int bufferIndex ) {
int start = bufferIndex;
- encryptionKey = new byte[encryptionKeyLength];
- System.arraycopy( buffer, bufferIndex,
- encryptionKey, 0, encryptionKeyLength );
- bufferIndex += encryptionKeyLength;
- if( byteCount > encryptionKeyLength ) {
+ server.encryptionKey = new byte[server.encryptionKeyLength];
+ System.arraycopy( buffer, bufferIndex,
+ server.encryptionKey, 0, server.encryptionKeyLength );
+ bufferIndex += server.encryptionKeyLength;
+ if( byteCount > server.encryptionKeyLength ) {
int len = 0;
- if(( flags2 & FLAGS2_UNICODE ) == FLAGS2_UNICODE ) {
- while( buffer[bufferIndex + len] != (byte)0x00 ||
- buffer[bufferIndex + len + 1] != (byte)0x00 ) {
- len += 2;
- if( len > 256 ) {
- throw new RuntimeException( "zero termination not found" );
+ try {
+ if(( flags2 & FLAGS2_UNICODE ) == FLAGS2_UNICODE ) {
+ while( buffer[bufferIndex + len] != (byte)0x00 ||
+ buffer[bufferIndex + len + 1] != (byte)0x00 ) {
+ len += 2;
+ if( len > 256 ) {
+ throw new RuntimeException( "zero termination not found" );
+ }
}
- }
- try {
- oemDomainName = new String( buffer, bufferIndex, len, "UnicodeLittle" );
- } catch( UnsupportedEncodingException uee ) {
- if( log.level > 1 )
- uee.printStackTrace( log );
- }
- } else {
- while( buffer[bufferIndex + len] != (byte)0x00 ) {
- len++;
- if( len > 256 ) {
- throw new RuntimeException( "zero termination not found" );
+ server.oemDomainName = new String( buffer, bufferIndex,
+ len, "UnicodeLittle" );
+ } else {
+ while( buffer[bufferIndex + len] != (byte)0x00 ) {
+ len++;
+ if( len > 256 ) {
+ throw new RuntimeException( "zero termination not found" );
+ }
}
+ server.oemDomainName = new String( buffer, bufferIndex,
+ len, ServerMessageBlock.OEM_ENCODING );
}
- try {
- oemDomainName = new String( buffer, bufferIndex, len, ServerMessageBlock.OEM_ENCODING );
- } catch( UnsupportedEncodingException uee ) {
- }
+ } catch( UnsupportedEncodingException uee ) {
+ if( log.level > 1 )
+ uee.printStackTrace( log );
}
bufferIndex += len;
} else {
- oemDomainName = new String();
+ server.oemDomainName = new String();
}
return bufferIndex - start;
super.toString() +
",wordCount=" + wordCount +
",dialectIndex=" + dialectIndex +
- ",securityMode=0x" + Hexdump.toHexString( securityMode, 1 ) +
- ",security=" + ( security == SECURITY_SHARE ? "share" : "user" ) +
- ",encryptedPasswords=" + encryptedPasswords +
- ",maxMpxCount=" + maxMpxCount +
- ",maxNumberVcs=" + maxNumberVcs +
- ",maxBufferSize=" + maxBufferSize +
- ",maxRawSize=" + maxRawSize +
- ",sessionKey=0x" + Hexdump.toHexString( sessionKey, 8 ) +
- ",capabilities=0x" + Hexdump.toHexString( capabilities, 8 ) +
- ",serverTime=" + new Date( serverTime ) +
- ",serverTimeZone=" + serverTimeZone +
- ",encryptionKeyLength=" + encryptionKeyLength +
+ ",securityMode=0x" + Hexdump.toHexString( server.securityMode, 1 ) +
+ ",security=" + ( server.security == SECURITY_SHARE ? "share" : "user" ) +
+ ",encryptedPasswords=" + server.encryptedPasswords +
+ ",maxMpxCount=" + server.maxMpxCount +
+ ",maxNumberVcs=" + server.maxNumberVcs +
+ ",maxBufferSize=" + server.maxBufferSize +
+ ",maxRawSize=" + server.maxRawSize +
+ ",sessionKey=0x" + Hexdump.toHexString( server.sessionKey, 8 ) +
+ ",capabilities=0x" + Hexdump.toHexString( server.capabilities, 8 ) +
+ ",serverTime=" + new Date( server.serverTime ) +
+ ",serverTimeZone=" + server.serverTimeZone +
+ ",encryptionKeyLength=" + server.encryptionKeyLength +
",byteCount=" + byteCount +
- ",encryptionKey=0x" + Hexdump.toHexString( encryptionKey,
+ ",encryptionKey=0x" + Hexdump.toHexString( server.encryptionKey,
0,
- encryptionKeyLength * 2 ) +
- ",oemDomainName=" + oemDomainName + "]" );
+ server.encryptionKeyLength * 2 ) +
+ ",oemDomainName=" + server.oemDomainName + "]" );
}
}
+
package jcifs.smb;
import java.util.Date;
-import java.io.IOException;
-import java.io.InputStream;
import jcifs.Config;
import jcifs.util.Hexdump;
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComOpenAndX[" +
super.toString() +
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComOpenAndXResponse[" +
super.toString() +
package jcifs.smb;
import jcifs.Config;
-import java.io.InputStream;
-import java.io.IOException;
class SmbComReadAndX extends AndXServerMessageBlock {
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComReadAndX[" +
super.toString() +
package jcifs.smb;
-import java.io.IOException;
-import java.io.InputStream;
-
class SmbComReadAndXResponse extends AndXServerMessageBlock {
- private int dataCompactionMode, dataOffset;
-
byte[] b;
- int dataLength, off;
+ int off, dataCompactionMode, dataLength, dataOffset;
SmbComReadAndXResponse() {
}
return bufferIndex - start;
}
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
+ // handled special in SmbTransport.doRecv()
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- int pad = dataOffset - ( HEADER_LENGTH + 3 + wordCount * 2 );
- in.read( buffer, bufferIndex, pad ); /* needed for signing */
- in.read( b, off, dataLength );
- return pad + dataLength;
- }
public String toString() {
return new String( "SmbComReadAndXResponse[" +
super.toString() +
package jcifs.smb;
import jcifs.Config;
-import java.io.IOException;
-import java.io.InputStream;
class SmbComSessionSetupAndX extends AndXServerMessageBlock {
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
String result = new String( "SmbComSessionSetupAndX[" +
super.toString() +
package jcifs.smb;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-import jcifs.util.Hexdump;
-
class SmbComSessionSetupAndXResponse extends AndXServerMessageBlock {
private String nativeOs = "";
while( buffer[bufferIndex + len] != (byte)0x00 ) {
len += 2;
if( len > 256 ) {
-Hexdump.hexdump( System.err, buffer, 0, 256 );
throw new RuntimeException( "zero termination not found" );
}
}
return bufferIndex - start;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
String result = new String( "SmbComSessionSetupAndXResponse[" +
super.toString() +
txn_buf = null;
}
- public void reset() {
+ void reset() {
bufDataStart = 0;
isPrimary = hasMore = true;
parametersDone = dataDone = false;
+ received = false;
}
public boolean hasMoreElements() {
- return hasMore;
+ return errorCode == 0 && hasMore;
}
public Object nextElement() {
if( isPrimary ) {
parametersDone = true;
}
- if( !dataDone &&
- ( dataDisplacement + dataCount ) == totalDataCount) {
+ if( !dataDone && ( dataDisplacement + dataCount ) == totalDataCount) {
dataDone = true;
}
package jcifs.smb;
import jcifs.Config;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import jcifs.util.Hexdump;
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
String result = new String( "SmbComTreeConnectAndX[" +
super.toString() +
package jcifs.smb;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.UnsupportedEncodingException;
class SmbComTreeConnectAndXResponse extends AndXServerMessageBlock {
return bufferIndex - start;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
String result = new String( "SmbComTreeConnectAndXResponse[" +
super.toString() +
package jcifs.smb;
import jcifs.Config;
-import java.io.IOException;
-import java.io.InputStream;
class SmbComWrite extends ServerMessageBlock {
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComWrite[" +
super.toString() +
package jcifs.smb;
import jcifs.Config;
-import java.io.IOException;
-import java.io.InputStream;
class SmbComWriteAndX extends AndXServerMessageBlock {
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComWriteAndX[" +
super.toString() +
package jcifs.smb;
-import java.io.IOException;
-import java.io.InputStream;
-
class SmbComWriteAndXResponse extends AndXServerMessageBlock {
long count;
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount,
- byte[] buffer, int bufferIndex ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComWriteAndXResponse[" +
super.toString() +
package jcifs.smb;
-import java.io.IOException;
-import java.io.InputStream;
-
class SmbComWriteResponse extends ServerMessageBlock {
long count;
int readBytesWireFormat( byte[] buffer, int bufferIndex ) {
return 0;
}
- int readBytesDirectWireFormat( InputStream in, int byteCount ) throws IOException {
- return 0;
- }
public String toString() {
return new String( "SmbComWriteResponse[" +
super.toString() +
--- /dev/null
+package jcifs.smb;
+
+import java.util.LinkedList;
+import java.net.InetAddress;
+import java.util.TimeZone;
+import jcifs.Config;
+
+interface SmbConstants {
+
+ static final int DEFAULT_PORT = 445;
+
+ static final int DEFAULT_MAX_MPX_COUNT = 10;
+ static final int DEFAULT_RESPONSE_TIMEOUT = 10000;
+ static final int DEFAULT_SO_TIMEOUT = 15000;
+ static final int DEFAULT_RCV_BUF_SIZE = 60416;
+ static final int DEFAULT_SND_BUF_SIZE = 16644;
+ static final int DEFAULT_SSN_LIMIT = 250;
+
+ static final InetAddress LADDR = Config.getLocalHost();
+ static final int LPORT = Config.getInt( "jcifs.smb.client.lport", 0 );
+ static final int MAX_MPX_COUNT = Config.getInt( "jcifs.smb.client.maxMpxCount", DEFAULT_MAX_MPX_COUNT );
+ static final int SND_BUF_SIZE = Config.getInt( "jcifs.smb.client.snd_buf_size", DEFAULT_SND_BUF_SIZE );
+ static final int RCV_BUF_SIZE = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
+ static final boolean USE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", true );
+ static final boolean FORCE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", false );
+ static final boolean USE_NTSTATUS = Config.getBoolean( "jcifs.smb.client.useNtStatus", true );
+ static final boolean SIGNPREF = Config.getBoolean("jcifs.smb.client.signingPreferred", false );
+ static final boolean USE_NTSMBS = Config.getBoolean( "jcifs.smb.client.useNTSmbs", true );
+ static final boolean USE_EXTSEC = Config.getBoolean( "jcifs.smb.client.useExtendedSecurity", false );
+
+ static final int FLAGS_NONE = 0x00;
+ static final int FLAGS_LOCK_AND_READ_WRITE_AND_UNLOCK = 0x01;
+ static final int FLAGS_RECEIVE_BUFFER_POSTED = 0x02;
+ static final int FLAGS_PATH_NAMES_CASELESS = 0x08;
+ static final int FLAGS_PATH_NAMES_CANONICALIZED = 0x10;
+ static final int FLAGS_OPLOCK_REQUESTED_OR_GRANTED = 0x20;
+ static final int FLAGS_NOTIFY_OF_MODIFY_ACTION = 0x40;
+ static final int FLAGS_RESPONSE = 0x80;
+
+ static final int FLAGS2_NONE = 0x0000;
+ static final int FLAGS2_LONG_FILENAMES = 0x0001;
+ static final int FLAGS2_EXTENDED_ATTRIBUTES = 0x0002;
+ static final int FLAGS2_SECURITY_SIGNATURES = 0x0004;
+ static final int FLAGS2_EXTENDED_SECURITY_NEGOTIATION = 0x0800;
+ static final int FLAGS2_RESOLVE_PATHS_IN_DFS = 0x1000;
+ static final int FLAGS2_PERMIT_READ_IF_EXECUTE_PERM = 0x2000;
+ static final int FLAGS2_STATUS32 = 0x4000;
+ static final int FLAGS2_UNICODE = 0x8000;
+
+ static final int CAP_NONE = 0x0000;
+ static final int CAP_RAW_MODE = 0x0001;
+ static final int CAP_MPX_MODE = 0x0002;
+ static final int CAP_UNICODE = 0x0004;
+ static final int CAP_LARGE_FILES = 0x0008;
+ static final int CAP_NT_SMBS = 0x0010;
+ static final int CAP_RPC_REMOTE_APIS = 0x0020;
+ static final int CAP_STATUS32 = 0x0040;
+ static final int CAP_LEVEL_II_OPLOCKS = 0x0080;
+ static final int CAP_LOCK_AND_READ = 0x0100;
+ static final int CAP_NT_FIND = 0x0200;
+ static final int CAP_DFS = 0x1000;
+
+ // file attribute encoding
+ static final int ATTR_READONLY = 0x01;
+ static final int ATTR_HIDDEN = 0x02;
+ static final int ATTR_SYSTEM = 0x04;
+ static final int ATTR_VOLUME = 0x08;
+ static final int ATTR_DIRECTORY = 0x10;
+ static final int ATTR_ARCHIVE = 0x20;
+
+ // extended file attribute encoding(others same as above)
+ static final int ATTR_COMPRESSED = 0x800;
+ static final int ATTR_NORMAL = 0x080;
+ static final int ATTR_TEMPORARY = 0x100;
+
+ // flags for move and copy
+ static final int FLAGS_TARGET_MUST_BE_FILE = 0x0001;
+ static final int FLAGS_TARGET_MUST_BE_DIRECTORY = 0x0002;
+ static final int FLAGS_COPY_TARGET_MODE_ASCII = 0x0004;
+ static final int FLAGS_COPY_SOURCE_MODE_ASCII = 0x0008;
+ static final int FLAGS_VERIFY_ALL_WRITES = 0x0010;
+ static final int FLAGS_TREE_COPY = 0x0020;
+
+ // open function
+ static final int OPEN_FUNCTION_FAIL_IF_EXISTS = 0x0000;
+ static final int OPEN_FUNCTION_OVERWRITE_IF_EXISTS = 0x0020;
+
+ static final int PID = (int)( Math.random() * 65536d );
+
+ static final int SECURITY_SHARE = 0x00;
+ static final int SECURITY_USER = 0x01;
+
+ static final int CMD_OFFSET = 4;
+ static final int ERROR_CODE_OFFSET = 5;
+ static final int FLAGS_OFFSET = 9;
+ static final int SIGNATURE_OFFSET = 14;
+ static final int TID_OFFSET = 24;
+ static final int HEADER_LENGTH = 32;
+
+ static final long MILLISECONDS_BETWEEN_1970_AND_1601 = 11644473600000L;
+ static final TimeZone TZ = TimeZone.getDefault();
+
+ static final boolean USE_BATCHING = Config.getBoolean( "jcifs.smb.client.useBatching", true );
+ static final String OEM_ENCODING =
+ Config.getProperty( "jcifs.encoding",
+ System.getProperty( "file.encoding" ));
+ static final int DEFAULT_FLAGS2 =
+ FLAGS2_LONG_FILENAMES |
+ FLAGS2_EXTENDED_ATTRIBUTES |
+ ( USE_EXTSEC ? FLAGS2_EXTENDED_SECURITY_NEGOTIATION : 0 ) |
+ ( SIGNPREF ? FLAGS2_SECURITY_SIGNATURES : 0 ) |
+ ( USE_NTSTATUS ? FLAGS2_STATUS32 : 0 ) |
+ ( USE_UNICODE ? FLAGS2_UNICODE : 0 );
+ static final int DEFAULT_CAPABILITIES =
+ ( USE_NTSMBS ? CAP_NT_SMBS : 0 ) |
+ ( USE_NTSTATUS ? CAP_STATUS32 : 0 ) |
+ ( USE_UNICODE ? CAP_UNICODE : 0 ) |
+ CAP_DFS;
+ static final int FLAGS2 = Config.getInt( "jcifs.smb.client.flags2", DEFAULT_FLAGS2 );
+ static final int CAPABILITIES = Config.getInt( "jcifs.smb.client.capabilities", DEFAULT_CAPABILITIES );
+ static final boolean TCP_NODELAY = Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false );
+ static final int RESPONSE_TIMEOUT =
+ Config.getInt( "jcifs.smb.client.responseTimeout", DEFAULT_RESPONSE_TIMEOUT );
+
+ static final LinkedList CONNECTIONS = new LinkedList();
+
+ static final int SSN_LIMIT =
+ Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT );
+ static final int SO_TIMEOUT =
+ Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT );
+ static final String NATIVE_OS =
+ Config.getProperty( "jcifs.smb.client.nativeOs", System.getProperty( "os.name" ));
+ static final String NATIVE_LANMAN =
+ Config.getProperty( "jcifs.smb.client.nativeLanMan", "jCIFS" );
+ static final int VC_NUMBER = 1;
+ static final SmbTransport NULL_TRANSPORT = new SmbTransport( null, 0, null, 0 );
+}
}
return blank_resp;
}
- void sendTransaction( SmbComTransaction request,
- SmbComTransactionResponse response ) throws SmbException {
+ void send( ServerMessageBlock request,
+ ServerMessageBlock response ) throws SmbException {
for( ;; ) {
connect0();
if( tree.inDfs ) {
throw new SmbException( dr.server, uhe );
}
- trans = SmbTransport.getSmbTransport( addr, 0 );
+ trans = SmbTransport.getSmbTransport( addr, url.getPort() );
tree = trans.getSmbSession( auth ).getSmbTree( dr.share, null );
- unc = dr.nodepath + unc.substring( dr.path.length() );
+ unc = request.path = dr.nodepath + unc.substring( dr.path.length() );
if( request.path.charAt( request.path.length() - 1 ) == '\\' ) {
request.path = unc + '\\';
} else {
}
dfsReferral = dr; /* for getDfsPath */
}
- }
- if( tree.inDfs ) {
- request.flags2 |= ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS;
- } else {
- request.flags2 &= ~ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS;
- }
- try {
- tree.sendTransaction( request, response );
- break;
- } catch( DfsReferral dr ) {
- if( dr.resolveHashes ) {
- throw dr;
- }
- request.reset();
- }
- }
- }
- void send( ServerMessageBlock request,
- ServerMessageBlock response ) throws SmbException {
- for( ;; ) {
- connect0();
- if( tree.inDfs ) {
- DfsReferral dr = tree.session.transport.lookupReferral( unc );
- if( dr != null ) {
- UniAddress addr;
- SmbTransport trans;
-
- try {
- addr = UniAddress.getByName( dr.server );
- } catch( UnknownHostException uhe ) {
- throw new SmbException( dr.server, uhe );
- }
-
- trans = SmbTransport.getSmbTransport( addr, url.getPort() );
- tree = trans.getSmbSession( auth ).getSmbTree( dr.share, null );
- unc = request.path = dr.nodepath + unc.substring( dr.path.length() );
- dfsReferral = dr; /* for getDfsPath */
- }
request.flags2 |= ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS;
} else {
request.flags2 &= ~ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS;
if( dr.resolveHashes ) {
throw dr;
}
+ request.reset();
}
}
}
Trans2QueryPathInformationResponse response =
new Trans2QueryPathInformationResponse( infoLevel );
- sendTransaction( new Trans2QueryPathInformation( path,
- infoLevel ), response );
+ send( new Trans2QueryPathInformation( path, infoLevel ), response );
return response.info;
} else {
do {
int n;
- sendTransaction( req, resp );
+ send( req, resp );
more = resp.status == SmbException.ERROR_MORE_DATA;
if( log.level > 2 )
log.println( "doFindFirstNext: " + req.path );
- sendTransaction( req, resp );
+ send( req, resp );
sid = resp.sid;
req = new Trans2FindNext2( sid, resp.resumeKey, resp.lastName );
req.reset( resp.resumeKey, resp.lastName );
resp.reset();
- sendTransaction( req, resp );
+ send( req, resp );
}
send( new SmbComFindClose2( sid ), blank_resp() );
off += resp.dataLength;
}
- dest.sendTransaction( new Trans2SetFileInformation(
+ dest.send( new Trans2SetFileInformation(
dest.fid, attributes, createTime, lastModified ),
new Trans2SetFileInformationResponse() );
dest.close( 0L );
int level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION;
response = new Trans2QueryFSInformationResponse( level );
- sendTransaction( new Trans2QueryFSInformation( level ), response );
+ send( new Trans2QueryFSInformation( level ), response );
size = response.info.getCapacity();
} else if( getUncPath0().length() > 1 && type != TYPE_NAMED_PIPE ) {
*/
public long getDiskFreeSpace() throws SmbException {
if( getType() == TYPE_SHARE || type == TYPE_FILESYSTEM ) {
- Trans2QueryFSInformationResponse response;
- int level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION;
+ int level = Trans2QueryFSInformationResponse.SMB_FS_FULL_SIZE_INFORMATION;
+ try {
+ return queryFSInformation(level);
+ } catch( SmbException ex ) {
+ if(ex.getNtStatus() == NtStatus.NT_STATUS_INVALID_INFO_CLASS) {
+ // SMB_FS_FULL_SIZE_INFORMATION not supported by the server.
+ level = Trans2QueryFSInformationResponse.SMB_INFO_ALLOCATION;
+ return queryFSInformation(level);
+ }
+ throw ex;
+ }
+ }
+ return 0L;
+ }
- response = new Trans2QueryFSInformationResponse( level );
- sendTransaction( new Trans2QueryFSInformation( level ), response );
+ private long queryFSInformation( int level ) throws SmbException {
+ Trans2QueryFSInformationResponse response;
- if( type == TYPE_SHARE ) {
- size = response.info.getCapacity();
- sizeExpiration = System.currentTimeMillis() + attrExpirationPeriod;
- }
+ response = new Trans2QueryFSInformationResponse( level );
+ send( new Trans2QueryFSInformation( level ), response );
- return response.info.getFree();
+ if( type == TYPE_SHARE ) {
+ size = response.info.getCapacity();
+ sizeExpiration = System.currentTimeMillis() + attrExpirationPeriod;
}
- return 0L;
+
+ return response.info.getFree();
}
/**
}
f = open0( O_RDONLY | SmbComNTCreateAndX.FILE_WRITE_ATTRIBUTES << 16, attrs, options );
- sendTransaction( new Trans2SetFileInformation( f, attrs, ctime, mtime ),
+ send( new Trans2SetFileInformation( f, attrs, ctime, mtime ),
new Trans2SetFileInformationResponse() );
close( f, 0L );
SmbFileInputStream( SmbFile file, int openFlags ) throws SmbException, MalformedURLException, UnknownHostException {
this.file = file;
this.openFlags = openFlags;
- file.open( openFlags, SmbFile.ATTR_NORMAL, 0 );
+ if (file.type != SmbFile.TYPE_NAMED_PIPE) {
+ file.open( openFlags, SmbFile.ATTR_NORMAL, 0 );
+ } else {
+ file.connect0();
+ }
readSize = Math.min( file.tree.session.transport.rcv_buf_size - 70,
file.tree.session.transport.server.maxBufferSize - 70 );
}
req = new TransPeekNamedPipe( file.unc, file.fid );
resp = new TransPeekNamedPipeResponse( pipe );
- pipe.sendTransaction( req, resp );
+ pipe.send( req, resp );
if( resp.status == TransPeekNamedPipeResponse.STATUS_DISCONNECTED ||
resp.status == TransPeekNamedPipeResponse.STATUS_SERVER_END_CLOSED ) {
file.opened = false;
}
if( file instanceof SmbNamedPipe && file.unc.startsWith( "\\pipe\\" )) {
file.unc = file.unc.substring( 5 );
- file.sendTransaction( new TransWaitNamedPipe( "\\pipe" + file.unc ),
+ file.send( new TransWaitNamedPipe( "\\pipe" + file.unc ),
new TransWaitNamedPipeResponse() );
}
file.open( openFlags, SmbFile.ATTR_NORMAL, 0 );
- this.openFlags &= ~(SmbFile.O_CREAT | SmbFile.O_TRUNC); /* in case close and reopen */
writeSize = file.tree.session.transport.snd_buf_size - 70;
useNTSmbs = file.tree.session.transport.hasCapability( ServerMessageBlock.CAP_NT_SMBS );
// ensure file is open
if( file.isOpen() == false ) {
if( file instanceof SmbNamedPipe ) {
- file.sendTransaction( new TransWaitNamedPipe( "\\pipe" + file.unc ),
+ file.send( new TransWaitNamedPipe( "\\pipe" + file.unc ),
new TransWaitNamedPipeResponse() );
}
file.open( openFlags, SmbFile.ATTR_NORMAL, 0 );
UniAddress dc = new UniAddress( addr );
SmbTransport trans = SmbTransport.getSmbTransport( dc, 0 );
if (USERNAME == null) {
- trans.negotiate();
+ trans.connect();
if (SmbTransport.log.level > 2)
SmbTransport.log.println(
"Default credentials (jcifs.smb.client.username/password)" +
public static byte[] getChallenge( UniAddress dc, int port )
throws SmbException, UnknownHostException {
SmbTransport trans = SmbTransport.getSmbTransport( dc, port );
- trans.negotiate();
+ trans.connect();
return trans.server.encryptionKey;
}
/**
} else {
Trans2FindFirst2 req = new Trans2FindFirst2( "\\", "*", SmbFile.ATTR_DIRECTORY );
Trans2FindFirst2Response resp = new Trans2FindFirst2Response();
- tree.sendTransaction( req, resp );
+ tree.send( req, resp );
}
}
}
return transport;
}
- void sendTransaction( SmbComTransaction request,
- SmbComTransactionResponse response ) throws SmbException {
- // transactions are not batchable
- sessionSetup( null, null );
- request.uid = uid;
- request.auth = auth;
- transport().sendTransaction( request, response );
- }
void send( ServerMessageBlock request,
ServerMessageBlock response ) throws SmbException {
if( response != null ) {
void sessionSetup( ServerMessageBlock andx,
ServerMessageBlock andxResponse ) throws SmbException {
- expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT;
-
synchronized( transport() ) {
if( sessionSetup ) {
return;
}
- transport.negotiate();
+ expiration = System.currentTimeMillis() + SmbTransport.SO_TIMEOUT;
+
+ transport.connect();
/*
* Session Setup And X Request / Response
t.treeDisconnect( inError );
}
- if( transport.server.security == ServerMessageBlock.SECURITY_SHARE ) {
- return;
- }
-
- if( !inError ) {
+ if( !inError && transport.server.security != ServerMessageBlock.SECURITY_SHARE ) {
/*
* Logoff And X Request / Response
} catch( SmbException se ) {
}
}
+
sessionSetup = false;
} finally {
transport = SmbTransport.NULL_TRANSPORT;
/* jcifs smb client library in Java
- * Copyright (C) 2000 "Michael B. Allen" <jcifs at samba dot org>
+ * Copyright (C) 2005 "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
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.security.MessageDigest;
-
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.Enumeration;
-import java.util.HashMap;
-
-import jcifs.util.LogStream;
-import jcifs.util.Hexdump;
-
-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 DEFAULT_RCV_BUF_SIZE = 60416;
- private static final int DEFAULT_SND_BUF_SIZE = 16644;
- private static final int DEFAULT_SSN_LIMIT = 250;
-
- private static final InetAddress LADDR = Config.getInetAddress( "jcifs.smb.client.laddr", null );
- private static final int LPORT = Config.getInt( "jcifs.smb.client.lport", 0 );
- private static final int MAX_MPX_COUNT = Config.getInt( "jcifs.smb.client.maxMpxCount", DEFAULT_MAX_MPX_COUNT );
- private static final int SND_BUF_SIZE = Config.getInt( "jcifs.smb.client.snd_buf_size", DEFAULT_SND_BUF_SIZE );
- private static final int RCV_BUF_SIZE = Config.getInt( "jcifs.smb.client.rcv_buf_size", DEFAULT_RCV_BUF_SIZE );
- private static final boolean USE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", true );
- private static final boolean FORCE_UNICODE = Config.getBoolean( "jcifs.smb.client.useUnicode", false );
- private static final boolean USE_NTSTATUS = Config.getBoolean( "jcifs.smb.client.useNtStatus", true );
- private static final boolean SIGNPREF = Config.getBoolean("jcifs.smb.client.signingPreferred", false );
- private static final boolean USE_NTSMBS = Config.getBoolean( "jcifs.smb.client.useNTSmbs", true );
- private static final int DEFAULT_FLAGS2 =
- ServerMessageBlock.FLAGS2_LONG_FILENAMES |
- ServerMessageBlock.FLAGS2_EXTENDED_ATTRIBUTES |
- ( SIGNPREF ? ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES : 0 ) |
- ( USE_NTSTATUS ? ServerMessageBlock.FLAGS2_STATUS32 : 0 ) |
- ( USE_UNICODE ? ServerMessageBlock.FLAGS2_UNICODE : 0 );
- private static final int DEFAULT_CAPABILITIES =
- ( USE_NTSMBS ? ServerMessageBlock.CAP_NT_SMBS : 0 ) |
- ( USE_NTSTATUS ? ServerMessageBlock.CAP_STATUS32 : 0 ) |
- ( USE_UNICODE ? ServerMessageBlock.CAP_UNICODE : 0 ) |
- ServerMessageBlock.CAP_DFS;
- private static final int FLAGS2 = Config.getInt( "jcifs.smb.client.flags2", DEFAULT_FLAGS2 );
- private static final int CAPABILITIES = Config.getInt( "jcifs.smb.client.capabilities", DEFAULT_CAPABILITIES );
- private static final boolean TCP_NODELAY = Config.getBoolean( "jcifs.smb.client.tcpNoDelay", false );
- private static final int RESPONSE_TIMEOUT =
- Config.getInt( "jcifs.smb.client.responseTimeout", DEFAULT_RESPONSE_TIMEOUT );
-
- private static final int PUSHBACK_BUF_SIZE = 64;
- private static final int MID_OFFSET = 30;
- private static final int FLAGS_RESPONSE = 0x80;
- private static final LinkedList CONNECTIONS = new LinkedList();
- private static final int MAGIC[] = { 0xFF, 'S', 'M', 'B' };
-
- private static final int ST_GROUND = 0;
- private static final int ST_NEGOTIATING = 1;
- private static final int ST_NEGOTIATED = 2;
-
-private static byte[] snd_buf = new byte[0xFFFF];
-private static byte[] rcv_buf = new byte[0xFFFF];
-
- private int state;
- private NbtSocket socket;
- private HashMap responseTable;
- private InputStream in;
- private OutputStream out;
- private int localPort;
- private InetAddress localAddr;
- private Thread thread;
- private Object outLock;
- private UniAddress address;
- private int port;
- private LinkedList referrals = new LinkedList();
- private Mid[] mids = new Mid[MAX_MPX_COUNT];
- private short mid_next;
- private IOException socketException;
- private long sessionExpiration = System.currentTimeMillis() + SO_TIMEOUT;
-
- static final int SSN_LIMIT =
- Config.getInt( "jcifs.smb.client.ssnLimit", DEFAULT_SSN_LIMIT );
- static final int SO_TIMEOUT =
- Config.getInt( "jcifs.smb.client.soTimeout", DEFAULT_SO_TIMEOUT );
- static final String NATIVE_OS =
- Config.getProperty( "jcifs.smb.client.nativeOs", System.getProperty( "os.name" ));
- static final String NATIVE_LANMAN =
- Config.getProperty( "jcifs.smb.client.nativeLanMan", "jCIFS" );
- static final int VC_NUMBER = 1;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+import jcifs.*;
+import jcifs.netbios.*;
+import jcifs.util.*;
+import jcifs.util.transport.*;
+
+public class SmbTransport extends Transport implements SmbConstants {
+
+ static final byte[] BUF = new byte[0xFFFF];
+ static final SmbComNegotiate NEGOTIATE_REQUEST = new SmbComNegotiate();
static LogStream log = LogStream.getInstance();
- static final SmbTransport NULL_TRANSPORT = new SmbTransport();
- class Mid {
- short mid;
+ static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
+ return getSmbTransport( address, port, LADDR, LPORT );
+ }
+ static synchronized SmbTransport getSmbTransport( UniAddress address, int port,
+ InetAddress localAddr, int localPort ) {
+ SmbTransport conn;
- public int hashCode() {
- return mid;
- }
- public boolean equals( Object obj ) {
- return ((Mid)obj).mid == mid;
+ synchronized( CONNECTIONS ) {
+ if( SSN_LIMIT != 1 ) {
+ ListIterator iter = CONNECTIONS.listIterator();
+ while( iter.hasNext() ) {
+ conn = (SmbTransport)iter.next();
+ if( conn.matches( address, port, localAddr, localPort ) &&
+ ( SSN_LIMIT == 0 || conn.sessions.size() < SSN_LIMIT )) {
+ return conn;
+ }
+ }
+ }
+
+ conn = new SmbTransport( address, port, localAddr, localPort );
+ CONNECTIONS.add( 0, conn );
}
+
+ return conn;
}
+
class ServerData {
byte flags;
int flags2;
int maxMpxCount;
int maxBufferSize;
int sessionKey;
- // NT 4 Workstation is 0x43FD
int capabilities;
String oemDomainName;
int securityMode;
byte[] encryptionKey;
}
+ InetAddress localAddr;
+ int localPort;
+ UniAddress address;
+ Socket socket;
+ int port, mid;
+ OutputStream out;
+ InputStream in;
+ byte[] sbuf = new byte[255]; /* small local buffer */
+ SmbComBlankResponse key = new SmbComBlankResponse();
+ long sessionExpiration = System.currentTimeMillis() + SO_TIMEOUT;
+ LinkedList referrals = new LinkedList();
+ SigningDigest digest = null;
+ LinkedList sessions = new LinkedList();
+ ServerData server = new ServerData();
+ /* Negotiated values */
int flags2 = FLAGS2;
int maxMpxCount = MAX_MPX_COUNT;
int snd_buf_size = SND_BUF_SIZE;
int sessionKey = 0x00000000;
boolean useUnicode = USE_UNICODE;
String tconHostName;
- ServerData server;
- SigningDigest digest = null;
- LinkedList sessions;
-
- static synchronized SmbTransport getSmbTransport( UniAddress address, int port ) {
- return getSmbTransport( address, port, LADDR, LPORT );
- }
- static synchronized SmbTransport getSmbTransport( UniAddress address, int port,
- InetAddress localAddr, int localPort ) {
- SmbTransport conn;
-
- synchronized( CONNECTIONS ) {
- if( SSN_LIMIT != 1 ) {
- ListIterator iter = CONNECTIONS.listIterator();
- while( iter.hasNext() ) {
- conn = (SmbTransport)iter.next();
- if( conn.matches( address, port, localAddr, localPort ) &&
- ( SSN_LIMIT == 0 || conn.sessions.size() < SSN_LIMIT )) {
- return conn;
- }
- }
- }
-
- conn = new SmbTransport( address, port, localAddr, localPort );
- CONNECTIONS.add( 0, conn );
- }
-
- return conn;
- }
SmbTransport( UniAddress address, int port, InetAddress localAddr, int localPort ) {
this.address = address;
this.port = port;
this.localAddr = localAddr;
this.localPort = localPort;
-
- sessions = new LinkedList();
- responseTable = new HashMap();
- outLock = new Object();
- state = ST_GROUND;
-
- int i;
- for( i = 0; i < MAX_MPX_COUNT; i++ ) {
- mids[i] = new Mid();
- }
- }
- SmbTransport() {
}
synchronized SmbSession getSmbSession() {
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;
+ int p1 = ( port == 0 || port == DEFAULT_PORT ) ? 0 : port;
+ int p2 = ( this.port == 0 || this.port == DEFAULT_PORT ) ? 0 : this.port;
+ InetAddress la1 = localAddr == null ? LADDR : localAddr;
+ InetAddress la2 = this.localAddr == null ? LADDR : this.localAddr;
return address.equals( this.address ) &&
p1 == p2 &&
la1.equals( la2 ) &&
localPort == this.localPort;
}
boolean hasCapability( int cap ) throws SmbException {
- if (state == ST_GROUND) {
- negotiate();
+ try {
+ connect( RESPONSE_TIMEOUT );
+ } catch( IOException ioe ) {
+ throw new SmbException( "", ioe );
}
return (capabilities & cap) == cap;
}
auth != NtlmPasswordAuthentication.NULL &&
NtlmPasswordAuthentication.NULL.equals( auth ) == false;
}
- void tryClose( boolean inError ) {
- SmbSession ssn;
- if( socket == null ) {
- inError = true;
- }
+ void ssn139() throws IOException {
+ Name calledName = new Name( address.firstCalledName(), 0x20, null );
+ do {
+ socket = new Socket( address.getHostAddress(), 139, localAddr, localPort );
+ socket.setSoTimeout( SO_TIMEOUT );
+ out = socket.getOutputStream();
+ in = socket.getInputStream();
+
+ SessionServicePacket ssp = new SessionRequestPacket( calledName,
+ NbtAddress.getLocalName() );
+ out.write( sbuf, 0, ssp.writeWireFormat( sbuf, 0 ));
+ if (readn( in, sbuf, 0, 4 ) < 4) {
+ throw new SmbException( "EOF during NetBIOS session request" );
+ }
+ switch( sbuf[0] & 0xFF ) {
+ case SessionServicePacket.POSITIVE_SESSION_RESPONSE:
+ if( log.level > 2 )
+ log.println( "session established ok with " + address );
+ return;
+ case SessionServicePacket.NEGATIVE_SESSION_RESPONSE:
+ int errorCode = (int)( in.read() & 0xFF );
+ switch (errorCode) {
+ case NbtException.CALLED_NOT_PRESENT:
+ case NbtException.NOT_LISTENING_CALLED:
+ socket.close();
+ break;
+ default:
+ disconnect( true );
+ throw new NbtException( NbtException.ERR_SSN_SRVC, errorCode );
+ }
+ break;
+ case -1:
+ disconnect( true );
+ throw new NbtException( NbtException.ERR_SSN_SRVC,
+ NbtException.CONNECTION_REFUSED );
+ default:
+ disconnect( true );
+ throw new NbtException( NbtException.ERR_SSN_SRVC, 0 );
+ }
+ } while(( calledName.name = address.nextCalledName()) != null );
- ListIterator iter = sessions.listIterator();
- while( iter.hasNext() ) {
- ssn = (SmbSession)iter.next();
- ssn.logoff( inError );
- }
- if( socket != null ) {
- try {
- socket.close();
- } catch( IOException ioe ) {
+ throw new IOException( "Failed to establish session with " + address );
+ }
+ private void negotiate( int port, ServerMessageBlock resp ) throws IOException {
+ /* We cannot use Transport.sendrecv() yet because
+ * the Transport thread is not setup until doConnect()
+ * returns and we want to supress all communication
+ * until we have properly negotiated.
+ */
+ synchronized (sbuf) {
+ if (port == 139) {
+ ssn139();
+ } else {
+ socket = new Socket( address.getHostAddress(), port, localAddr, localPort );
+ socket.setSoTimeout( SO_TIMEOUT );
+ out = socket.getOutputStream();
+ in = socket.getInputStream();
}
+
+ if (++mid == 32000) mid = 1;
+ NEGOTIATE_REQUEST.mid = mid;
+ int n = NEGOTIATE_REQUEST.encode( sbuf, 4 );
+ Encdec.enc_uint32be( n & 0xFFFF, sbuf, 0 ); /* 4 byte ssn msg header */
+ out.write( sbuf, 0, 4 + n );
+ out.flush();
+ /* Note the Transport thread isn't running yet so we can
+ * read from the socket here.
+ */
+ peekKey(); /* try to read header */
+ int size = Encdec.dec_uint16be( sbuf, 2 );
+ if (size < 33 || (4 + size) > sbuf.length ) {
+ throw new IOException( "Invalid payload size: " + size );
+ }
+ readn( in, sbuf, 4 + 32, size - 32 );
+ resp.decode( sbuf, 4 );
}
- digest = null;
- in = null;
- out = null;
- socket = null;
- thread = null;
- responseTable.clear();
- referrals.clear();
- sessions.clear();
- synchronized( CONNECTIONS ) {
- CONNECTIONS.remove( this );
- }
- state = ST_GROUND;
}
- void start() throws Exception {
- thread = new Thread( this, "JCIFS-SmbTransport" );
- thread.setDaemon( true );
- thread.start();
-
- wait( RESPONSE_TIMEOUT ); /* wait for the thread to be started and socket opened */
-
- if( socket == null ) { /* failed to open socket for some reason */
- throw new SmbException( "Timeout trying to open socket", socketException );
+ public void connect() throws SmbException {
+ try {
+ super.connect( RESPONSE_TIMEOUT );
+ } catch( TransportException te ) {
+ throw new SmbException( "", te );
}
}
- public void run() {
- Mid mid = new Mid();
- int i, m, nbtlen;
- ServerMessageBlock response;
+ protected void doConnect() throws IOException {
+ /*
+ * Negotiate Protocol Request / Response
+ */
+ SmbComNegotiateResponse resp = new SmbComNegotiateResponse( server );
try {
- Object obj;
- NbtAddress naddr;
- String calledName;
+ negotiate( 445, resp );
+ } catch( ConnectException ce ) {
+ negotiate( 139, resp );
+ }
- 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
- }
- }
+ if( resp.dialectIndex > 10 ) {
+ throw new SmbException( "This client does not support the negotiated dialect." );
+ }
- calledName = address.firstCalledName();
- do {
- try {
- socket = new NbtSocket( naddr, calledName, port, localAddr, localPort );
- if( TCP_NODELAY ) {
- socket.setTcpNoDelay( true );
- }
- socket.setSoTimeout( SO_TIMEOUT );
- in = new PushbackInputStream( socket.getInputStream(), PUSHBACK_BUF_SIZE );
- out = socket.getOutputStream();
- break;
- } catch( NbtException ne ) {
- if( ne.errorClass == NbtException.ERR_SSN_SRVC &&
- ( ne.errorCode == NbtException.CALLED_NOT_PRESENT ||
- ne.errorCode == NbtException.NOT_LISTENING_CALLED )) {
- if( log.level > 2 )
- ne.printStackTrace( log );
- } else {
- throw ne;
- }
- }
- } while(( calledName = address.nextCalledName()) != null );
+ /* Adjust negotiated values */
- if( socket == null ) {
- throw new IOException( "Failed to establish session with " + address );
+ tconHostName = address.getHostName();
+ if (server.signaturesRequired || (server.signaturesEnabled && SIGNPREF)) {
+ flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
+ } else {
+ flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
+ }
+ maxMpxCount = Math.min( maxMpxCount, server.maxMpxCount );
+ if (maxMpxCount < 1) maxMpxCount = 1;
+ snd_buf_size = Math.min( snd_buf_size, server.maxBufferSize );
+ capabilities &= server.capabilities;
+ if ((capabilities & ServerMessageBlock.CAP_UNICODE) == 0) {
+ // server doesn't want unicode
+ if (FORCE_UNICODE) {
+ capabilities |= ServerMessageBlock.CAP_UNICODE;
+ } else {
+ useUnicode = false;
+ flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
}
+ }
+ }
+ protected void doDisconnect( boolean hard ) throws IOException {
+ ListIterator iter = sessions.listIterator();
+ while (iter.hasNext()) {
+ SmbSession ssn = (SmbSession)iter.next();
+ ssn.logoff( hard );
+ iter.remove();
+ }
+ out.close();
+ in.close();
+ socket.close();
+ }
- /* Save the calledName for using on SMB_COM_TREE_CONNECT
+ protected void makeKey( Request request ) throws IOException {
+ /* The request *is* the key */
+ if (++mid == 32000) mid = 1;
+ ((ServerMessageBlock)request).mid = mid;
+ }
+ protected Request peekKey() throws IOException {
+ int n;
+ do {
+ n = readn( in, sbuf, 0, 4 );
+ } while (sbuf[0] == 0x85); /* Dodge NetBIOS keep-alive */
+ /* read smb header */
+ if ((n = readn( in, sbuf, 4, 32 )) < 32) {
+ return null; /* stream closed */
+ }
+ if (log.level > 2) {
+ log.println( "New data read: " + this );
+ jcifs.util.Hexdump.hexdump( log, sbuf, 4, 32 );
+ }
+
+ for ( ;; ) {
+ /* 01234567
+ * 00SSFSMB
+ * 0 - 0's
+ * S - size of payload
+ * FSMB - 0xFF SMB magic #
*/
- if( calledName == NbtAddress.SMBSERVER_NAME ) {
- tconHostName = address.getHostAddress();
- } else {
- tconHostName = calledName;
+
+ if (sbuf[0] == (byte)0x00 &&
+ sbuf[1] == (byte)0x00 &&
+ sbuf[4] == (byte)0xFF &&
+ sbuf[5] == (byte)'S' &&
+ sbuf[6] == (byte)'M' &&
+ sbuf[7] == (byte)'B') {
+ break; /* all good */
}
- } catch( IOException ioe ) {
- socketException = ioe;
- if( log.level > 1 )
- ioe.printStackTrace( log );
- return;
- } finally {
- synchronized( this ) {
- notifyAll();
+ /* out of phase maybe? */
+ /* inch forward 1 byte and try again */
+ for (int i = 0; i < 7; i++) {
+ sbuf[i] = sbuf[i + 1];
}
+ int b;
+ if ((b = in.read()) == 0) return null;
+ sbuf[7] = (byte)b;
}
- while( thread == Thread.currentThread() ) {
- try {
- 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;
- }
- }
+ key.mid = Encdec.dec_uint16le( sbuf, 34 );
- nbtlen = 4 + in.available();
+ /* Unless key returned is null or invalid Transport.loop() always
+ * calls doRecv() after and no one else but the transport thread
+ * should call doRecv(). Therefore it is ok to expect that the data
+ * in sbuf will be preserved for copying into BUF in doRecv().
+ */
-synchronized( rcv_buf ) {
- rcv_buf[0] = (byte)0xFF;
- rcv_buf[1] = (byte)'S';
- rcv_buf[2] = (byte)'M';
- rcv_buf[3] = (byte)'B';
+ return key;
+ }
- if( in.read( rcv_buf, 4, ServerMessageBlock.HEADER_LENGTH - 4 ) !=
- ( ServerMessageBlock.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;
+ protected void doSend( Request request ) throws IOException {
+ synchronized (BUF) {
+ int n = ((ServerMessageBlock)request).encode( BUF, 4 );
+ Encdec.enc_uint32be( n & 0xFFFF, BUF, 0 ); /* 4 byte session message header */
+ out.write( BUF, 0, 4 + n );
+ }
+ }
+
+ protected void doRecv( Response response ) throws IOException {
+ ServerMessageBlock resp = (ServerMessageBlock)response;
+ resp.useUnicode = useUnicode;
+ synchronized (BUF) {
+ System.arraycopy( sbuf, 0, BUF, 0, 4 + HEADER_LENGTH );
+ int size = Encdec.dec_uint16be( BUF, 2 );
+ if (size < (HEADER_LENGTH + 1) || (4 + size) > rcv_buf_size ) {
+ throw new IOException( "Invalid payload size: " + size );
+ }
+ if (resp instanceof SmbComReadAndXResponse) {
+ SmbComReadAndXResponse r = (SmbComReadAndXResponse)resp;
+ int off = HEADER_LENGTH;
+ /* WordCount thru dataOffset always 27 */
+ readn( in, BUF, 4 + off, 27 ); off += 27;
+ resp.decode( BUF, 4 );
+ if (r.dataLength > 0) {
+ readn( in, BUF, 4 + off, r.dataOffset - off); /* pad */
+ readn( in, r.b, r.off, r.dataLength ); /* read direct */
}
- ((PushbackInputStream)in).unread( rcv_buf, 0, ServerMessageBlock.HEADER_LENGTH );
- if( rcv_buf[0] != (byte)0xFF ||
- rcv_buf[1] != (byte)'S' ||
- rcv_buf[2] != (byte)'M' ||
- rcv_buf[3] != (byte)'B' ) {
- if( log.level > 1 )
- log.println( "bad smb header, purging session message: " + address );
- in.skip( in.available() );
- continue;
+ return;
+ }
+ readn( in, BUF, 4 + 32, size - 32 );
+ resp.decode( BUF, 4 );
+ if (resp instanceof SmbComTransactionResponse) {
+ ((SmbComTransactionResponse)resp).nextElement();
+ }
+ }
+ }
+ protected void doSkip() throws IOException {
+ int size = Encdec.dec_uint16be( sbuf, 2 );
+ if (size < 33 || (4 + size) > rcv_buf_size ) {
+ /* log message? */
+ in.skip( in.available() );
+ } else {
+ in.skip( size - 32 );
+ }
+ }
+ void checkStatus( ServerMessageBlock req, ServerMessageBlock resp ) throws SmbException {
+ resp.errorCode = SmbException.getStatusByCode( resp.errorCode );
+ switch( resp.errorCode ) {
+ case NtStatus.NT_STATUS_OK:
+ break;
+ case NtStatus.NT_STATUS_ACCESS_DENIED:
+ case NtStatus.NT_STATUS_WRONG_PASSWORD:
+ case NtStatus.NT_STATUS_LOGON_FAILURE:
+ case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION:
+ case NtStatus.NT_STATUS_INVALID_LOGON_HOURS:
+ 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:
+ case NtStatus.NT_STATUS_TRUSTED_DOMAIN_FAILURE:
+ throw new SmbAuthException( resp.errorCode );
+ case NtStatus.NT_STATUS_PATH_NOT_COVERED:
+ if( req.auth == null ) {
+ throw new SmbException( resp.errorCode, null );
}
- if(( rcv_buf[ServerMessageBlock.FLAGS_OFFSET] &
- ServerMessageBlock.FLAGS_RESPONSE ) ==
- ServerMessageBlock.FLAGS_RESPONSE ) {
- mid.mid = (short)(ServerMessageBlock.readInt2( rcv_buf, MID_OFFSET ) & 0xFFFF);
-
- response = (ServerMessageBlock)responseTable.get( mid );
- if( response == null ) {
- if( log.level > 2 ) {
- log.println( "no handler for mid=" + mid.mid +
- ", purging session message: " + address );
+ DfsReferral dr = getDfsReferral( req.auth, req.path );
+ referrals.add( dr );
+ throw dr;
+ case 0x80000005: /* STATUS_BUFFER_OVERFLOW */
+ break; /* normal for DCERPC named pipes */
+ default:
+ throw new SmbException( resp.errorCode, null );
+ }
+ }
+ void send( ServerMessageBlock request, ServerMessageBlock response ) throws SmbException {
+
+ connect(); /* must negotiate before we can test flags2, useUnicode, etc */
+
+ request.flags2 |= flags2;
+ request.useUnicode = useUnicode;
+
+ try {
+ if (response == null) {
+ doSend( request );
+ return;
+ } else if (request instanceof SmbComTransaction) {
+ SmbComTransaction req = (SmbComTransaction)request;
+ SmbComTransactionResponse resp = (SmbComTransactionResponse)response;
+
+ req.maxBufferSize = snd_buf_size;
+ resp.reset();
+
+ try {
+ BufferCache.getBuffers( req, resp );
+
+ /*
+ * First request w/ interim response
+ */
+
+ req.nextElement();
+ if (req.hasMoreElements()) {
+ SmbComBlankResponse interim = new SmbComBlankResponse();
+ super.sendrecv( req, interim, RESPONSE_TIMEOUT );
+ if (interim.errorCode != 0) {
+ checkStatus( req, interim );
}
- in.skip( in.available() );
- continue;
+ req.nextElement();
+ } else {
+ makeKey( req );
}
- synchronized( response ) {
- response.useUnicode = useUnicode;
-
- if( log.level > 3 )
- log.println( "new data read from socket: " + address );
-
- if( response instanceof SmbComTransactionResponse ) {
- Enumeration e = (Enumeration)response;
- if( e.hasMoreElements() ) {
- e.nextElement();
- } else {
- if( log.level > 2 )
- log.println( "more responses to transaction than expected" );
- continue;
- }
- if((m = response.readWireFormat( in, rcv_buf, 0 )) != nbtlen ) {
- if( log.level > 1 ) {
- log.println( "decoded " + m + " but nbtlen=" +
- nbtlen + ", purging session message" );
- }
- in.skip( in.available() );
- }
- response.received = true;
- if( log.level > 3 )
- log.println( response );
-
- if( response.errorCode != 0 || e.hasMoreElements() == false ) {
- ((SmbComTransactionResponse)response).hasMore = false;
- if( digest != null ) {
- synchronized( outLock ) {
- digest.verify(rcv_buf, 0, response);
- }
- }
- response.notify();
- }
- } else {
- response.readWireFormat( in, rcv_buf, 0 );
- response.received = true;
-
- if( log.level > 3 ) {
- ServerMessageBlock smb = response;
-
- do {
- log.println( smb );
- } while( smb instanceof AndXServerMessageBlock &&
- ( smb = ((AndXServerMessageBlock)smb).andx ) != null );
- if( log.level > 5 ) {
- Hexdump.hexdump( log, rcv_buf, 0, Math.min( response.length, 1024 ));
+ synchronized (response_map) {
+ response.received = false;
+ resp.isReceived = false;
+ try {
+ response_map.put( req, resp );
+
+ /*
+ * Send multiple fragments
+ */
+
+ do {
+ doSend( req );
+ } while( req.hasMoreElements() && req.nextElement() != null );
+
+ /*
+ * Receive multiple fragments
+ */
+
+ long timeout = RESPONSE_TIMEOUT;
+ resp.expiration = System.currentTimeMillis() + timeout;
+ while( resp.hasMoreElements() ) {
+ response_map.wait( timeout );
+ timeout = resp.expiration - System.currentTimeMillis();
+ if (timeout <= 0) {
+ throw new TransportException( this +
+ " timedout waiting for response to " +
+ req );
}
}
- if( digest != null ) {
- synchronized( outLock ) {
- digest.verify(rcv_buf, 0, response);
- }
+ if (response.errorCode != 0) {
+ checkStatus( req, resp );
}
-
- response.notify();
+ } catch( InterruptedException ie ) {
+ throw new TransportException( ie );
+ } finally {
+ response_map.remove( req );
}
}
- } else {
- // it's a request(break oplock)
- }
-}
- } catch( InterruptedIOException iioe ) {
- if( responseTable.size() == 0 ) {
- tryClose( false );
- } else if( log.level > 1 ) {
- log.println( "soTimeout has occured but there are " +
- responseTable.size() + " pending requests" );
- }
- } catch( IOException ioe ) {
- synchronized( this ) {
- tryClose( true );
- }
- if( log.level > 0 &&
- ioe.getMessage().startsWith( "Connection reset" ) == false ) {
- log.println( ioe.getMessage() + ": " + address );
- ioe.printStackTrace( log );
+ } finally {
+ BufferCache.releaseBuffer( req.txn_buf );
+ BufferCache.releaseBuffer( resp.txn_buf );
}
+
+ } else {
+ super.sendrecv( request, response, RESPONSE_TIMEOUT );
}
+ } catch( SmbException se ) {
+ throw se;
+ } catch( IOException ioe ) {
+ throw new SmbException( "", ioe );
}
+
+ checkStatus( request, response );
+ }
+ public String toString() {
+ return super.toString() + "[" + address + ":" + port + "]";
}
- synchronized DfsReferral getDfsReferral( NtlmPasswordAuthentication auth, String path ) throws SmbException {
+ /* DFS */
+
+ synchronized DfsReferral getDfsReferral( NtlmPasswordAuthentication auth,
+ String path ) throws SmbException {
String subpath, node, host;
DfsReferral dr = new DfsReferral();
int p, n, i, s;
SmbTree ipc = getSmbSession( auth ).getSmbTree( "IPC$", null );
Trans2GetDfsReferralResponse resp = new Trans2GetDfsReferralResponse();
- ipc.sendTransaction( new Trans2GetDfsReferral( path ), resp );
+ ipc.send( new Trans2GetDfsReferral( path ), resp );
subpath = path.substring( 0, resp.pathConsumed );
node = resp.referral.node;
return null;
}
- void send( ServerMessageBlock request,
- ServerMessageBlock response ) throws SmbException {
- Mid mid = null;
-
- if( request.command != request.SMB_COM_NEGOTIATE )
- negotiate();
-
- request.flags2 |= flags2;
- request.useUnicode = useUnicode;
-
- if( response == null ) {
- synchronized( outLock ) {
- try {
- mid = aquireMid();
- request.mid = mid.mid;
-synchronized( snd_buf ) {
- request.digest = digest;
- request.response = null;
- int length = request.writeWireFormat(snd_buf, 4);
- out.write(snd_buf, 4, length);
- out.flush();
-
- if( log.level > 3 ) {
- ServerMessageBlock smb = request;
-
- do {
- log.println( smb );
- } while( smb instanceof AndXServerMessageBlock &&
- ( smb = ((AndXServerMessageBlock)smb).andx ) != null );
- if( log.level > 5 ) {
- Hexdump.hexdump( log, snd_buf, 0, Math.min( request.length, 1024 ));
- }
- }
-}
- } catch( IOException ioe ) {
- tryClose( true );
- throw new SmbException( "An error occured sending the request.", ioe );
- } finally {
- releaseMid( mid );
- }
- }
-
- return;
- }
-
- // now for the normal case where response is not null
-
- synchronized( response ) {
- try {
- synchronized( outLock ) {
- response.received = false;
- mid = aquireMid();
- request.mid = mid.mid;
- responseTable.put( mid, response );
-synchronized( snd_buf ) {
- if( digest != null ) {
- request.digest = digest;
- request.response = response;
- }
- int length = request.writeWireFormat(snd_buf, 4);
- out.write(snd_buf, 4, length);
- out.flush();
-
- if( log.level > 3 ) {
- ServerMessageBlock smb = request;
-
- do {
- log.println( smb );
- } while( smb instanceof AndXServerMessageBlock &&
- ( smb = ((AndXServerMessageBlock)smb).andx ) != null );
- if( log.level > 5 ) {
- Hexdump.hexdump( log, snd_buf, 0, request.length );
- }
- }
}
- }
-
- // default it 1 so that 0 can be used as forever
- response.wait( response.responseTimeout == 1 ? RESPONSE_TIMEOUT : response.responseTimeout );
- } catch( InterruptedException ie ) {
- tryClose( true );
- } catch( IOException ioe ) {
- tryClose( true );
- throw new SmbException( "An error occured sending the request.", ioe );
- } finally {
- responseTable.remove( mid );
- synchronized( outLock ) {
- releaseMid( mid );
- }
- }
- }
-
- if( response.received == false ) {
- tryClose( true );
- throw new SmbException( "Timeout waiting for response from server: " + address );
- } else if( response.verifyFailed ) {
- tryClose( true );
- throw new SmbException( "Unverifiable signature: " + address );
- }
- response.errorCode = SmbException.getStatusByCode( response.errorCode );
- switch( response.errorCode ) {
- case NtStatus.NT_STATUS_OK:
- break;
- case NtStatus.NT_STATUS_ACCESS_DENIED:
- case NtStatus.NT_STATUS_WRONG_PASSWORD:
- case NtStatus.NT_STATUS_LOGON_FAILURE:
- case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION:
- case NtStatus.NT_STATUS_INVALID_LOGON_HOURS:
- 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 ) {
- throw new SmbException( response.errorCode, null );
- }
- DfsReferral dr = getDfsReferral( request.auth, request.path );
- referrals.add( dr );
- throw dr;
- default:
- throw new SmbException( response.errorCode, null );
- }
- }
- void sendTransaction( SmbComTransaction request,
- SmbComTransactionResponse response ) throws SmbException {
- Mid mid = null;
-
- negotiate();
-
- request.flags2 |= flags2;
- request.useUnicode = useUnicode;
- request.maxBufferSize = snd_buf_size;
- response.received = false;
- response.hasMore = true;
- response.isPrimary = true;
-
- try {
- synchronized( outLock ) {
- mid = aquireMid();
- }
- request.txn_buf = BufferCache.getBuffer();
- response.txn_buf = BufferCache.getBuffer();
-
- request.nextElement();
- if( request.hasMoreElements() ) {
- // multi-part request
-
- SmbComBlankResponse interimResponse = new SmbComBlankResponse();
-
- synchronized( interimResponse ) {
- try {
- synchronized( outLock ) {
- request.mid = mid.mid;
- responseTable.put( mid, interimResponse );
-synchronized(snd_buf) {
- request.digest = digest;
- request.response = response;
- int length = request.writeWireFormat(snd_buf, 4);
- out.write(snd_buf, 4, length);
- out.flush();
-
- if( log.level > 3 ) {
- log.println( request );
- if( log.level > 5 ) {
- Hexdump.hexdump( log, snd_buf, 0, request.length );
- }
- }
-}
- }
-
- interimResponse.wait( RESPONSE_TIMEOUT );
-
- if( interimResponse.received == false ) {
- throw new SmbException( "Timeout waiting for response from server: " + address );
- }
- interimResponse.errorCode = SmbException.getStatusByCode( interimResponse.errorCode );
- switch( interimResponse.errorCode ) {
- case NtStatus.NT_STATUS_OK:
- break;
- case NtStatus.NT_STATUS_ACCESS_DENIED:
- case NtStatus.NT_STATUS_WRONG_PASSWORD:
- case NtStatus.NT_STATUS_LOGON_FAILURE:
- case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION:
- case NtStatus.NT_STATUS_INVALID_LOGON_HOURS:
- 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 ) {
- throw new SmbException( interimResponse.errorCode, null );
- }
- DfsReferral dr = getDfsReferral( request.auth, request.path );
- referrals.add( dr );
- throw dr;
- default:
- throw new SmbException( interimResponse.errorCode, null );
- }
- } finally {
- responseTable.remove( mid );
- }
- }
-
- request.nextElement();
- }
-
- synchronized( response ) {
- try {
- synchronized( outLock ) {
- request.mid = mid.mid;
- responseTable.put( mid, response );
- do {
-synchronized( snd_buf ) {
- request.digest = digest;
- request.response = response;
- int length = request.writeWireFormat(snd_buf, 4);
- out.write(snd_buf, 4, length);
- out.flush();
-
- if( log.level > 3 ) {
- log.println( request );
- if( log.level > 5 ) {
- Hexdump.hexdump( log, 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 ? RESPONSE_TIMEOUT : response.responseTimeout );
- } while( response.received && response.hasMoreElements() );
- } finally {
- responseTable.remove( mid );
- }
- }
- } catch( InterruptedException ie ) {
- tryClose( true );
- } catch( IOException ioe ) {
- tryClose( true );
- throw new SmbException( "An error occured sending the request.", ioe );
- } finally {
- synchronized( outLock ) {
- releaseMid( mid );
- }
- BufferCache.releaseBuffer( request.txn_buf );
- BufferCache.releaseBuffer( response.txn_buf );
- }
-
- if( response.received == false ) {
- tryClose( true );
- throw new SmbException( "Timeout waiting for response from server: " + address );
- } else if( response.verifyFailed ) {
- tryClose( true );
- throw new SmbException( "Unverifiable signature: " + address );
- }
- response.errorCode = SmbException.getStatusByCode( response.errorCode );
- switch( response.errorCode ) {
- case NtStatus.NT_STATUS_OK:
- break;
- case NtStatus.NT_STATUS_ACCESS_DENIED:
- case NtStatus.NT_STATUS_WRONG_PASSWORD:
- case NtStatus.NT_STATUS_LOGON_FAILURE:
- case NtStatus.NT_STATUS_ACCOUNT_RESTRICTION:
- case NtStatus.NT_STATUS_INVALID_LOGON_HOURS:
- 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 ) {
- throw new SmbException( response.errorCode, null );
- }
- DfsReferral dr = getDfsReferral( request.auth, request.path );
- referrals.add( dr );
- throw dr;
- case 0x80000005:
- break;
- default:
- throw new SmbException( response.errorCode, null );
- }
- }
- synchronized void negotiate0() throws Exception {
- start(); /* start the transport thread (which opens the socket) */
- if( this == NULL_TRANSPORT ) {
- throw new RuntimeException( "Null transport cannot be used" );
- }
-
- if( log.level > 2 )
- log.println( "requesting negotiation with " + address );
-
- /*
- * Negotiate Protocol Request / Response
- */
-
- SmbComNegotiateResponse response = new SmbComNegotiateResponse();
- send( new SmbComNegotiate(), response );
-
- if( response.dialectIndex > 10 ) {
- throw new SmbException( "This client does not support the negotiated dialect." );
- }
-
- server = new ServerData();
- server.securityMode = response.securityMode;
- server.security = response.security;
- server.encryptedPasswords = response.encryptedPasswords;
- server.signaturesEnabled = response.signaturesEnabled;
- server.signaturesRequired = response.signaturesRequired;
- server.maxMpxCount = response.maxMpxCount;
- server.maxNumberVcs = response.maxNumberVcs;
- server.maxBufferSize = response.maxBufferSize;
- server.maxRawSize = response.maxRawSize;
- server.sessionKey = response.sessionKey;
- server.capabilities = response.capabilities;
- server.serverTime = response.serverTime;
- server.serverTimeZone = response.serverTimeZone;
- server.encryptionKeyLength = response.encryptionKeyLength;
- server.encryptionKey = response.encryptionKey;
- server.oemDomainName = response.oemDomainName;
-
- if (server.signaturesRequired || (server.signaturesEnabled && SIGNPREF)) {
- flags2 |= ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
- } else {
- flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_SECURITY_SIGNATURES;
- }
-
- maxMpxCount = maxMpxCount < server.maxMpxCount ? maxMpxCount : server.maxMpxCount;
- maxMpxCount = maxMpxCount < 1 ? 1 : maxMpxCount;
-
- snd_buf_size = snd_buf_size < server.maxBufferSize ? snd_buf_size : server.maxBufferSize;
-
- capabilities &= server.capabilities;
- if(( capabilities & ServerMessageBlock.CAP_UNICODE ) == 0 ) {
- // server doesn't want unicode
- if( FORCE_UNICODE ) {
- capabilities |= ServerMessageBlock.CAP_UNICODE;
- } else {
- useUnicode = false;
- flags2 &= 0xFFFF ^ ServerMessageBlock.FLAGS2_UNICODE;
- }
- }
- }
- synchronized void negotiate() throws SmbException {
- if( state == ST_GROUND ) {
- state = ST_NEGOTIATING;
- } else {
- while( state != ST_NEGOTIATED ) {
- try {
- wait();
- } catch( InterruptedException ie ) {
- tryClose( true );
- throw new SmbException( "Interrupted opening socket", ie );
- }
- }
- return;
- }
-
- try {
- negotiate0();
- state = ST_NEGOTIATED;
- } catch( Exception ex ) {
- if( log.level > 1 )
- ex.printStackTrace( log );
- tryClose( true );
- throw new SmbException( "Failed to negotiate", ex );
- } finally {
- notifyAll();
- }
- }
- 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;
- }
-
- /* Manage MIDs */
-
- Mid aquireMid() throws SmbException {
- int i;
-
- if( mid_next == 0 ) {
- mid_next++;
- }
-
- for( ;; ) {
- for( i = 0; i < maxMpxCount; i++ ) {
- if( mids[i].mid == 0 ) {
- break;
- }
- }
- if( i == maxMpxCount ) {
- try {
- outLock.wait();
- } catch( InterruptedException ie ) {
- throw new SmbException( "Interrupted aquiring mid", ie );
- }
- } else {
- break;
- }
- }
-
- mids[i].mid = mid_next++;
-
- return mids[i];
- }
- void releaseMid( Mid mid ) {
- int i;
-
- for( i = 0; i < maxMpxCount; i++ ) {
- if( mids[i].mid == mid.mid ) {
- mid.mid = 0;
- outLock.notify();
- return;
- }
- }
- if( log.level > 1 )
- log.println( "mid not found" );
- }
-}
class SmbTree {
- private static final String DEFAULT_SERVICE = Config.getProperty( "jcifs.smb.client.serviceType", "?????" );
-
private int tid;
private String share;
- String service = DEFAULT_SERVICE;
+ String service = "?????";
SmbSession session;
boolean treeConnected, inDfs;
( service == null || service.startsWith( "??" ) ||
this.service.equalsIgnoreCase( service ));
}
- void sendTransaction( SmbComTransaction request,
- SmbComTransactionResponse response ) throws SmbException {
- // transactions are not batchable
- treeConnect( null, null );
- if( service.equals( "A:" ) == false ) {
- switch( ((SmbComTransaction)request).subCommand & 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:
- case SmbComTransaction.TRANS_TRANSACT_NAMED_PIPE:
- case SmbComTransaction.TRANS2_GET_DFS_REFERRAL:
- break;
- default:
- throw new SmbException( "Invalid operation for " + service + " service" );
- }
- }
- request.tid = tid;
- if( inDfs && request.path != null && request.path.length() > 0 ) {
- request.path = '\\' + session.transport().tconHostName + '\\' + share + request.path;
- }
- session.sendTransaction( request, response );
- }
void send( ServerMessageBlock request,
ServerMessageBlock response ) throws SmbException {
if( response != null ) {
case ServerMessageBlock.SMB_COM_CLOSE:
case ServerMessageBlock.SMB_COM_TREE_DISCONNECT:
break;
+ case ServerMessageBlock.SMB_COM_TRANSACTION:
+ 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:
+ case SmbComTransaction.TRANS_TRANSACT_NAMED_PIPE:
+ case SmbComTransaction.TRANS2_GET_DFS_REFERRAL:
+ break;
+ default:
+ throw new SmbException( "Invalid operation for " + service + " service" );
+ }
+ break;
default:
throw new SmbException( "Invalid operation for " + service + " service" );
}
request.flags2 = ServerMessageBlock.FLAGS2_RESOLVE_PATHS_IN_DFS;
request.path = '\\' + session.transport().tconHostName + '\\' + share + request.path;
}
- session.send( request, response );
+ try {
+ session.send( request, response );
+ } catch( SmbException se ) {
+ if (se.getNtStatus() == se.NT_STATUS_NETWORK_NAME_DELETED) {
+ /* Someone removed the share while we were
+ * connected. Bastards! Disconnect this tree
+ * so that it reconnects cleanly should the share
+ * reappear in this client's lifetime.
+ */
+ treeDisconnect( true );
+ }
+ throw se;
+ }
}
void treeConnect( ServerMessageBlock andx,
ServerMessageBlock andxResponse ) throws SmbException {
String unc;
synchronized( session.transport() ) {
- if( treeConnected ) {
+ if (treeConnected) {
return;
}
* established.
*/
- session.transport.negotiate();
+ session.transport.connect();
unc = "\\\\" + session.transport.tconHostName + '\\' + share;
session.transport.log.println( "treeConnect: unc=" + unc + ",service=" + service );
SmbComTreeConnectAndXResponse response =
- new SmbComTreeConnectAndXResponse( andxResponse );
+ new SmbComTreeConnectAndXResponse( andxResponse );
SmbComTreeConnectAndX request =
- new SmbComTreeConnectAndX( session, unc, service, andx );
+ new SmbComTreeConnectAndX( session, unc, service, andx );
session.send( request, response );
tid = response.tid;
}
void treeDisconnect( boolean inError ) {
synchronized( session.transport ) {
- if( treeConnected == false ) {
- return;
- }
- if( !inError ) {
+ if (treeConnected && !inError) {
try {
send( new SmbComTreeDisconnect(), null );
} catch( SmbException se ) {
+ if (session.transport.log.level > 1) {
+ se.printStackTrace( session.transport.log );
+ }
}
}
treeConnected = false;
// information levels
static final int SMB_INFO_ALLOCATION = 1;
static final int SMB_QUERY_FS_SIZE_INFO = 0x103;
+ static final int SMB_FS_FULL_SIZE_INFORMATION = 1007;
class SmbInfoAllocation implements AllocInfo {
long alloc; // Also handles SmbQueryFSSizeInfo
return readSmbInfoAllocationWireFormat( buffer, bufferIndex );
case SMB_QUERY_FS_SIZE_INFO:
return readSmbQueryFSSizeInfoWireFormat( buffer, bufferIndex );
+ case SMB_FS_FULL_SIZE_INFORMATION:
+ return readFsFullSizeInformationWireFormat( buffer, bufferIndex );
default:
return 0;
}
SmbInfoAllocation info = new SmbInfoAllocation();
- info.alloc = readInt4( buffer, bufferIndex );
- bufferIndex += 4;
- info.alloc |= readInt4( buffer, bufferIndex ) << 32L;
- bufferIndex += 4;
+ info.alloc = readInt8( buffer, bufferIndex );
+ bufferIndex += 8;
- info.free = readInt4( buffer, bufferIndex );
+ info.free = readInt8( buffer, bufferIndex );
+ bufferIndex += 8;
+
+ info.sectPerAlloc = readInt4( buffer, bufferIndex );
bufferIndex += 4;
- info.free |= readInt4( buffer, bufferIndex ) << 32L;
+
+ info.bytesPerSect = readInt4( buffer, bufferIndex );
bufferIndex += 4;
+ this.info = info;
+
+ return bufferIndex - start;
+ }
+ int readFsFullSizeInformationWireFormat( byte[] buffer, int bufferIndex )
+ {
+ int start = bufferIndex;
+
+ SmbInfoAllocation info = new SmbInfoAllocation();
+
+ // Read total allocation units.
+ info.alloc = readInt8( buffer, bufferIndex );
+ bufferIndex += 8;
+
+ // read caller available allocation units
+ info.free = readInt8( buffer, bufferIndex );
+ bufferIndex += 8;
+
+ // skip actual free units
+ bufferIndex += 8;
+
info.sectPerAlloc = readInt4( buffer, bufferIndex );
bufferIndex += 4;
-
+
info.bytesPerSect = readInt4( buffer, bufferIndex );
bufferIndex += 4;
return bufferIndex - start;
}
+
public String toString() {
return new String( "Trans2QueryFSInformationResponse[" +
super.toString() + "]" );
Object lock;
- TransactNamedPipeInputStream( SmbNamedPipe pipe ) throws SmbException, MalformedURLException, UnknownHostException {
+ TransactNamedPipeInputStream( SmbNamedPipe pipe ) throws SmbException,
+ MalformedURLException, UnknownHostException {
super( pipe, ( pipe.pipeType & 0xFFFF0000 ) | SmbFile.O_EXCL );
- this.dcePipe = ( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT ) == SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT;
+ this.dcePipe = ( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT ) != SmbNamedPipe.PIPE_TYPE_DCE_TRANSACT;
lock = new Object();
}
public int read() throws IOException {
if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_CALL ) ==
SmbNamedPipe.PIPE_TYPE_CALL ) {
- pipe.sendTransaction( new TransWaitNamedPipe( path ),
+ pipe.send( new TransWaitNamedPipe( path ),
new TransWaitNamedPipeResponse() );
- pipe.sendTransaction( new TransCallNamedPipe( path, b, off, len ),
+ pipe.send( new TransCallNamedPipe( path, b, off, len ),
new TransCallNamedPipeResponse( pipe ));
} else if(( pipe.pipeType & SmbNamedPipe.PIPE_TYPE_TRANSACT ) ==
SmbNamedPipe.PIPE_TYPE_TRANSACT ) {
if (dcePipe) {
req.maxDataCount = 1024;
}
- pipe.sendTransaction( req, new TransTransactNamedPipeResponse( pipe ));
+ pipe.send( req, new TransTransactNamedPipeResponse( pipe ));
}
}
}
--- /dev/null
+package jcifs.util.transport;
+
+public interface Request {
+}
--- /dev/null
+package jcifs.util.transport;
+
+public abstract class Response {
+ public long expiration;
+ public boolean isReceived;
+}
--- /dev/null
+package jcifs.util.transport;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import jcifs.util.LogStream;
+
+/**
+ * This class simplifies communication for protocols that support
+ * multiplexing requests. It encapsulates a stream and some protocol
+ * knowledge (provided by a concrete subclass) so that connecting,
+ * disconnecting, sending, and receiving can be syncronized
+ * properly. Apparatus is provided to send and receive requests
+ * concurrently.
+ */
+
+public abstract class Transport implements Runnable {
+
+ static int id = 0;
+ static LogStream log = LogStream.getInstance();
+
+ public static int readn( InputStream in,
+ byte[] b,
+ int off,
+ int len ) throws IOException {
+ int i = 0, n = -5;
+
+ while (i < len) {
+ n = in.read( b, off + i, len - i );
+ if (n <= 0) {
+ break;
+ }
+ i += n;
+ }
+
+ return i;
+ }
+
+ /* state values
+ * 0 - not connected
+ * 1 - connecting
+ * 2 - run connected
+ * 3 - connected
+ * 4 - error
+ */
+ int state = 0;
+
+ String name = "Transport" + id++;
+ Thread thread;
+ TransportException te;
+
+ protected HashMap response_map = new HashMap( 4 );
+
+ protected abstract void makeKey( Request request ) throws IOException;
+ protected abstract Request peekKey() throws IOException;
+ protected abstract void doSend( Request request ) throws IOException;
+ protected abstract void doRecv( Response response ) throws IOException;
+ protected abstract void doSkip() throws IOException;
+
+ public void sendrecv( Request request,
+ Response response,
+ long timeout ) throws IOException {
+ synchronized (response_map) {
+ makeKey( request );
+ response.isReceived = false;
+ try {
+ response_map.put( request, response );
+ doSend( request );
+ response.expiration = System.currentTimeMillis() + timeout;
+ while (!response.isReceived) {
+ response_map.wait( timeout );
+ timeout = response.expiration - System.currentTimeMillis();
+ if (timeout <= 0) {
+ throw new TransportException( name +
+ " timedout waiting for response to " +
+ request );
+ }
+ }
+ } catch( InterruptedException ie ) {
+ throw new TransportException( ie );
+ } finally {
+ response_map.remove( request );
+ }
+ }
+ }
+ private void loop() {
+ while( thread == Thread.currentThread() ) {
+ try {
+ Request key = peekKey();
+ if (key == null) return;
+ synchronized (response_map) {
+ Response response = (Response)response_map.get( key );
+ if (response == null) {
+ if (log.level > 2)
+ log.println( "Invalid key, skipping message" );
+ doSkip();
+ } else {
+ doRecv( response );
+ response.isReceived = true;
+ response_map.notifyAll();
+ }
+ }
+ } catch( IOException ex ) {
+ String msg = ex.getMessage();
+ boolean hard = true;
+
+ if (log.level > 2)
+ ex.printStackTrace( log );
+
+ if (msg != null && msg.equals( "Read timed out" )) {
+ hard = false;
+ }
+ try {
+ disconnect( hard );
+ } catch( IOException ioe ) {
+ ioe.printStackTrace( log );
+ }
+ }
+ }
+ }
+
+ /* Build a connection. Only one thread will ever call this method at
+ * any one time. If this method throws an exception or the connect timeout
+ * expires an encapsulating TransportException will be thrown from connect
+ * and the transport will be in error.
+ */
+
+ protected abstract void doConnect() throws Exception;
+
+ /* Tear down a connection. If the hard parameter is true, the diconnection
+ * procedure should not initiate or wait for any outstanding requests on
+ * this transport.
+ */
+
+ protected abstract void doDisconnect( boolean hard ) throws IOException;
+
+ public synchronized void connect( long timeout ) throws TransportException {
+ switch (state) {
+ case 0:
+ break;
+ case 3:
+ return; // already connected
+ case 4:
+ throw new TransportException( "Connection in error", te );
+ default:
+ throw new TransportException( "Invalid state: " + state );
+ }
+
+ state = 1;
+ te = null;
+ thread = new Thread( this, name );
+ thread.setDaemon( true );
+
+ synchronized (thread) {
+ thread.start();
+ try {
+ thread.wait( timeout ); /* wait for doConnect */
+ } catch( InterruptedException ie ) {
+ throw new TransportException( ie );
+ }
+
+ switch (state) {
+ case 1: /* doConnect never returned */
+ te = new TransportException( "Connection timeout" );
+ case 2:
+ if (te != null) { /* doConnect throw Exception */
+ state = 4; /* error */
+ thread = null;
+ throw te;
+ }
+ state = 3; /* Success! */
+ return;
+ default:
+ te = new TransportException( "Invalid state: " + state );
+ }
+ }
+ }
+ public synchronized void disconnect( boolean hard ) throws IOException {
+ switch (state) {
+ case 0: /* not connected - just return */
+ return;
+ case 3: /* connected - go ahead and disconnect */
+ if (response_map.size() != 0 && !hard) {
+ break; /* outstanding requests */
+ }
+ doDisconnect( hard );
+ case 4: /* in error - reset the transport */
+ thread = null;
+ state = 0;
+ break;
+ default:
+ throw new TransportException( "Invalid state: " + state );
+ }
+ }
+ public void run() {
+ Thread run_thread = Thread.currentThread();
+ Exception ex0 = null;
+
+ try {
+ /* We cannot synchronize (run_thread) here or the caller's
+ * thread.wait( timeout ) cannot reaquire the lock and
+ * return which would render the timeout effectively useless.
+ */
+ doConnect();
+ } catch( Exception ex ) {
+ ex0 = ex; // Defer to below where we're locked
+ return;
+ } finally {
+ synchronized (run_thread) {
+ if (run_thread != thread) {
+ /* Thread no longer the one setup for this transport --
+ * doConnect returned too late, just ignore.
+ */
+ if (ex0 != null) {
+ ex0.printStackTrace();
+ }
+ return;
+ }
+ if (ex0 != null) {
+ te = new TransportException( ex0 );
+ }
+ state = 2; // run connected
+ run_thread.notify();
+ }
+ }
+
+ /* Proccess responses
+ */
+ loop();
+ }
+
+ public String toString() {
+ return name;
+ }
+}
--- /dev/null
+package jcifs.util.transport;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+public class TransportException extends IOException {
+
+ private Throwable rootCause;
+
+ public TransportException() {
+ }
+ public TransportException( String msg ) {
+ super( msg );
+ }
+ public TransportException( Throwable rootCause ) {
+ this.rootCause = rootCause;
+ }
+ public TransportException( String msg, Throwable rootCause ) {
+ super( msg );
+ this.rootCause = rootCause;
+ }
+
+ public Throwable getRootCause() {
+ return rootCause;
+ }
+ public String toString() {
+ if( rootCause != null ) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter( sw );
+ rootCause.printStackTrace( pw );
+ return super.toString() + "\n" + sw;
+ } else {
+ return super.toString();
+ }
+ }
+}
+