jcifs.smb.ServerMessageBlock Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcifs Show documentation
Show all versions of jcifs Show documentation
JCIFS is an Open Source client library that implements the CIFS/SMB networking protocol in 100% Java
/* jcifs smb client library in Java
* Copyright (C) 2000 "Michael B. Allen"
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package jcifs.smb;
import jcifs.Config;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import jcifs.util.Hexdump;
import jcifs.util.LogStream;
import jcifs.util.transport.*;
abstract class ServerMessageBlock extends Response implements Request, SmbConstants {
static LogStream log = LogStream.getInstance();
static final byte[] header = {
(byte)0xFF, (byte)'S', (byte)'M', (byte)'B',
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
};
static void writeInt2( long val, byte[] dst, int dstIndex ) {
dst[dstIndex] = (byte)(val);
dst[++dstIndex] = (byte)(val >> 8);
}
static void writeInt4( long val, byte[] dst, int dstIndex ) {
dst[dstIndex] = (byte)(val);
dst[++dstIndex] = (byte)(val >>= 8);
dst[++dstIndex] = (byte)(val >>= 8);
dst[++dstIndex] = (byte)(val >> 8);
}
static int readInt2( byte[] src, int srcIndex ) {
return ( src[srcIndex] & 0xFF ) +
(( src[srcIndex + 1] & 0xFF ) << 8 );
}
static int readInt4( byte[] src, int srcIndex ) {
return ( src[srcIndex] & 0xFF ) +
(( src[srcIndex + 1] & 0xFF ) << 8 ) +
(( src[srcIndex + 2] & 0xFF ) << 16 ) +
(( src[srcIndex + 3] & 0xFF ) << 24 );
}
static long readInt8( byte[] src, int srcIndex ) {
return (readInt4( src, srcIndex ) & 0xFFFFFFFFL) +
((long)(readInt4( src, srcIndex + 4 )) << 32);
}
static void writeInt8( long val, byte[] dst, int dstIndex ) {
dst[dstIndex] = (byte)(val);
dst[++dstIndex] = (byte)(val >>= 8);
dst[++dstIndex] = (byte)(val >>= 8);
dst[++dstIndex] = (byte)(val >>= 8);
dst[++dstIndex] = (byte)(val >>= 8);
dst[++dstIndex] = (byte)(val >>= 8);
dst[++dstIndex] = (byte)(val >>= 8);
dst[++dstIndex] = (byte)(val >> 8);
}
static long readTime( byte[] src, int srcIndex ) {
int low = readInt4( src, srcIndex );
int hi = readInt4( src, srcIndex + 4 );
long t = ((long)hi << 32L ) | (low & 0xFFFFFFFFL);
t = ( t / 10000L - MILLISECONDS_BETWEEN_1970_AND_1601 );
return t;
}
static void writeTime( long t, byte[] dst, int dstIndex ) {
if( t != 0L ) {
t = (t + MILLISECONDS_BETWEEN_1970_AND_1601) * 10000L;
}
writeInt8( t, dst, dstIndex );
}
static long readUTime( byte[] buffer, int bufferIndex ) {
return readInt4( buffer, bufferIndex ) * 1000L;
}
static void writeUTime( long t, byte[] dst, int dstIndex ) {
if( t == 0L || t == 0xFFFFFFFFFFFFFFFFL ) {
writeInt4( 0xFFFFFFFF, dst, dstIndex );
return;
}
synchronized( TZ ) {
if( TZ.inDaylightTime( new Date() )) {
// in DST
if( TZ.inDaylightTime( new Date( t ))) {
// t also in DST so no correction
} else {
// t not in DST so subtract 1 hour
t -= 3600000;
}
} else {
// not in DST
if( TZ.inDaylightTime( new Date( t ))) {
// t is in DST so add 1 hour
t += 3600000;
} else {
// t isn't in DST either
}
}
}
writeInt4( (int)(t / 1000L), dst, dstIndex );
}
/*
* These are all the smbs supported by this library. This includes requests
* and well as their responses for each type however the actuall implementations
* of the readXxxWireFormat and writeXxxWireFormat methods may not be in
* place. For example at the time of this writing the readXxxWireFormat
* for requests and the writeXxxWireFormat for responses are not implemented
* and simply return 0. These would need to be completed for a server
* implementation.
*/
static final byte SMB_COM_CREATE_DIRECTORY = (byte)0x00;
static final byte SMB_COM_DELETE_DIRECTORY = (byte)0x01;
static final byte SMB_COM_CLOSE = (byte)0x04;
static final byte SMB_COM_DELETE = (byte)0x06;
static final byte SMB_COM_RENAME = (byte)0x07;
static final byte SMB_COM_QUERY_INFORMATION = (byte)0x08;
static final byte SMB_COM_WRITE = (byte)0x0B;
static final byte SMB_COM_CHECK_DIRECTORY = (byte)0x10;
static final byte SMB_COM_TRANSACTION = (byte)0x25;
static final byte SMB_COM_TRANSACTION_SECONDARY = (byte)0x26;
static final byte SMB_COM_MOVE = (byte)0x2A;
static final byte SMB_COM_ECHO = (byte)0x2B;
static final byte SMB_COM_OPEN_ANDX = (byte)0x2D;
static final byte SMB_COM_READ_ANDX = (byte)0x2E;
static final byte SMB_COM_WRITE_ANDX = (byte)0x2F;
static final byte SMB_COM_TRANSACTION2 = (byte)0x32;
static final byte SMB_COM_FIND_CLOSE2 = (byte)0x34;
static final byte SMB_COM_TREE_DISCONNECT = (byte)0x71;
static final byte SMB_COM_NEGOTIATE = (byte)0x72;
static final byte SMB_COM_SESSION_SETUP_ANDX = (byte)0x73;
static final byte SMB_COM_LOGOFF_ANDX = (byte)0x74;
static final byte SMB_COM_TREE_CONNECT_ANDX = (byte)0x75;
static final byte SMB_COM_NT_TRANSACT = (byte)0xA0;
static final byte SMB_COM_NT_TRANSACT_SECONDARY = (byte)0xA1;
static final byte SMB_COM_NT_CREATE_ANDX = (byte)0xA2;
/*
* Some fields specify the offset from the beginning of the header. This
* field should be used for calculating that. This would likely be zero
* but an implemantation that encorporates the transport header(for
* efficiency) might use a different initial bufferIndex. For example,
* to eliminate copying data when writing NbtSession data one might
* manage that 4 byte header specifically and therefore the initial
* bufferIndex, and thus headerStart, would be 4).(NOTE: If one where
* looking for a way to improve perfomance this is precisly what you
* would want to do as the jcifs.netbios.SocketXxxputStream classes
* arraycopy all data read or written into a new buffer shifted over 4!)
*/
byte command, flags;
int headerStart,
length,
batchLevel,
errorCode,
flags2,
tid, pid, uid, mid,
wordCount, byteCount;
boolean useUnicode, received, extendedSecurity;
long responseTimeout = 1;
int signSeq;
boolean verifyFailed;
NtlmPasswordAuthentication auth = null;
String path;
SigningDigest digest = null;
ServerMessageBlock response;
ServerMessageBlock() {
flags = (byte)( FLAGS_PATH_NAMES_CASELESS | FLAGS_PATH_NAMES_CANONICALIZED );
pid = PID;
batchLevel = 0;
}
void reset() {
flags = (byte)( FLAGS_PATH_NAMES_CASELESS | FLAGS_PATH_NAMES_CANONICALIZED );
flags2 = 0;
errorCode = 0;
received = false;
digest = null;
}
int writeString( String str, byte[] dst, int dstIndex ) {
return writeString( str, dst, dstIndex, useUnicode );
}
int writeString( String str, byte[] dst, int dstIndex, boolean useUnicode ) {
int start = dstIndex;
try {
if( useUnicode ) {
// Unicode requires word alignment
if((( dstIndex - headerStart ) % 2 ) != 0 ) {
dst[dstIndex++] = (byte)'\0';
}
System.arraycopy( str.getBytes( UNI_ENCODING ), 0,
dst, dstIndex, str.length() * 2 );
dstIndex += str.length() * 2;
dst[dstIndex++] = (byte)'\0';
dst[dstIndex++] = (byte)'\0';
} else {
byte[] b = str.getBytes( OEM_ENCODING );
System.arraycopy( b, 0, dst, dstIndex, b.length );
dstIndex += b.length;
dst[dstIndex++] = (byte)'\0';
}
} catch( UnsupportedEncodingException uee ) {
if( log.level > 1 )
uee.printStackTrace( log );
}
return dstIndex - start;
}
String readString( byte[] src, int srcIndex ) {
return readString( src, srcIndex, 256, useUnicode );
}
String readString( byte[] src, int srcIndex, int maxLen, boolean useUnicode ) {
int len = 0;
String str = null;
try {
if( useUnicode ) {
// Unicode requires word alignment
if((( srcIndex - headerStart ) % 2 ) != 0 ) {
srcIndex++;
}
while( src[srcIndex + len] != (byte)0x00 ||
src[srcIndex + len + 1] != (byte)0x00 ) {
len += 2;
if( len > maxLen ) {
if( log.level > 0 )
Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 );
throw new RuntimeException( "zero termination not found" );
}
}
str = new String( src, srcIndex, len, UNI_ENCODING );
} else {
while( src[srcIndex + len] != (byte)0x00 ) {
len++;
if( len > maxLen ) {
if( log.level > 0 )
Hexdump.hexdump( System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128 );
throw new RuntimeException( "zero termination not found" );
}
}
str = new String( src, srcIndex, len, OEM_ENCODING );
}
} catch( UnsupportedEncodingException uee ) {
if( log.level > 1 )
uee.printStackTrace( log );
}
return str;
}
String readString(byte[] src, int srcIndex, int srcEnd, int maxLen, boolean useUnicode) {
int len = 0;
String str = null;
try {
if (useUnicode) {
// Unicode requires word alignment
if (((srcIndex - headerStart) % 2) != 0) {
srcIndex++;
}
for (len = 0; (srcIndex + len + 1) < srcEnd; len += 2) {
if (src[srcIndex + len] == (byte)0x00 && src[srcIndex + len + 1] == (byte)0x00) {
break;
}
if (len > maxLen) {
if (log.level > 0)
Hexdump.hexdump(System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128);
throw new RuntimeException("zero termination not found");
}
}
str = new String(src, srcIndex, len, UNI_ENCODING);
} else {
for (len = 0; srcIndex < srcEnd; len++) {
if (src[srcIndex + len] == (byte)0x00) {
break;
}
if (len > maxLen) {
if (log.level > 0)
Hexdump.hexdump(System.err, src, srcIndex, maxLen < 128 ? maxLen + 8 : 128);
throw new RuntimeException("zero termination not found");
}
}
str = new String(src, srcIndex, len, OEM_ENCODING);
}
} catch( UnsupportedEncodingException uee ) {
if( log.level > 1 )
uee.printStackTrace( log );
}
return str;
}
int stringWireLength( String str, int offset ) {
int len = str.length() + 1;
if( useUnicode ) {
len = str.length() * 2 + 2;
len = ( offset % 2 ) != 0 ? len + 1 : len;
}
return len;
}
int readStringLength( byte[] src, int srcIndex, int max ) {
int len = 0;
while( src[srcIndex + len] != (byte)0x00 ) {
if( len++ > max ) {
throw new RuntimeException( "zero termination not found: " + this );
}
}
return len;
}
int encode( byte[] dst, int dstIndex ) {
int start = headerStart = dstIndex;
dstIndex += writeHeaderWireFormat( dst, dstIndex );
wordCount = writeParameterWordsWireFormat( dst, dstIndex + 1 );
dst[dstIndex++] = (byte)(( wordCount / 2 ) & 0xFF );
dstIndex += wordCount;
wordCount /= 2;
byteCount = writeBytesWireFormat( dst, dstIndex + 2 );
dst[dstIndex++] = (byte)( byteCount & 0xFF );
dst[dstIndex++] = (byte)(( byteCount >> 8 ) & 0xFF );
dstIndex += byteCount;
length = dstIndex - start;
if( digest != null ) {
digest.sign( dst, headerStart, length, this, response );
}
return length;
}
int decode( byte[] buffer, int bufferIndex ) {
int start = headerStart = bufferIndex;
bufferIndex += readHeaderWireFormat( buffer, bufferIndex );
wordCount = buffer[bufferIndex++];
if( wordCount != 0 ) {
int n;
if(( n = readParameterWordsWireFormat( buffer, bufferIndex )) != wordCount * 2 ) {
if( log.level >= 5 ) {
log.println( "wordCount * 2=" + ( wordCount * 2 ) +
" but readParameterWordsWireFormat returned " + n );
}
}
bufferIndex += wordCount * 2;
}
byteCount = readInt2( buffer, bufferIndex );
bufferIndex += 2;
if( byteCount != 0 ) {
int n;
if(( n = readBytesWireFormat( buffer, bufferIndex )) != byteCount ) {
if( log.level >= 5 ) {
log.println( "byteCount=" + byteCount +
" but readBytesWireFormat returned " + n );
}
}
// Don't think we can rely on n being correct here. Must use byteCount.
// Last paragraph of section 3.13.3 eludes to this.
bufferIndex += byteCount;
}
length = bufferIndex - start;
return length;
}
int writeHeaderWireFormat( byte[] dst, int dstIndex ) {
System.arraycopy( header, 0, dst, dstIndex, header.length );
dst[dstIndex + CMD_OFFSET] = command;
dst[dstIndex + FLAGS_OFFSET] = flags;
writeInt2( flags2, dst, dstIndex + FLAGS_OFFSET + 1 );
dstIndex += TID_OFFSET;
writeInt2( tid, dst, dstIndex );
writeInt2( pid, dst, dstIndex + 2 );
writeInt2( uid, dst, dstIndex + 4 );
writeInt2( mid, dst, dstIndex + 6 );
return HEADER_LENGTH;
}
int readHeaderWireFormat( byte[] buffer, int bufferIndex ) {
command = buffer[bufferIndex + CMD_OFFSET];
errorCode = readInt4( buffer, bufferIndex + ERROR_CODE_OFFSET );
flags = buffer[bufferIndex + FLAGS_OFFSET];
flags2 = readInt2( buffer, bufferIndex + FLAGS_OFFSET + 1 );
tid = readInt2( buffer, bufferIndex + TID_OFFSET );
pid = readInt2( buffer, bufferIndex + TID_OFFSET + 2 );
uid = readInt2( buffer, bufferIndex + TID_OFFSET + 4 );
mid = readInt2( buffer, bufferIndex + TID_OFFSET + 6 );
return HEADER_LENGTH;
}
boolean isResponse() {
return ( flags & FLAGS_RESPONSE ) == FLAGS_RESPONSE;
}
/*
* For this packet deconstruction technique to work for
* other networking protocols the InputStream may need
* to be passed to the readXxxWireFormat methods. This is
* actually purer. However, in the case of smb we know the
* wordCount and byteCount. And since every subclass of
* ServerMessageBlock would have to perform the same read
* operation on the input stream, we might as will pull that
* common functionality into the superclass and read wordCount
* and byteCount worth of data.
*
* We will still use the readXxxWireFormat return values to
* indicate how many bytes(note: readParameterWordsWireFormat
* returns bytes read and not the number of words(but the
* wordCount member DOES store the number of words)) we
* actually read. Incedentally this is important to the
* AndXServerMessageBlock class that needs to potentially
* read in another smb's parameter words and bytes based on
* information in it's andxCommand, andxOffset, ...etc.
*/
abstract int writeParameterWordsWireFormat( byte[] dst, int dstIndex );
abstract int writeBytesWireFormat( byte[] dst, int dstIndex );
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 ) {
case SMB_COM_NEGOTIATE:
c = "SMB_COM_NEGOTIATE";
break;
case SMB_COM_SESSION_SETUP_ANDX:
c = "SMB_COM_SESSION_SETUP_ANDX";
break;
case SMB_COM_TREE_CONNECT_ANDX:
c = "SMB_COM_TREE_CONNECT_ANDX";
break;
case SMB_COM_QUERY_INFORMATION:
c = "SMB_COM_QUERY_INFORMATION";
break;
case SMB_COM_CHECK_DIRECTORY:
c = "SMB_COM_CHECK_DIRECTORY";
break;
case SMB_COM_TRANSACTION:
c = "SMB_COM_TRANSACTION";
break;
case SMB_COM_TRANSACTION2:
c = "SMB_COM_TRANSACTION2";
break;
case SMB_COM_TRANSACTION_SECONDARY:
c = "SMB_COM_TRANSACTION_SECONDARY";
break;
case SMB_COM_FIND_CLOSE2:
c = "SMB_COM_FIND_CLOSE2";
break;
case SMB_COM_TREE_DISCONNECT:
c = "SMB_COM_TREE_DISCONNECT";
break;
case SMB_COM_LOGOFF_ANDX:
c = "SMB_COM_LOGOFF_ANDX";
break;
case SMB_COM_ECHO:
c = "SMB_COM_ECHO";
break;
case SMB_COM_MOVE:
c = "SMB_COM_MOVE";
break;
case SMB_COM_RENAME:
c = "SMB_COM_RENAME";
break;
case SMB_COM_DELETE:
c = "SMB_COM_DELETE";
break;
case SMB_COM_DELETE_DIRECTORY:
c = "SMB_COM_DELETE_DIRECTORY";
break;
case SMB_COM_NT_CREATE_ANDX:
c = "SMB_COM_NT_CREATE_ANDX";
break;
case SMB_COM_OPEN_ANDX:
c = "SMB_COM_OPEN_ANDX";
break;
case SMB_COM_READ_ANDX:
c = "SMB_COM_READ_ANDX";
break;
case SMB_COM_CLOSE:
c = "SMB_COM_CLOSE";
break;
case SMB_COM_WRITE_ANDX:
c = "SMB_COM_WRITE_ANDX";
break;
case SMB_COM_CREATE_DIRECTORY:
c = "SMB_COM_CREATE_DIRECTORY";
break;
case SMB_COM_NT_TRANSACT:
c = "SMB_COM_NT_TRANSACT";
break;
case SMB_COM_NT_TRANSACT_SECONDARY:
c = "SMB_COM_NT_TRANSACT_SECONDARY";
break;
default:
c = "UNKNOWN";
}
String str = errorCode == 0 ? "0" : SmbException.getMessageByCode( errorCode );
return new String(
"command=" + c +
",received=" + received +
",errorCode=" + str +
",flags=0x" + Hexdump.toHexString( flags & 0xFF, 4 ) +
",flags2=0x" + Hexdump.toHexString( flags2, 4 ) +
",signSeq=" + signSeq +
",tid=" + tid +
",pid=" + pid +
",uid=" + uid +
",mid=" + mid +
",wordCount=" + wordCount +
",byteCount=" + byteCount );
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy