bool as_root;
uint16_t fileid_ofs;
bool allow_invalid_fileid;
+ bool modify;
} smbd_smb2_table[] = {
#define _OP(o) .opcode = o, .name = #o
{
.need_session = true,
.need_tcon = true,
.fileid_ofs = 0x10,
+ .modify = true;
},{
_OP(SMB2_OP_LOCK),
.need_session = true,
.need_tcon = true,
.fileid_ofs = 0x08,
.allow_invalid_fileid = true,
+ .modify = true;
},{
_OP(SMB2_OP_CANCEL),
.as_root = true,
.need_session = true,
.need_tcon = true,
.fileid_ofs = 0x10,
+ .modify = true;
},{
_OP(SMB2_OP_BREAK),
.need_session = true,
uint16_t opcode;
uint32_t flags;
uint64_t mid;
+ uint16_t channel_sequence;
NTSTATUS status;
NTSTATUS session_status;
uint32_t allowed_flags;
struct smbXsrv_session *x = NULL;
bool signing_required = false;
bool encryption_required = false;
+ struct smbXsrv_open *op = NULL;
inhdr = SMBD_SMB2_IN_HDR_PTR(req);
flags = IVAL(inhdr, SMB2_HDR_FLAGS);
opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
+ channel_sequence = SVAL(inhdr, SMB2_HDR_CHANNEL_SEQUENCE);
DEBUG(10,("smbd_smb2_request_dispatch: opcode[%s] mid = %llu\n",
smb2_opcode_name(opcode),
(unsigned long long)mid));
if (opcode == SMB2_OP_CANCEL) {
allowed_flags |= SMB2_HDR_FLAG_ASYNC;
}
+ if (conn->protocol >= PROTOCOL_SMB2_22) {
+ allowed_flags |= SMB2_HDR_FLAG_REPLAY_OPERATION;
+ }
if ((flags & ~allowed_flags) != 0) {
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
}
file_id_volatile = BVAL(body, call->fileid_ofs + 8);
fsp = file_fsp_smb2(req, file_id_persistent, file_id_volatile);
- if (fsp == NULL) {
+ if (fsp != NULL) {
+ op = fsp->op;
+ } else {
if (!call->allow_invalid_fileid) {
return smbd_smb2_request_error(req,
NT_STATUS_FILE_CLOSED);
}
}
+ if ((conn->protocol >= PROTOCOL_SMB2_22) && (op != NULL)) {
+ int cmp = channel_sequence - op->global->channel_sequence;
+ bool overflow = false;
+
+ if (abs(cmp) > INT16_MAX) {
+ /*
+ * we like to handle an 16-bit overflow here.
+ *
+ * If the difference between the numbers
+ * if more than 15-bit, it is likely to be an overflow.
+ */
+ overflow = true;
+ cmp *= -1;
+ }
+
+ if (!(flags & SMB2_HDR_FLAG_REPLAY_OPERATION)) {
+ if (cmp == 0) {
+ op->request_count += 1;
+ } else if (cmp > 0) {
+ op->pre_request_count += op->request_count;
+ op->request_count = 0;
+ op->request_count += 1;
+ op->global->channel_sequence = channel_sequence;
+ update_open = true;
+ } else if (call->modify) {
+ return smbd_smb2_request_error(req,
+ NT_STATUS_FILE_NOT_AVAILABLE);
+ }
+ } else {
+ if (cmp == 0) {
+ if (op->pre_request_count == 0) {
+ op->request_count += 1;
+ } else if (call->modify) {
+ return smbd_smb2_request_error(req,
+ NT_STATUS_FILE_NOT_AVAILABLE);
+ }
+ } else if (cmp > 0) {
+ if (op->pre_request_count == 0) {
+ op->request_count += 1;
+ op->global->channel_sequence =
+ channel_sequence;
+ update_open = true;
+ } else if (call->modify) {
+ return smbd_smb2_request_error(req,
+ NT_STATUS_FILE_NOT_AVAILABLE);
+ }
+ } else {
+ if (call->modify) {
+ return smbd_smb2_request_error(req,
+ NT_STATUS_FILE_NOT_AVAILABLE);
+ }
+ }
+ }
+ }
+
if (call->as_root) {
SMB_ASSERT(call->fileid_ofs == 0);
/* This call needs to be run as root */