![JAR search and dependency download from the Maven repository](/logo.png)
jcifs.internal.smb2.ServerMessageBlock2 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
/*
* © 2017 AgNO3 Gmbh & Co. KG
*
* 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.internal.smb2;
import jcifs.Configuration;
import jcifs.internal.CommonServerMessageBlock;
import jcifs.internal.CommonServerMessageBlockResponse;
import jcifs.internal.SMBProtocolDecodingException;
import jcifs.internal.SMBSigningDigest;
import jcifs.internal.util.SMBUtil;
import jcifs.smb.SmbException;
import jcifs.util.Hexdump;
/**
*
* @author mbechler
*
*/
public abstract class ServerMessageBlock2 implements CommonServerMessageBlock {
/*
* These are all the smbs supported by this library. This includes requests
* and well as their responses for each type however the actual 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.
*/
protected static final short SMB2_NEGOTIATE = 0x00;
protected static final short SMB2_SESSION_SETUP = 0x01;
protected static final short SMB2_LOGOFF = 0x02;
protected static final short SMB2_TREE_CONNECT = 0x0003;
protected static final short SMB2_TREE_DISCONNECT = 0x0004;
protected static final short SMB2_CREATE = 0x0005;
protected static final short SMB2_CLOSE = 0x0006;
protected static final short SMB2_FLUSH = 0x0007;
protected static final short SMB2_READ = 0x0008;
protected static final short SMB2_WRITE = 0x0009;
protected static final short SMB2_LOCK = 0x000A;
protected static final short SMB2_IOCTL = 0x000B;
protected static final short SMB2_CANCEL = 0x000C;
protected static final short SMB2_ECHO = 0x000D;
protected static final short SMB2_QUERY_DIRECTORY = 0x000E;
protected static final short SMB2_CHANGE_NOTIFY = 0x000F;
protected static final short SMB2_QUERY_INFO = 0x0010;
protected static final short SMB2_SET_INFO = 0x0011;
protected static final short SMB2_OPLOCK_BREAK = 0x0012;
/**
*
*/
public static final int SMB2_FLAGS_SERVER_TO_REDIR = 0x00000001;
/**
*
*/
public static final int SMB2_FLAGS_ASYNC_COMMAND = 0x00000002;
/**
*
*/
public static final int SMB2_FLAGS_RELATED_OPERATIONS = 0x00000004;
/**
*
*/
public static final int SMB2_FLAGS_SIGNED = 0x00000008;
/**
*
*/
public static final int SMB2_FLAGS_PRIORITY_MASK = 0x00000070;
/**
*
*/
public static final int SMB2_FLAGS_DFS_OPERATIONS = 0x10000000;
/**
*
*/
public static final int SMB2_FLAGS_REPLAY_OPERATION = 0x20000000;
private int command;
private int flags;
private int length, headerStart, wordCount, byteCount;
private byte[] signature = new byte[16];
private Smb2SigningDigest digest = null;
private Configuration config;
private int creditCharge;
private int status;
private int credit;
private int nextCommand;
private int readSize;
private boolean async;
private int treeId;
private long mid, asyncId, sessionId;
private byte errorContextCount;
private byte[] errorData;
private boolean retainPayload;
private byte[] rawPayload;
private ServerMessageBlock2 next;
protected ServerMessageBlock2 ( Configuration config ) {
this.config = config;
}
protected ServerMessageBlock2 ( Configuration config, int command ) {
this.config = config;
this.command = command;
}
/**
* @return the config
*/
protected Configuration getConfig () {
return this.config;
}
@Override
public void reset () {
this.flags = 0;
this.digest = null;
this.sessionId = 0;
this.treeId = 0;
}
/**
* @return the command
*/
@Override
public final int getCommand () {
return this.command;
}
/**
* @return offset to next compound command
*/
public final int getNextCommandOffset () {
return this.nextCommand;
}
/**
* @param readSize
* the readSize to set
*/
public void setReadSize ( int readSize ) {
this.readSize = readSize;
}
/**
* @return the async
*/
public boolean isAsync () {
return this.async;
}
/**
* @param command
* the command to set
*/
@Override
public final void setCommand ( int command ) {
this.command = command;
}
/**
* @return the treeId
*/
public final int getTreeId () {
return this.treeId;
}
/**
* @param treeId
* the treeId to set
*/
public final void setTreeId ( int treeId ) {
this.treeId = treeId;
if ( this.next != null ) {
this.next.setTreeId(treeId);
}
}
/**
* @return the asyncId
*/
public final long getAsyncId () {
return this.asyncId;
}
/**
* @param asyncId
* the asyncId to set
*/
public final void setAsyncId ( long asyncId ) {
this.asyncId = asyncId;
}
/**
* @return the credit
*/
public final int getCredit () {
return this.credit;
}
/**
* @param credit
* the credit to set
*/
public final void setCredit ( int credit ) {
this.credit = credit;
}
/**
* @return the creditCharge
*/
public final int getCreditCharge () {
return this.creditCharge;
}
@Override
public void retainPayload () {
this.retainPayload = true;
}
@Override
public boolean isRetainPayload () {
return this.retainPayload;
}
@Override
public byte[] getRawPayload () {
return this.rawPayload;
}
@Override
public void setRawPayload ( byte[] rawPayload ) {
this.rawPayload = rawPayload;
}
/**
* {@inheritDoc}
*
* @see jcifs.internal.CommonServerMessageBlock#getDigest()
*/
@Override
public Smb2SigningDigest getDigest () {
return this.digest;
}
/**
*
* {@inheritDoc}
*
* @see jcifs.internal.CommonServerMessageBlock#setDigest(jcifs.internal.SMBSigningDigest)
*/
@Override
public void setDigest ( SMBSigningDigest digest ) {
this.digest = (Smb2SigningDigest) digest;
if ( this.next != null ) {
this.next.setDigest(digest);
}
}
/**
* @return the status
*/
public final int getStatus () {
return this.status;
}
/**
* @return the sessionId
*/
public long getSessionId () {
return this.sessionId;
}
/**
* @param sessionId
* the sessionId to set
*/
@Override
public final void setSessionId ( long sessionId ) {
this.sessionId = sessionId;
if ( this.next != null ) {
this.next.setSessionId(sessionId);
}
}
/**
* {@inheritDoc}
*
* @see jcifs.internal.CommonServerMessageBlock#setExtendedSecurity(boolean)
*/
@Override
public void setExtendedSecurity ( boolean extendedSecurity ) {
// ignore
}
/**
* {@inheritDoc}
*
* @see jcifs.internal.CommonServerMessageBlock#setUid(int)
*/
@Override
public void setUid ( int uid ) {
// ignore
}
/**
* @return the flags
*/
public final int getFlags () {
return this.flags;
}
/**
*
* @param flag
*/
public final void addFlags ( int flag ) {
this.flags |= flag;
}
/**
*
* @param flag
*/
public final void clearFlags ( int flag ) {
this.flags &= ~flag;
}
/**
* @return the mid
*/
@Override
public final long getMid () {
return this.mid;
}
/**
* @param mid
* the mid to set
*/
@Override
public final void setMid ( long mid ) {
this.mid = mid;
}
/**
* @param n
* @return whether chaining was successful
*/
public boolean chain ( ServerMessageBlock2 n ) {
if ( this.next != null ) {
return this.next.chain(n);
}
n.addFlags(SMB2_FLAGS_RELATED_OPERATIONS);
this.next = n;
return true;
}
protected ServerMessageBlock2 getNext () {
return this.next;
}
protected void setNext ( ServerMessageBlock2 n ) {
this.next = n;
}
/**
* @return the response
*/
@Override
public ServerMessageBlock2Response getResponse () {
return null;
}
/**
*
* {@inheritDoc}
*
* @see jcifs.internal.CommonServerMessageBlock#setResponse(jcifs.internal.CommonServerMessageBlockResponse)
*/
@Override
public void setResponse ( CommonServerMessageBlockResponse msg ) {
}
/**
* @return the errorData
*/
public final byte[] getErrorData () {
return this.errorData;
}
/**
* @return the errorContextCount
*/
public final byte getErrorContextCount () {
return this.errorContextCount;
}
/**
* @return the headerStart
*/
public final int getHeaderStart () {
return this.headerStart;
}
/**
* @return the length
*/
public final int getLength () {
return this.length;
}
@Override
public int encode ( byte[] dst, int dstIndex ) {
int start = this.headerStart = dstIndex;
dstIndex += writeHeaderWireFormat(dst, dstIndex);
this.byteCount = writeBytesWireFormat(dst, dstIndex);
dstIndex += this.byteCount;
dstIndex += pad8(dstIndex);
this.length = dstIndex - start;
int len = this.length;
if ( this.next != null ) {
int nextStart = dstIndex;
dstIndex += this.next.encode(dst, dstIndex);
int off = nextStart - start;
SMBUtil.writeInt4(off, dst, start + 20);
len += dstIndex - nextStart;
}
if ( this.digest != null ) {
this.digest.sign(dst, this.headerStart, this.length, this, getResponse());
}
if ( isRetainPayload() ) {
this.rawPayload = new byte[len];
System.arraycopy(dst, start, this.rawPayload, 0, len);
}
return len;
}
protected static final int size8 ( int size ) {
return size8(size, 0);
}
protected static final int size8 ( int size, int align ) {
int rem = size % 8 - align;
if ( rem == 0 ) {
return size;
}
if ( rem < 0 ) {
rem = 8 + rem;
}
return size + 8 - rem;
}
/**
* @param dstIndex
* @return
*/
protected final int pad8 ( int dstIndex ) {
int fromHdr = dstIndex - this.headerStart;
int rem = fromHdr % 8;
if ( rem == 0 ) {
return 0;
}
return 8 - rem;
}
@Override
public int decode ( byte[] buffer, int bufferIndex ) throws SMBProtocolDecodingException {
return decode(buffer, bufferIndex, false);
}
/**
* @param buffer
* @param bufferIndex
* @param compound
* @return decoded length
* @throws SMBProtocolDecodingException
*/
public int decode ( byte[] buffer, int bufferIndex, boolean compound ) throws SMBProtocolDecodingException {
int start = this.headerStart = bufferIndex;
bufferIndex += readHeaderWireFormat(buffer, bufferIndex);
if ( isErrorResponseStatus() ) {
bufferIndex += readErrorResponse(buffer, bufferIndex);
}
else {
bufferIndex += readBytesWireFormat(buffer, bufferIndex);
}
this.length = bufferIndex - start;
int len = this.length;
if ( this.nextCommand != 0 ) {
// padding becomes part of signature if this is _PART_ of a compound chain
len += pad8(bufferIndex);
}
else if ( compound && this.nextCommand == 0 && this.readSize > 0 ) {
// TODO: only apply this for actual compound chains, or is this correct for single responses, too?
// 3.2.5.1.9 Handling Compounded Responses
// The final response in the compounded response chain will have NextCommand equal to 0,
// and it MUST be processed as an individual message of a size equal to the number of bytes
// remaining in this receive.
int rem = this.readSize - this.length;
len += rem;
}
haveResponse(buffer, start, len);
if ( this.nextCommand != 0 && this.next != null ) {
if ( this.nextCommand % 8 != 0 ) {
throw new SMBProtocolDecodingException("Chained command is not aligned");
}
}
return len;
}
protected boolean isErrorResponseStatus () {
return getStatus() != 0;
}
/**
* @param buffer
* @param start
* @param len
* @throws SMBProtocolDecodingException
*/
protected void haveResponse ( byte[] buffer, int start, int len ) throws SMBProtocolDecodingException {}
/**
* @param buffer
* @param bufferIndex
* @return
* @throws Smb2ProtocolDecodingException
*/
protected int readErrorResponse ( byte[] buffer, int bufferIndex ) throws SMBProtocolDecodingException {
int start = bufferIndex;
int structureSize = SMBUtil.readInt2(buffer, bufferIndex);
if ( structureSize != 9 ) {
throw new SMBProtocolDecodingException("Error structureSize should be 9");
}
this.errorContextCount = buffer[ bufferIndex + 2 ];
bufferIndex += 4;
int bc = SMBUtil.readInt4(buffer, bufferIndex);
bufferIndex += 4;
if ( bc > 0 ) {
this.errorData = new byte[bc];
System.arraycopy(buffer, bufferIndex, this.errorData, 0, bc);
bufferIndex += bc;
}
return bufferIndex - start;
}
protected int writeHeaderWireFormat ( byte[] dst, int dstIndex ) {
System.arraycopy(SMBUtil.SMB2_HEADER, 0, dst, dstIndex, SMBUtil.SMB2_HEADER.length);
SMBUtil.writeInt2(this.creditCharge, dst, dstIndex + 6);
SMBUtil.writeInt2(this.command, dst, dstIndex + 12);
SMBUtil.writeInt2(this.credit, dst, dstIndex + 14);
SMBUtil.writeInt4(this.flags, dst, dstIndex + 16);
SMBUtil.writeInt4(this.nextCommand, dst, dstIndex + 20);
SMBUtil.writeInt8(this.mid, dst, dstIndex + 24);
if ( this.async ) {
SMBUtil.writeInt8(this.asyncId, dst, dstIndex + 32);
SMBUtil.writeInt8(this.sessionId, dst, dstIndex + 40);
}
else {
// 4 reserved
SMBUtil.writeInt4(this.treeId, dst, dstIndex + 36);
SMBUtil.writeInt8(this.sessionId, dst, dstIndex + 40);
// + signature
}
return Smb2Constants.SMB2_HEADER_LENGTH;
}
protected int readHeaderWireFormat ( byte[] buffer, int bufferIndex ) {
// these are common between SYNC/ASYNC
SMBUtil.readInt4(buffer, bufferIndex);
bufferIndex += 4;
SMBUtil.readInt2(buffer, bufferIndex);
this.creditCharge = SMBUtil.readInt2(buffer, bufferIndex + 2);
bufferIndex += 4;
this.status = SMBUtil.readInt4(buffer, bufferIndex);
bufferIndex += 4;
this.command = SMBUtil.readInt2(buffer, bufferIndex);
this.credit = SMBUtil.readInt2(buffer, bufferIndex + 2);
bufferIndex += 4;
this.flags = SMBUtil.readInt4(buffer, bufferIndex);
bufferIndex += 4;
this.nextCommand = SMBUtil.readInt4(buffer, bufferIndex);
bufferIndex += 4;
this.mid = SMBUtil.readInt8(buffer, bufferIndex);
bufferIndex += 8;
if ( ( this.flags & SMB2_FLAGS_ASYNC_COMMAND ) == SMB2_FLAGS_ASYNC_COMMAND ) {
// async
this.async = true;
this.asyncId = SMBUtil.readInt8(buffer, bufferIndex);
bufferIndex += 8;
this.sessionId = SMBUtil.readInt8(buffer, bufferIndex);
bufferIndex += 8;
System.arraycopy(buffer, bufferIndex, this.signature, 0, 16);
bufferIndex += 16;
}
else {
// sync
this.async = false;
bufferIndex += 4; // reserved
this.treeId = SMBUtil.readInt4(buffer, bufferIndex);
bufferIndex += 4;
this.sessionId = SMBUtil.readInt8(buffer, bufferIndex);
bufferIndex += 8;
System.arraycopy(buffer, bufferIndex, this.signature, 0, 16);
bufferIndex += 16;
}
return Smb2Constants.SMB2_HEADER_LENGTH;
}
boolean isResponse () {
return ( this.flags & SMB2_FLAGS_SERVER_TO_REDIR ) == SMB2_FLAGS_SERVER_TO_REDIR;
}
protected abstract int writeBytesWireFormat ( byte[] dst, int dstIndex );
protected abstract int readBytesWireFormat ( byte[] buffer, int bufferIndex ) throws SMBProtocolDecodingException;
@Override
public int hashCode () {
return (int) this.mid;
}
@Override
public boolean equals ( Object obj ) {
return obj instanceof ServerMessageBlock2 && ( (ServerMessageBlock2) obj ).mid == this.mid;
}
@Override
public String toString () {
String c;
switch ( this.command ) {
case SMB2_NEGOTIATE:
c = "SMB2_NEGOTIATE";
break;
case SMB2_SESSION_SETUP:
c = "SMB2_SESSION_SETUP";
break;
case SMB2_LOGOFF:
c = "SMB2_LOGOFF";
break;
case SMB2_TREE_CONNECT:
c = "SMB2_TREE_CONNECT";
break;
case SMB2_TREE_DISCONNECT:
c = "SMB2_TREE_DISCONNECT";
break;
case SMB2_CREATE:
c = "SMB2_CREATE";
break;
case SMB2_CLOSE:
c = "SMB2_CLOSE";
break;
case SMB2_FLUSH:
c = "SMB2_FLUSH";
break;
case SMB2_READ:
c = "SMB2_READ";
break;
case SMB2_WRITE:
c = "SMB2_WRITE";
break;
case SMB2_LOCK:
c = "SMB2_LOCK";
break;
case SMB2_IOCTL:
c = "SMB2_IOCTL";
break;
case SMB2_CANCEL:
c = "SMB2_CANCEL";
break;
case SMB2_ECHO:
c = "SMB2_ECHO";
break;
case SMB2_QUERY_DIRECTORY:
c = "SMB2_QUERY_DIRECTORY";
break;
case SMB2_CHANGE_NOTIFY:
c = "SMB2_CHANGE_NOTIFY";
break;
case SMB2_QUERY_INFO:
c = "SMB2_QUERY_INFO";
break;
case SMB2_SET_INFO:
c = "SMB2_SET_INFO";
break;
case SMB2_OPLOCK_BREAK:
c = "SMB2_OPLOCK_BREAK";
break;
default:
c = "UNKNOWN";
}
String str = this.status == 0 ? "0" : SmbException.getMessageByCode(this.status);
return new String(
"command=" + c + ",status=" + str + ",flags=0x" + Hexdump.toHexString(this.flags, 4) + ",mid=" + this.mid + ",wordCount=" + this.wordCount
+ ",byteCount=" + this.byteCount);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy