The branch, master has been updated via c90870f s4:torture/smb2: fix compound.invalid2 against windows via 09d3df6 s4:smb_server/smb2: correctly implement related compound requests via 95ca064 s4:smb_server/smb2: always grant the requested credits via f30fe1d s4:smb_server/smb2: echo back more header fields via 91648ae s3:smb2_server: FLAG_CHAINED means we always use the last session_id and tid via 8d07d71 s3:smb2_server: don't reset the tid and session id in the out hdr of compound requests via c7d3b6b s3:smb2_server: echo the SMB2_HDR_CREDIT_CHARGE and SMB2_HDR_SIGNATURE fields from 6c2c189 s4-torture: smb2 copychunk data integrity checks
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit c90870f9b728dfb827ebc2fe8ad67a7ca3a50c43 Author: Stefan Metzmacher <me...@samba.org> Date: Thu Oct 27 21:41:11 2011 +0200 s4:torture/smb2: fix compound.invalid2 against windows Tested against w2k8r2 with signing and win8pre0 without signing. metze Autobuild-User: Stefan Metzmacher <me...@samba.org> Autobuild-Date: Mon Oct 31 21:40:25 CET 2011 on sn-devel-104 commit 09d3df6e7e6aef03a306413e74ecd127215e1921 Author: Stefan Metzmacher <me...@samba.org> Date: Mon Oct 31 15:23:00 2011 +0100 s4:smb_server/smb2: correctly implement related compound requests We need to remember the session id and tree id. metze commit 95ca06410310589ef2ccf95f25b089dae756b1d0 Author: Stefan Metzmacher <me...@samba.org> Date: Mon Oct 31 13:43:01 2011 +0100 s4:smb_server/smb2: always grant the requested credits At least one credit, if the client asked for 0. metze commit f30fe1decdad3090655a759aeecd027bd59c386c Author: Stefan Metzmacher <me...@samba.org> Date: Thu Oct 27 20:46:12 2011 +0200 s4:smb_server/smb2: echo back more header fields metze commit 91648aeb6409787c7766943225f5c7a9c695aa0b Author: Stefan Metzmacher <me...@samba.org> Date: Thu Oct 27 16:35:28 2011 +0200 s3:smb2_server: FLAG_CHAINED means we always use the last session_id and tid metze commit 8d07d7148bf47ea14e62d39ed8a8cc4f1366810e Author: Stefan Metzmacher <me...@samba.org> Date: Thu Oct 27 13:01:22 2011 +0200 s3:smb2_server: don't reset the tid and session id in the out hdr of compound requests Windows also leaves tid (0xFFFFFFFF) and session id (0xFFFFFFFFFFFFFFFF) as the client requested them. metze commit c7d3b6b2c38711943910aebff72b0188b0c346db Author: Stefan Metzmacher <me...@samba.org> Date: Thu Oct 27 16:42:44 2011 +0200 s3:smb2_server: echo the SMB2_HDR_CREDIT_CHARGE and SMB2_HDR_SIGNATURE fields Windows just echos back the given values by default. metze ----------------------------------------------------------------------- Summary of changes: source3/smbd/globals.h | 2 + source3/smbd/smb2_server.c | 71 ++++++++++---------------------- source4/smb_server/smb2/receive.c | 47 +++++++++++++++++---- source4/smb_server/smb2/sesssetup.c | 7 +-- source4/smb_server/smb2/smb2_server.h | 2 + source4/smb_server/smb2/tcon.c | 9 ---- source4/torture/smb2/compound.c | 4 +- 7 files changed, 68 insertions(+), 74 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 14337e0..2e94b55 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -339,9 +339,11 @@ struct smbd_smb2_request { /* the session the request operates on, maybe NULL */ struct smbd_smb2_session *session; + uint64_t last_session_id; /* the tcon the request operates on, maybe NULL */ struct smbd_smb2_tcon *tcon; + uint32_t last_tid; int current_idx; bool do_signing; diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 84b55cc..5b41c3b 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -209,6 +209,9 @@ static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx) req->mem_pool = mem_pool; req->parent = parent; + req->last_session_id = UINT64_MAX; + req->last_tid = UINT32_MAX; + talloc_set_destructor(parent, smbd_smb2_request_parent_destructor); talloc_set_destructor(req, smbd_smb2_request_destructor); @@ -577,7 +580,8 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req) /* setup the SMB2 header */ SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); SSVAL(outhdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); - SSVAL(outhdr, SMB2_HDR_EPOCH, 0); + SSVAL(outhdr, SMB2_HDR_CREDIT_CHARGE, + SVAL(inhdr, SMB2_HDR_CREDIT_CHARGE)); SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(NT_STATUS_INTERNAL_ERROR)); SSVAL(outhdr, SMB2_HDR_OPCODE, @@ -593,7 +597,8 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req) IVAL(inhdr, SMB2_HDR_TID)); SBVAL(outhdr, SMB2_HDR_SESSION_ID, BVAL(inhdr, SMB2_HDR_SESSION_ID)); - memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16); + memcpy(outhdr + SMB2_HDR_SIGNATURE, + inhdr + SMB2_HDR_SIGNATURE, 16); /* setup error body header */ SSVAL(outbody, 0x00, 0x08 + 1); @@ -1139,32 +1144,20 @@ static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req) const uint8_t *inhdr; const uint8_t *outhdr; int i = req->current_idx; + uint32_t in_flags; uint32_t in_tid; void *p; struct smbd_smb2_tcon *tcon; - bool chained_fixup = false; + + req->tcon = NULL; inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; + in_flags = IVAL(inhdr, SMB2_HDR_FLAGS); in_tid = IVAL(inhdr, SMB2_HDR_TID); - if (in_tid == (0xFFFFFFFF)) { - if (req->async) { - /* - * async request - fill in tid from - * already setup out.vector[].iov_base. - */ - outhdr = (const uint8_t *)req->out.vector[i].iov_base; - in_tid = IVAL(outhdr, SMB2_HDR_TID); - } else if (i > 2) { - /* - * Chained request - fill in tid from - * the previous request out.vector[].iov_base. - */ - outhdr = (const uint8_t *)req->out.vector[i-3].iov_base; - in_tid = IVAL(outhdr, SMB2_HDR_TID); - chained_fixup = true; - } + if (in_flags & SMB2_HDR_FLAG_CHAINED) { + in_tid = req->last_tid; } /* lookup an existing session */ @@ -1184,12 +1177,7 @@ static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req) } req->tcon = tcon; - - if (chained_fixup) { - /* Fix up our own outhdr. */ - outhdr = (const uint8_t *)req->out.vector[i].iov_base; - SIVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_TID, in_tid); - } + req->last_tid = in_tid; return NT_STATUS_OK; } @@ -1203,32 +1191,21 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req) const uint8_t *inhdr; const uint8_t *outhdr; int i = req->current_idx; + uint32_t in_flags; uint64_t in_session_id; void *p; struct smbd_smb2_session *session; - bool chained_fixup = false; + + req->session = NULL; + req->tcon = NULL; inhdr = (const uint8_t *)req->in.vector[i+0].iov_base; + in_flags = IVAL(inhdr, SMB2_HDR_FLAGS); in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID); - if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) { - if (req->async) { - /* - * async request - fill in session_id from - * already setup request out.vector[].iov_base. - */ - outhdr = (const uint8_t *)req->out.vector[i].iov_base; - in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID); - } else if (i > 2) { - /* - * Chained request - fill in session_id from - * the previous request out.vector[].iov_base. - */ - outhdr = (const uint8_t *)req->out.vector[i-3].iov_base; - in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID); - chained_fixup = true; - } + if (in_flags & SMB2_HDR_FLAG_CHAINED) { + in_session_id = req->last_session_id; } /* lookup an existing session */ @@ -1247,12 +1224,8 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req) session->session_info->info->domain_name); req->session = session; + req->last_session_id = in_session_id; - if (chained_fixup) { - /* Fix up our own outhdr. */ - outhdr = (const uint8_t *)req->out.vector[i].iov_base; - SBVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_SESSION_ID, in_session_id); - } return NT_STATUS_OK; } diff --git a/source4/smb_server/smb2/receive.c b/source4/smb_server/smb2/receive.c index b51e2b0..0ebf8f3 100644 --- a/source4/smb_server/smb2/receive.c +++ b/source4/smb_server/smb2/receive.c @@ -69,6 +69,9 @@ struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn) 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; @@ -77,14 +80,22 @@ struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn) 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) { @@ -110,17 +121,19 @@ NTSTATUS smb2srv_setup_reply(struct smb2srv_request *req, uint16_t body_fixed_si 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)); @@ -223,6 +236,8 @@ static void smb2srv_chain_reply(struct smb2srv_request *p_req) 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; } @@ -332,9 +347,17 @@ static NTSTATUS smb2srv_reply(struct smb2srv_request *req) 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 @@ -569,11 +592,21 @@ NTSTATUS smb2srv_queue_pending(struct smb2srv_request *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) { @@ -583,11 +616,6 @@ NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req) 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); @@ -596,6 +624,7 @@ NTSTATUS smb2srv_queue_pending(struct smb2srv_request *req) } 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); diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c index 243765f..41f629b 100644 --- a/source4/smb_server/smb2/sesssetup.c +++ b/source4/smb_server/smb2/sesssetup.c @@ -31,12 +31,10 @@ static void smb2srv_sesssetup_send(struct smb2srv_request *req, union smb_sesssetup *io) { - uint16_t credit; - if (NT_STATUS_IS_OK(req->status)) { - credit = 0x0003; + /* nothing */ } else if (NT_STATUS_EQUAL(req->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { - credit = 0x0002; + /* nothing */ } else { smb2srv_send_error(req, req->status); return; @@ -44,7 +42,6 @@ static void smb2srv_sesssetup_send(struct smb2srv_request *req, union smb_sessse SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x08, true, io->smb2.out.secblob.length)); - SSVAL(req->out.hdr, SMB2_HDR_CREDIT, credit); SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, io->smb2.out.uid); SSVAL(req->out.body, 0x02, io->smb2.out.session_flags); diff --git a/source4/smb_server/smb2/smb2_server.h b/source4/smb_server/smb2/smb2_server.h index 7fb09f6..5fe12fe 100644 --- a/source4/smb_server/smb2/smb2_server.h +++ b/source4/smb_server/smb2/smb2_server.h @@ -64,6 +64,8 @@ struct smb2srv_request { /* chained file handle */ uint8_t _chained_file_handle[16]; uint8_t *chained_file_handle; + uint64_t chained_session_id; + uint32_t chained_tree_id; bool is_signed; diff --git a/source4/smb_server/smb2/tcon.c b/source4/smb_server/smb2/tcon.c index 0dac29c..6ee2eb5 100644 --- a/source4/smb_server/smb2/tcon.c +++ b/source4/smb_server/smb2/tcon.c @@ -359,23 +359,14 @@ failed: static void smb2srv_tcon_send(struct smb2srv_request *req, union smb_tcon *io) { - uint16_t credit; - if (!NT_STATUS_IS_OK(req->status)) { smb2srv_send_error(req, req->status); return; } - if (io->smb2.out.share_type == NTVFS_IPC) { - /* if it's an IPC share vista returns 0x0005 */ - credit = 0x0005; - } else { - credit = 0x0001; - } SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x10, false, 0)); SIVAL(req->out.hdr, SMB2_HDR_TID, io->smb2.out.tid); - SSVAL(req->out.hdr, SMB2_HDR_CREDIT,credit); SCVAL(req->out.body, 0x02, io->smb2.out.share_type); SCVAL(req->out.body, 0x03, io->smb2.out.reserved); diff --git a/source4/torture/smb2/compound.c b/source4/torture/smb2/compound.c index c40c71d..1caa688 100644 --- a/source4/torture/smb2/compound.c +++ b/source4/torture/smb2/compound.c @@ -367,9 +367,9 @@ static bool test_compound_invalid2(struct torture_context *tctx, status = smb2_close_recv(req[1], &cl); CHECK_STATUS(status, NT_STATUS_OK); status = smb2_close_recv(req[2], &cl); - CHECK_STATUS(status, NT_STATUS_FILE_CLOSED); + CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); status = smb2_close_recv(req[3], &cl); - CHECK_STATUS(status, NT_STATUS_FILE_CLOSED); + CHECK_STATUS(status, NT_STATUS_USER_SESSION_DELETED); status = smb2_close_recv(req[4], &cl); CHECK_STATUS(status, NT_STATUS_INVALID_PARAMETER); -- Samba Shared Repository