#include "libcli/smb2/smb2.h"
#include "libcli/smb2/smb2_calls.h"
#include "smb_server/smb_server.h"
-#include "smb_server/service_smb_proto.h"
#include "smb_server/smb2/smb2_server.h"
#include "smbd/service_stream.h"
#include "lib/stream/packet.h"
#include "ntvfs/ntvfs.h"
#include "param/param.h"
-#include "auth/gensec/gensec.h"
#include "auth/auth.h"
req->smb_conn = smb_conn;
+ req->chained_session_id = UINT64_MAX;
+ req->chained_tree_id = UINT32_MAX;
+
talloc_set_destructor(req, smb2srv_request_destructor);
return req;
NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_size,
bool body_dynamic_present, uint32_t body_dynamic_size)
{
- uint32_t flags = SMB2_HDR_FLAG_REDIRECT;
+ uint32_t flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
uint32_t pid = IVAL(req->in.hdr, SMB2_HDR_PID);
uint32_t tid = IVAL(req->in.hdr, SMB2_HDR_TID);
+ uint16_t credits = SVAL(req->in.hdr, SMB2_HDR_CREDIT);
+
+ if (credits == 0) {
+ credits = 1;
+ }
+
+ flags |= SMB2_HDR_FLAG_REDIRECT;
if (req->pending_id) {
flags |= SMB2_HDR_FLAG_ASYNC;
pid = req->pending_id;
tid = 0;
+ credits = 0;
}
if (body_dynamic_present) {
SIVAL(req->out.hdr, 0, SMB2_MAGIC);
SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
- SSVAL(req->out.hdr, SMB2_HDR_EPOCH, 0);
+ SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE,
+ SVAL(req->in.hdr, SMB2_HDR_CREDIT_CHARGE));
SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status));
SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE));
- SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0x0001);
+ SSVAL(req->out.hdr, SMB2_HDR_CREDIT, credits);
SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags);
SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, req->seqnum);
SIVAL(req->out.hdr, SMB2_HDR_PID, pid);
SIVAL(req->out.hdr, SMB2_HDR_TID, tid);
SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, BVAL(req->in.hdr, SMB2_HDR_SESSION_ID));
- memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
+ memcpy(req->out.hdr+SMB2_HDR_SIGNATURE,
+ req->in.hdr+SMB2_HDR_SIGNATURE, 16);
/* set the length of the fixed body part and +1 if there's a dynamic part also */
SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
static void smb2srv_chain_reply(struct smb2srv_request *p_req)
{
NTSTATUS status;
+ struct smbsrv_connection *smb_conn = p_req->smb_conn;
struct smb2srv_request *req;
uint32_t chain_offset;
uint32_t protocol_version;
uint16_t buffer_code;
uint32_t dynamic_size;
+ uint32_t flags;
+ uint32_t last_hdr_offset;
+
+ last_hdr_offset = p_req->in.hdr - p_req->in.buffer;
chain_offset = p_req->chain_offset;
p_req->chain_offset = 0;
- if (p_req->in.size < (NBT_HDR_SIZE + chain_offset + SMB2_MIN_SIZE_NO_BODY)) {
- DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X\n",
- chain_offset));
- smbsrv_terminate_connection(p_req->smb_conn, "Invalid SMB2 chained packet");
+ if (p_req->in.size < (last_hdr_offset + chain_offset + SMB2_MIN_SIZE_NO_BODY)) {
+ DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X from last hdr 0x%X\n",
+ chain_offset, last_hdr_offset));
+ smbsrv_terminate_connection(smb_conn, "Invalid SMB2 chained packet");
return;
}
- protocol_version = IVAL(p_req->in.buffer, NBT_HDR_SIZE + chain_offset);
+ protocol_version = IVAL(p_req->in.buffer, last_hdr_offset + chain_offset);
if (protocol_version != SMB2_MAGIC) {
DEBUG(2,("Invalid SMB chained packet: protocol prefix: 0x%08X\n",
protocol_version));
- smbsrv_terminate_connection(p_req->smb_conn, "NON-SMB2 chained packet");
+ smbsrv_terminate_connection(smb_conn, "NON-SMB2 chained packet");
return;
}
- req = smb2srv_init_request(p_req->smb_conn);
+ req = smb2srv_init_request(smb_conn);
if (!req) {
- smbsrv_terminate_connection(p_req->smb_conn, "SMB2 chained packet - no memory");
+ smbsrv_terminate_connection(smb_conn, "SMB2 chained packet - no memory");
return;
}
req->request_time = p_req->request_time;
req->in.allocated = req->in.size;
- req->in.hdr = req->in.buffer+ NBT_HDR_SIZE + chain_offset;
+ req->in.hdr = req->in.buffer+ last_hdr_offset + chain_offset;
req->in.body = req->in.hdr + SMB2_HDR_BODY;
- req->in.body_size = req->in.size - (NBT_HDR_SIZE+ chain_offset + SMB2_HDR_BODY);
+ req->in.body_size = req->in.size - (last_hdr_offset+ chain_offset + SMB2_HDR_BODY);
req->in.dynamic = NULL;
req->seqnum = BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
other packet types */
uint16_t opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
if (opcode == SMB2_OP_NEGPROT) {
- smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
+ smbsrv_terminate_connection(smb_conn, "Bad body size in SMB2 negprot");
} else {
smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
}
smb2srv_setup_bufinfo(req);
- if (p_req->chained_file_handle) {
- memcpy(req->_chained_file_handle,
- p_req->_chained_file_handle,
- sizeof(req->_chained_file_handle));
- req->chained_file_handle = req->_chained_file_handle;
+ flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
+ if (flags & SMB2_HDR_FLAG_CHAINED) {
+ if (p_req->chained_file_handle) {
+ memcpy(req->_chained_file_handle,
+ p_req->_chained_file_handle,
+ sizeof(req->_chained_file_handle));
+ req->chained_file_handle = req->_chained_file_handle;
+ }
+ req->chained_session_id = p_req->chained_session_id;
+ req->chained_tree_id = p_req->chained_tree_id;
+ req->chain_status = p_req->chain_status;
}
/*
status = smb2srv_reply(req);
if (!NT_STATUS_IS_OK(status)) {
- smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
+ smbsrv_terminate_connection(smb_conn, nt_errstr(status));
talloc_free(req);
return;
}
}
if (req->out.size > NBT_HDR_SIZE) {
- _smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
+ _smb_setlen_tcp(req->out.buffer, req->out.size - NBT_HDR_SIZE);
}
/* if signing is active on the session then sign the packet */
SSVAL(req->out.body, 0x02, 0);
SIVAL(req->out.body, 0x04, 0);
+ req->chain_status = NT_STATUS_INVALID_PARAMETER;
+
smb2srv_send_reply(req);
}
uid = BVAL(req->in.hdr, SMB2_HDR_SESSION_ID);
flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
- if (req->smb_conn->highest_smb2_seqnum != 0 &&
+ if (opcode != SMB2_OP_CANCEL &&
+ req->smb_conn->highest_smb2_seqnum != 0 &&
req->seqnum <= req->smb_conn->highest_smb2_seqnum) {
smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 sequence number");
return NT_STATUS_INVALID_PARAMETER;
}
- req->smb_conn->highest_smb2_seqnum = req->seqnum;
-
+ if (opcode != SMB2_OP_CANCEL) {
+ req->smb_conn->highest_smb2_seqnum = req->seqnum;
+ }
+
+ if (flags & SMB2_HDR_FLAG_CHAINED) {
+ uid = req->chained_session_id;
+ tid = req->chained_tree_id;
+ }
+
req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
+ req->chained_session_id = uid;
+ req->chained_tree_id = tid;
+
errno = 0;
/* supporting signing is mandatory in SMB2, and is per-packet. So we
return NT_STATUS_OK;
}
- /* TODO: check the seqnum */
+ if (!NT_STATUS_IS_OK(req->chain_status)) {
+ smb2srv_send_error(req, req->chain_status);
+ return NT_STATUS_OK;
+ }
switch (opcode) {
case SMB2_OP_NEGPROT:
uint32_t protocol_version;
uint16_t buffer_code;
uint32_t dynamic_size;
+ uint32_t flags;
smb_conn->statistics.last_request_time = cur_time;
uint16_t opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
if (opcode == SMB2_OP_NEGPROT) {
smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
+ return NT_STATUS_OK;
} else {
smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
+ return NT_STATUS_OK;
}
}
* - make sure it's a request
*/
+ flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
+ /* the first request should never have the related flag set */
+ if (flags & SMB2_HDR_FLAG_CHAINED) {
+ req->chain_status = NT_STATUS_INVALID_PARAMETER;
+ }
+
return smb2srv_reply(req);
}
NTSTATUS status;
bool signing_used = false;
int id;
+ uint16_t credits = SVAL(req->in.hdr, SMB2_HDR_CREDIT);
+
+ if (credits == 0) {
+ credits = 1;
+ }
if (req->pending_id) {
return NT_STATUS_INTERNAL_ERROR;
}
+ if (req->smb_conn->connection->event.fde == NULL) {
+ /* the socket has been destroyed - no point trying to send an error! */
+ return NT_STATUS_REMOTE_DISCONNECT;
+ }
+
id = idr_get_new_above(req->smb_conn->requests2.idtree_req, req,
1, req->smb_conn->requests2.idtree_limit);
if (id == -1) {
DLIST_ADD_END(req->smb_conn->requests2.list, req, struct smb2srv_request *);
req->pending_id = id;
- if (req->smb_conn->connection->event.fde == NULL) {
- /* the socket has been destroyed - no point trying to send an error! */
- return NT_STATUS_REMOTE_DISCONNECT;
- }
-
talloc_set_destructor(req, smb2srv_request_deny_destructor);
status = smb2srv_setup_reply(req, 8, true, 0);
}
SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
+ SSVAL(req->out.hdr, SMB2_HDR_CREDIT, credits);
SSVAL(req->out.body, 0x02, 0);
SIVAL(req->out.body, 0x04, 0);
/* this is the size that w2k uses, and it appears to be important for
good performance */
- smb_conn->negotiate.max_recv = lp_max_xmit(smb_conn->lp_ctx);
+ smb_conn->negotiate.max_recv = lpcfg_max_xmit(smb_conn->lp_ctx);
smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
- smb_conn->config.security = SEC_USER;
smb_conn->config.nt_status_support = true;
status = smbsrv_init_sessions(smb_conn, UINT64_MAX);