The branch, master has been updated via c301691 s3:smb2_server: fix SMB2 signing of compound responses via 40f771e s3:smb2_server: there's no need to copy req->out.vector when we just keep the last request via 8d63efe s3:smb2_server: use memmove instead of copying single vector elements via 9b8973d s3:smb2_server: make use of SMBD_SMB2_OUT_HDR_PTR() smbd_smb2_request_pending_queue() via bfc87a4 s3:smb2_server: check for compound based on SMBD_SMB2_NUM_IOV_PER_REQ via 5730272 s3:smb2_server: make use of SMBD_SMB2_OUT_*_IOV smbd_smb2_request_reply() via 727b1d1 s3:smb2_server: check for compound based on SMBD_SMB2_NUM_IOV_PER_REQ via 2da6217 s3:smb2_server: make use of SMBD_SMB2_*_IOV_OFS via d609bb9 s3:smb2_server: make use of helper macros in smb2_calculate_credits() via efaea8e s3:smb2_server: make use of helper macros in smbd_smb2_request_validate() via 4e6e1ec s3:smb2_server: make use of SMBD_SMB2_NUM_IOV_PER_REQ via 337604a s3:smb2_server: add some more SMBD_SMB2_* defines/macros from d825adf s3-param: Remove never-reached condition for popts == NULL
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit c3016915a1ea381976b747c4e185d4046e7995ca Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 14:24:28 2012 +0200 s3:smb2_server: fix SMB2 signing of compound responses We need to defer the signing until we know the response doesn't change anymore before it goes over the wire. metze Autobuild-User(master): Stefan Metzmacher <me...@samba.org> Autobuild-Date(master): Tue Aug 7 20:29:30 CEST 2012 on sn-devel-104 commit 40f771e0105a0d13d83d66d99d9412acf6b73978 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 13:02:14 2012 +0200 s3:smb2_server: there's no need to copy req->out.vector when we just keep the last request metze commit 8d63efe27397f0f45b774e04e6146f87a84ba799 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 13:00:50 2012 +0200 s3:smb2_server: use memmove instead of copying single vector elements metze commit 9b8973d3b528169bf70a57f3cc17f35e51dfc81e Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:57:14 2012 +0200 s3:smb2_server: make use of SMBD_SMB2_OUT_HDR_PTR() smbd_smb2_request_pending_queue() metze commit bfc87a4a76294b26f6031547e18228afd4d535e5 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:56:23 2012 +0200 s3:smb2_server: check for compound based on SMBD_SMB2_NUM_IOV_PER_REQ metze commit 5730272690b5f4d854a4c7e8b0d68040b159d6aa Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:55:28 2012 +0200 s3:smb2_server: make use of SMBD_SMB2_OUT_*_IOV smbd_smb2_request_reply() metze commit 727b1d1fa867e1421cc01f4eee95f8001d315a12 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:47:44 2012 +0200 s3:smb2_server: check for compound based on SMBD_SMB2_NUM_IOV_PER_REQ metze commit 2da62179de7d2547703ff6ae78f80518abed91b8 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:41:07 2012 +0200 s3:smb2_server: make use of SMBD_SMB2_*_IOV_OFS metze commit d609bb9b4201f50322278e949fe036fe70c1e77f Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:31:36 2012 +0200 s3:smb2_server: make use of helper macros in smb2_calculate_credits() metze commit efaea8e0e1ca389ac7bd82f2d9a3401f92094fe4 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:30:54 2012 +0200 s3:smb2_server: make use of helper macros in smbd_smb2_request_validate() metze commit 4e6e1ecb6eb948c9651c6a1e17319c75191a1bac Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:26:38 2012 +0200 s3:smb2_server: make use of SMBD_SMB2_NUM_IOV_PER_REQ metze commit 337604a0cff2c4a09b4e29b88650149db897b8b2 Author: Stefan Metzmacher <me...@samba.org> Date: Tue Aug 7 12:22:06 2012 +0200 s3:smb2_server: add some more SMBD_SMB2_* defines/macros metze ----------------------------------------------------------------------- Summary of changes: source3/smbd/globals.h | 34 ++++++- source3/smbd/smb2_server.c | 228 +++++++++++++++++++++++++++----------------- 2 files changed, 169 insertions(+), 93 deletions(-) Changeset truncated at 500 lines: diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 967fe85..7b2d31d 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -460,6 +460,12 @@ struct smbd_smb2_request { bool cancelled; bool compound_related; + /* + * the signing/encryption key for the last + * request/response of a compound chain + */ + DATA_BLOB last_key; + struct timeval request_time; /* fake smb1 request. */ @@ -474,21 +480,37 @@ struct smbd_smb2_request { */ struct tevent_req *subreq; -#define SMBD_SMB2_IN_HDR_IOV(req) (&req->in.vector[req->current_idx+0]) +#define SMBD_SMB2_HDR_IOV_OFS 0 +#define SMBD_SMB2_BODY_IOV_OFS 1 +#define SMBD_SMB2_DYN_IOV_OFS 2 + +#define SMBD_SMB2_NUM_IOV_PER_REQ 3 + +#define SMBD_SMB2_IOV_IDX_OFS(req,dir,idx,ofs) \ + (&req->dir.vector[(idx)+(ofs)]) + +#define SMBD_SMB2_IDX_HDR_IOV(req,dir,idx) \ + SMBD_SMB2_IOV_IDX_OFS(req,dir,idx,SMBD_SMB2_HDR_IOV_OFS) +#define SMBD_SMB2_IDX_BODY_IOV(req,dir,idx) \ + SMBD_SMB2_IOV_IDX_OFS(req,dir,idx,SMBD_SMB2_BODY_IOV_OFS) +#define SMBD_SMB2_IDX_DYN_IOV(req,dir,idx) \ + SMBD_SMB2_IOV_IDX_OFS(req,dir,idx,SMBD_SMB2_DYN_IOV_OFS) + +#define SMBD_SMB2_IN_HDR_IOV(req) SMBD_SMB2_IDX_HDR_IOV(req,in,req->current_idx) #define SMBD_SMB2_IN_HDR_PTR(req) (uint8_t *)(SMBD_SMB2_IN_HDR_IOV(req)->iov_base) -#define SMBD_SMB2_IN_BODY_IOV(req) (&req->in.vector[req->current_idx+1]) +#define SMBD_SMB2_IN_BODY_IOV(req) SMBD_SMB2_IDX_BODY_IOV(req,in,req->current_idx) #define SMBD_SMB2_IN_BODY_PTR(req) (uint8_t *)(SMBD_SMB2_IN_BODY_IOV(req)->iov_base) #define SMBD_SMB2_IN_BODY_LEN(req) (SMBD_SMB2_IN_BODY_IOV(req)->iov_len) -#define SMBD_SMB2_IN_DYN_IOV(req) (&req->in.vector[req->current_idx+2]) +#define SMBD_SMB2_IN_DYN_IOV(req) SMBD_SMB2_IDX_DYN_IOV(req,in,req->current_idx) #define SMBD_SMB2_IN_DYN_PTR(req) (uint8_t *)(SMBD_SMB2_IN_DYN_IOV(req)->iov_base) #define SMBD_SMB2_IN_DYN_LEN(req) (SMBD_SMB2_IN_DYN_IOV(req)->iov_len) -#define SMBD_SMB2_OUT_HDR_IOV(req) (&req->out.vector[req->current_idx+0]) +#define SMBD_SMB2_OUT_HDR_IOV(req) SMBD_SMB2_IDX_HDR_IOV(req,out,req->current_idx) #define SMBD_SMB2_OUT_HDR_PTR(req) (uint8_t *)(SMBD_SMB2_OUT_HDR_IOV(req)->iov_base) -#define SMBD_SMB2_OUT_BODY_IOV(req) (&req->out.vector[req->current_idx+1]) +#define SMBD_SMB2_OUT_BODY_IOV(req) SMBD_SMB2_IDX_BODY_IOV(req,out,req->current_idx) #define SMBD_SMB2_OUT_BODY_PTR(req) (uint8_t *)(SMBD_SMB2_OUT_BODY_IOV(req)->iov_base) #define SMBD_SMB2_OUT_BODY_LEN(req) (SMBD_SMB2_OUT_BODY_IOV(req)->iov_len) -#define SMBD_SMB2_OUT_DYN_IOV(req) (&req->out.vector[req->current_idx+2]) +#define SMBD_SMB2_OUT_DYN_IOV(req) SMBD_SMB2_IDX_DYN_IOV(req,out,req->current_idx) #define SMBD_SMB2_OUT_DYN_PTR(req) (uint8_t *)(SMBD_SMB2_OUT_DYN_IOV(req)->iov_base) #define SMBD_SMB2_OUT_DYN_LEN(req) (SMBD_SMB2_OUT_DYN_IOV(req)->iov_len) diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 4e3259a..afd001c 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -235,6 +235,12 @@ static void smb2_setup_nbt_length(struct iovec *vector, int count) _smb2_setlen(vector[0].iov_base, len); } +static int smbd_smb2_request_destructor(struct smbd_smb2_request *req) +{ + data_blob_clear_free(&req->last_key); + return 0; +} + static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx) { TALLOC_CTX *mem_pool; @@ -261,6 +267,8 @@ static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx) req->last_session_id = UINT64_MAX; req->last_tid = UINT32_MAX; + talloc_set_destructor(req, smbd_smb2_request_destructor); + return req; } @@ -292,6 +300,9 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn, size_t full_size; size_t next_command_ofs; uint16_t body_size; + uint8_t *body = NULL; + uint32_t dyn_size; + uint8_t *dyn = NULL; struct iovec *iov_tmp; /* @@ -338,23 +349,26 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *conn, */ body_size = full_size - SMB2_HDR_BODY; } + body = hdr + SMB2_HDR_BODY; + dyn = body + body_size; + dyn_size = full_size - (SMB2_HDR_BODY + body_size); iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec, - num_iov + 3); + num_iov + SMBD_SMB2_NUM_IOV_PER_REQ); if (iov_tmp == NULL) { TALLOC_FREE(iov); return NT_STATUS_NO_MEMORY; } iov = iov_tmp; cur = &iov[num_iov]; - num_iov += 3; + num_iov += SMBD_SMB2_NUM_IOV_PER_REQ; - cur[0].iov_base = hdr; - cur[0].iov_len = SMB2_HDR_BODY; - cur[1].iov_base = hdr + SMB2_HDR_BODY; - cur[1].iov_len = body_size; - cur[2].iov_base = hdr + SMB2_HDR_BODY + body_size; - cur[2].iov_len = full_size - (SMB2_HDR_BODY + body_size); + cur[SMBD_SMB2_HDR_IOV_OFS].iov_base = hdr; + cur[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY; + cur[SMBD_SMB2_BODY_IOV_OFS].iov_base = body; + cur[SMBD_SMB2_BODY_IOV_OFS].iov_len = body_size; + cur[SMBD_SMB2_DYN_IOV_OFS].iov_base = dyn; + cur[SMBD_SMB2_DYN_IOV_OFS].iov_len = dyn_size; taken += full_size; } @@ -584,24 +598,26 @@ static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req) count = req->in.vector_count; - if (count < 4) { + if (count < 1 + SMBD_SMB2_NUM_IOV_PER_REQ) { /* It's not a SMB2 request */ return NT_STATUS_INVALID_PARAMETER; } - for (idx=1; idx < count; idx += 3) { + for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) { + struct iovec *hdr = SMBD_SMB2_IDX_HDR_IOV(req,in,idx); + struct iovec *body = SMBD_SMB2_IDX_BODY_IOV(req,in,idx); const uint8_t *inhdr = NULL; uint32_t flags; - if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) { + if (hdr->iov_len != SMB2_HDR_BODY) { return NT_STATUS_INVALID_PARAMETER; } - if (req->in.vector[idx+1].iov_len < 2) { + if (body->iov_len < 2) { return NT_STATUS_INVALID_PARAMETER; } - inhdr = (const uint8_t *)req->in.vector[idx].iov_base; + inhdr = (const uint8_t *)hdr->iov_base; /* Check the SMB2 header */ if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) { @@ -799,16 +815,18 @@ static void smb2_calculate_credits(const struct smbd_smb2_request *inreq, count = outreq->out.vector_count; - for (idx=1; idx < count; idx += 3) { - uint8_t *outhdr = (uint8_t *)outreq->out.vector[idx].iov_base; - smb2_set_operation_credit(outreq->sconn, - &inreq->in.vector[idx], - &outreq->out.vector[idx]); + for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) { + struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(inreq,in,idx); + struct iovec *outhdr_v = SMBD_SMB2_IDX_HDR_IOV(outreq,out,idx); + uint8_t *outhdr = (uint8_t *)outhdr_v->iov_base; + + smb2_set_operation_credit(outreq->sconn, inhdr_v, outhdr_v); + /* To match Windows, count up what we just granted. */ total_credits += SVAL(outhdr, SMB2_HDR_CREDIT); /* Set to zero in all but the last reply. */ - if (idx + 3 < count) { + if (idx + SMBD_SMB2_NUM_IOV_PER_REQ < count) { SSVAL(outhdr, SMB2_HDR_CREDIT, 0); } else { SSVAL(outhdr, SMB2_HDR_CREDIT, total_credits); @@ -832,21 +850,20 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req) vector[0].iov_len = 4; SIVAL(req->out.nbt_hdr, 0, 0); - for (idx=1; idx < count; idx += 3) { - const uint8_t *inhdr = NULL; + for (idx=1; idx < count; idx += SMBD_SMB2_NUM_IOV_PER_REQ) { + struct iovec *inhdr_v = SMBD_SMB2_IDX_HDR_IOV(req,in,idx); + const uint8_t *inhdr = (const uint8_t *)inhdr_v->iov_base; uint8_t *outhdr = NULL; uint8_t *outbody = NULL; uint32_t next_command_ofs = 0; struct iovec *current = &vector[idx]; - if ((idx + 3) < count) { + if ((idx + SMBD_SMB2_NUM_IOV_PER_REQ) < count) { /* we have a next command - * setup for the error case. */ next_command_ofs = SMB2_HDR_BODY + 9; } - inhdr = (const uint8_t *)req->in.vector[idx].iov_base; - outhdr = talloc_zero_array(vector, uint8_t, OUTVEC_ALLOC_SIZE); if (outhdr == NULL) { @@ -855,14 +872,14 @@ static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req) outbody = outhdr + SMB2_HDR_BODY; - current[0].iov_base = (void *)outhdr; - current[0].iov_len = SMB2_HDR_BODY; + current[SMBD_SMB2_HDR_IOV_OFS].iov_base = (void *)outhdr; + current[SMBD_SMB2_HDR_IOV_OFS].iov_len = SMB2_HDR_BODY; - current[1].iov_base = (void *)outbody; - current[1].iov_len = 8; + current[SMBD_SMB2_BODY_IOV_OFS].iov_base = (void *)outbody; + current[SMBD_SMB2_BODY_IOV_OFS].iov_len = 8; - current[2].iov_base = NULL; - current[2].iov_len = 0; + current[SMBD_SMB2_DYN_IOV_OFS].iov_base = NULL; + current[SMBD_SMB2_DYN_IOV_OFS].iov_len = 0; /* setup the SMB2 header */ SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); @@ -1013,7 +1030,7 @@ static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *re memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4); /* Setup the vectors identically to the ones in req. */ - for (i = 1; i < count; i += 3) { + for (i = 1; i < count; i += SMBD_SMB2_NUM_IOV_PER_REQ) { if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) { break; } @@ -1035,9 +1052,11 @@ static void smbd_smb2_request_writev_done(struct tevent_req *subreq); static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request *req) { - int i = 0; + struct smbXsrv_connection *conn = req->sconn->conn; + struct iovec *outhdr_v = NULL; uint8_t *outhdr = NULL; struct smbd_smb2_request *nreq = NULL; + NTSTATUS status; /* Create a new smb2 request we'll use for the interim return. */ @@ -1046,36 +1065,37 @@ static NTSTATUS smb2_send_async_interim_response(const struct smbd_smb2_request return NT_STATUS_NO_MEMORY; } - /* Lose the last 3 out vectors. They're the + /* Lose the last X out vectors. They're the ones we'll be using for the async reply. */ - nreq->out.vector_count -= 3; + nreq->out.vector_count -= SMBD_SMB2_NUM_IOV_PER_REQ; smb2_setup_nbt_length(nreq->out.vector, nreq->out.vector_count); /* Step back to the previous reply. */ - i = nreq->current_idx - 3; - outhdr = (uint8_t *)nreq->out.vector[i].iov_base; + nreq->current_idx -= SMBD_SMB2_NUM_IOV_PER_REQ; + outhdr_v = SMBD_SMB2_OUT_HDR_IOV(nreq); + outhdr = SMBD_SMB2_OUT_HDR_PTR(nreq); /* And end the chain. */ SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0); /* Calculate outgoing credits */ smb2_calculate_credits(req, nreq); - /* Re-sign if needed. */ - if (nreq->do_signing) { - NTSTATUS status; - struct smbXsrv_session *x = nreq->session; - struct smbXsrv_connection *conn = x->connection; - DATA_BLOB signing_key = x->global->channels[0].signing_key; - - status = smb2_signing_sign_pdu(signing_key, + /* + * As we have changed the header (SMB2_HDR_NEXT_COMMAND), + * we need to sign here with the last signing key we remembered + */ + if (req->last_key.length > 0) { + status = smb2_signing_sign_pdu(req->last_key, conn->protocol, - &nreq->out.vector[i], 3); + outhdr_v, + SMBD_SMB2_NUM_IOV_PER_REQ); if (!NT_STATUS_IS_OK(status)) { return status; } } + if (DEBUGLEVEL >= 10) { dbgtext("smb2_send_async_interim_response: nreq->current_idx = %u\n", (unsigned int)nreq->current_idx ); @@ -1161,7 +1181,7 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, return NT_STATUS_OK; } - if (req->in.vector_count > i + 3) { + if (req->in.vector_count > i + SMBD_SMB2_NUM_IOV_PER_REQ) { /* * We're trying to go async in a compound * request chain. This is not allowed. @@ -1178,10 +1198,9 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, print_req_vectors(req); } - if (req->out.vector_count > 4) { - struct iovec *outvec = NULL; - - /* This is a compound reply. We + if (req->out.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ)) { + /* + * This is a compound reply. We * must do an interim response * followed by the async response * to match W2K8R2. @@ -1205,43 +1224,28 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, req->compound_related = false; req->sconn->smb2.compound_related_in_progress = false; + req->current_idx = 1; + /* Re-arrange the in.vectors. */ - req->in.vector[1] = req->in.vector[i]; - req->in.vector[2] = req->in.vector[i+1]; - req->in.vector[3] = req->in.vector[i+2]; - req->in.vector_count = 4; + memmove(&req->in.vector[req->current_idx], + &req->in.vector[i], + sizeof(req->in.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ); + req->in.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ; /* Reset the new in size. */ - smb2_setup_nbt_length(req->in.vector, 4); - - /* Now recreate the out.vectors. */ - outvec = talloc_zero_array(req, struct iovec, 4); - if (!outvec) { - return NT_STATUS_NO_MEMORY; - } - - /* 0 is always boilerplate and must - * be of size 4 for the length field. */ - - outvec[0].iov_base = req->out.nbt_hdr; - outvec[0].iov_len = 4; - SIVAL(req->out.nbt_hdr, 0, 0); - - if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) { - return NT_STATUS_NO_MEMORY; - } - - TALLOC_FREE(req->out.vector); + smb2_setup_nbt_length(req->in.vector, req->in.vector_count); - req->out.vector = outvec; - - req->current_idx = 1; - req->out.vector_count = 4; + /* Re-arrange the out.vectors. */ + memmove(&req->out.vector[req->current_idx], + &req->out.vector[i], + sizeof(req->out.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ); + req->out.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ; - outhdr = (uint8_t *)req->out.vector[1].iov_base; + outhdr = SMBD_SMB2_OUT_HDR_PTR(req); flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED); SIVAL(outhdr, SMB2_HDR_FLAGS, flags); } + data_blob_clear_free(&req->last_key); defer_endtime = timeval_current_ofs_usec(defer_time); req->async_te = tevent_add_timer(req->sconn->ev_ctx, @@ -1749,7 +1753,8 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) req->do_signing = true; status = smb2_signing_check_pdu(signing_key, conn->protocol, - SMBD_SMB2_IN_HDR_IOV(req), 3); + SMBD_SMB2_IN_HDR_IOV(req), + SMBD_SMB2_NUM_IOV_PER_REQ); if (!NT_STATUS_IS_OK(status)) { return smbd_smb2_request_error(req, status); } @@ -1968,13 +1973,23 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req) static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) { + struct smbXsrv_connection *conn = req->sconn->conn; struct tevent_req *subreq; - int i = req->current_idx; + struct iovec *outhdr = SMBD_SMB2_OUT_HDR_IOV(req); + struct iovec *outdyn = SMBD_SMB2_OUT_DYN_IOV(req); + struct iovec *lasthdr = NULL; req->subreq = NULL; TALLOC_FREE(req->async_te); - req->current_idx += 3; + if ((req->current_idx > SMBD_SMB2_NUM_IOV_PER_REQ) && + (req->last_key.length > 0)) { + int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ; + + lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx); + } + + req->current_idx += SMBD_SMB2_NUM_IOV_PER_REQ; if (req->current_idx < req->out.vector_count) { /* @@ -1989,6 +2004,25 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) if (!im) { return NT_STATUS_NO_MEMORY; } + + data_blob_clear_free(&req->last_key); + + if (req->do_signing) { + struct smbXsrv_session *x = req->session; + DATA_BLOB signing_key = x->global->channels[0].signing_key; + + /* + * we need to remember the signing key + * and defer the signing until + * we are sure that we do not change + * the header again. + */ + req->last_key = data_blob_dup_talloc(req, signing_key); + if (req->last_key.data == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + tevent_schedule_immediate(im, req->sconn->ev_ctx, smbd_smb2_request_dispatch_immediate, @@ -2006,15 +2040,36 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) is a final reply for an async operation). */ smb2_calculate_credits(req, req); + /* + * As we are sure the header of the last request in the + * compound chain will not change, we can to sign here + * with the last signing key we remembered. + */ + if (lasthdr != NULL) { + NTSTATUS status; + + status = smb2_signing_sign_pdu(req->last_key, + conn->protocol, + lasthdr, + SMBD_SMB2_NUM_IOV_PER_REQ); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + data_blob_clear_free(&req->last_key); + + /* + * now check if we need to sign the current response + */ if (req->do_signing) { NTSTATUS status; struct smbXsrv_session *x = req->session; - struct smbXsrv_connection *conn = x->connection; DATA_BLOB signing_key = x->global->channels[0].signing_key; status = smb2_signing_sign_pdu(signing_key, conn->protocol, - &req->out.vector[i], 3); + outhdr, + SMBD_SMB2_NUM_IOV_PER_REQ); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -2026,9 +2081,8 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) } /* I am a sick, sick man... :-). Sendfile hack ... JRA. */ - if (req->out.vector_count == 4 && - req->out.vector[3].iov_base == NULL && - req->out.vector[3].iov_len != 0) { + if (req->out.vector_count < (2*SMBD_SMB2_NUM_IOV_PER_REQ) && + outdyn->iov_base == NULL && outdyn->iov_len != 0) { -- Samba Shared Repository