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-ng Show documentation
Show all versions of jcifs-ng Show documentation
A pure-java CIFS/SMB client library
/*
* © 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 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;
}
/**
* @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 ( compound || this.nextCommand != 0 ) {
// padding becomes part of signature if this is _PART_ of a compound chain
len += pad8(bufferIndex);
}
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 - 2024 Weber Informatics LLC | Privacy Policy