All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hierynomus.mssmb2.SMB2Header Maven / Gradle / Ivy

There is a newer version: 0.13.0
Show newest version
/*
 * Copyright (C)2016 - SMBJ Contributors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.hierynomus.mssmb2;

import com.hierynomus.protocol.commons.buffer.Buffer;
import com.hierynomus.smb.SMBBuffer;
import com.hierynomus.smb.SMBHeader;
import com.hierynomus.smbj.common.Check;

import static com.hierynomus.protocol.commons.EnumWithValue.EnumUtils.isSet;

/**
 * [MS-SMB2].pdf 2.2.1 SMB2 Packet Header
 */
public class SMB2Header implements SMBHeader {
    public static final byte[] EMPTY_SIGNATURE = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
    public static final int STRUCTURE_SIZE = 64;
    public static final int SIGNATURE_OFFSET = 48;
    public static final int SIGNATURE_SIZE = 16;

    private SMB2Dialect dialect;
    private int creditCharge = 1;
    private int creditRequest;
    private int creditResponse;
    private SMB2MessageCommandCode message;
    private long messageId;
    private long asyncId;
    private long sessionId;
    private long treeId;
    private long statusCode;
    private long flags;
    private long nextCommandOffset; // TODO Message Compounding
    private byte[] signature;
    // We need to keep track of where the header is in the buffer, for both signature verification as well as compounding.
    private int headerStartPosition;

    @Override
    public void writeTo(SMBBuffer buffer) {
        this.headerStartPosition = buffer.wpos(); // Set the current start position of the header.
        buffer.putRawBytes(new byte[]{(byte) 0xFE, 'S', 'M', 'B'}); // ProtocolId (4 byte)
        buffer.putUInt16(STRUCTURE_SIZE); // StructureSize (2 byte)
        writeCreditCharge(buffer); // CreditCharge (2 byte)
        writeChannelSequenceReserved(buffer); // (ChannelSequence/Reserved)/Status (4 bytes)
        buffer.putUInt16(message.getValue()); // Command (2 bytes)
        writeCreditRequest(buffer); // CreditRequest (2 bytes)
        buffer.putUInt32(flags); // Flags (4 bytes)
        buffer.putUInt32(nextCommandOffset); // NextCommand (4 bytes)
        buffer.putLong(messageId); // MessageId (8 bytes)
        if (isSet(flags, SMB2MessageFlag.SMB2_FLAGS_ASYNC_COMMAND)) {
            buffer.putLong(asyncId);
        } else {
            buffer.putReserved4(); // Reserved (4 bytes)
            buffer.putUInt32(treeId); // TreeId (4 bytes)
        }
        buffer.putLong(sessionId); // SessionId (8 bytes)
        buffer.putRawBytes(EMPTY_SIGNATURE); // Signature (16 bytes)
    }

    private void writeChannelSequenceReserved(SMBBuffer buffer) {
        if (dialect.isSmb3x()) {
            buffer.putRawBytes(new byte[]{0x0, 0x0}); // ChannelSequence (2 bytes)
            buffer.putReserved(2); // Reserved (2 bytes)
            throw new UnsupportedOperationException("SMB 3.x not yet implemented");
        } else {
            buffer.putReserved4(); // Status (4 bytes) (reserved on request)
        }
    }

    /**
     * [MS-SMB2].pdf 3.2.4.1.2 Requesting Credits from the Server
     * 

* We should at least request the number of credits this request consumes, but we can request more (by calling {@link #setCreditRequest(int)}). */ private void writeCreditRequest(SMBBuffer buffer) { buffer.putUInt16(creditRequest + creditCharge); // Ask for the credit buffer wanted + what we use } private void writeCreditCharge(SMBBuffer buffer) { switch (dialect) { case UNKNOWN: case SMB_2_0_2: buffer.putReserved(2); break; default: buffer.putUInt16(creditCharge); break; } } public void setMessageId(long messageId) { this.messageId = messageId; } void setMessageType(SMB2MessageCommandCode messageType) { this.message = messageType; } public SMB2MessageCommandCode getMessage() { return message; } public long getTreeId() { return treeId; } public void setTreeId(long treeId) { this.treeId = treeId; } public long getSessionId() { return sessionId; } public void setSessionId(long sessionId) { this.sessionId = sessionId; } public void setDialect(SMB2Dialect dialect) { this.dialect = dialect; } public boolean isFlagSet(SMB2MessageFlag flag) { return isSet(this.flags, flag); } public void setFlag(SMB2MessageFlag flag) { this.flags |= flag.getValue(); } public long getMessageId() { return messageId; } public void setCreditRequest(int creditRequest) { this.creditRequest = creditRequest; } public int getCreditResponse() { return creditResponse; } public void setAsyncId(long asyncId) { this.asyncId = asyncId; } public long getAsyncId() { return asyncId; } @Override public void readFrom(Buffer buffer) throws Buffer.BufferException { this.headerStartPosition = buffer.rpos(); // Keep track of the header start position. byte[] protocolId = buffer.readRawBytes(4); // ProtocolId (4 bytes) (already verified) Check.ensureEquals(protocolId, new byte[]{(byte) 0xFE, 'S', 'M', 'B'}, "Could not find SMB2 Packet header"); buffer.skip(2); // StructureSize (2 bytes) buffer.readUInt16(); // CreditCharge (2 bytes) statusCode = buffer.readUInt32(); // Status (4 bytes) message = SMB2MessageCommandCode.lookup(buffer.readUInt16()); // Command (2 bytes) creditResponse = buffer.readUInt16(); // CreditRequest/CreditResponse (2 bytes) flags = buffer.readUInt32(); // Flags (4 bytes) nextCommandOffset = buffer.readUInt32(); // NextCommand (4 bytes) messageId = buffer.readLong(); // MessageId (4 bytes) if (isSet(flags, SMB2MessageFlag.SMB2_FLAGS_ASYNC_COMMAND)) { asyncId = buffer.readLong(); } else { buffer.skip(4); // Reserved (4 bytes) treeId = buffer.readUInt32(); // TreeId (4 bytes) } sessionId = buffer.readLong(); // SessionId (8 bytes) signature = buffer.readRawBytes(16); // Signature (16 bytes) } public void setStatusCode(long statusCode) { this.statusCode = statusCode; } public long getStatusCode() { return statusCode; } public long getFlags() { return flags; } public void setFlags(long flags) { this.flags = flags; } public long getNextCommandOffset() { return nextCommandOffset; } public void setNextCommandOffset(long nextCommandOffset) { this.nextCommandOffset = nextCommandOffset; } public void setCreditCharge(int creditCharge) { this.creditCharge = creditCharge; } public String toString() { return String.format( "dialect=%s, creditCharge=%s, creditRequest=%s, creditResponse=%s, message=%s, messageId=%s, asyncId=%s, sessionId=%s, treeId=%s, status=0x%08x, flags=%s, nextCommandOffset=%s", dialect, creditCharge, creditRequest, creditResponse, message, messageId, asyncId, sessionId, treeId, statusCode, flags, nextCommandOffset); } public int getCreditCharge() { return creditCharge; } public byte[] getSignature() { return signature; } public int getHeaderStartPosition() { return headerStartPosition; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy