summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/smb2_server.c96
1 files changed, 53 insertions, 43 deletions
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 1738b5ef5e..8f804a6a2e 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -1298,16 +1298,26 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
if (req->in.vector_count > req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ) {
/*
* We're trying to go async in a compound
- * request chain. This is not allowed.
- * Cancel the outstanding request.
+ * request chain.
+ * This is only allowed for opens that
+ * cause an oplock break, otherwise it
+ * is not allowed. See [MS-SMB2].pdf
+ * note <194> on Section 3.3.5.2.7.
*/
- bool ok = tevent_req_cancel(req->subreq);
- if (ok) {
- return NT_STATUS_OK;
+ const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
+
+ if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_CREATE) {
+ /*
+ * Cancel the outstanding request.
+ */
+ bool ok = tevent_req_cancel(req->subreq);
+ if (ok) {
+ return NT_STATUS_OK;
+ }
+ TALLOC_FREE(req->subreq);
+ return smbd_smb2_request_error(req,
+ NT_STATUS_INTERNAL_ERROR);
}
- TALLOC_FREE(req->subreq);
- return smbd_smb2_request_error(req,
- NT_STATUS_INTERNAL_ERROR);
}
if (DEBUGLEVEL >= 10) {
@@ -1316,51 +1326,51 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
print_req_vectors(req);
}
- if (req->out.vector_count >= (2*SMBD_SMB2_NUM_IOV_PER_REQ)) {
- int idx = req->current_idx;
+ if (req->current_idx > 1) {
/*
- * This is a compound reply. We
- * must do an interim response
- * followed by the async response
- * to match W2K8R2.
+ * We're going async in a compound
+ * chain after the first request has
+ * already been processed. Send an
+ * interim response containing the
+ * set of replies already generated.
*/
+ int idx = req->current_idx;
+
status = smb2_send_async_interim_response(req);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
data_blob_clear_free(&req->first_key);
- /*
- * We're splitting off the last SMB2
- * request in a compound set, and the
- * smb2_send_async_interim_response()
- * call above just sent all the replies
- * for the previous SMB2 requests in
- * this compound set. So we're no longer
- * in the "compound_related_in_progress"
- * state, and this is no longer a compound
- * request.
- */
- req->compound_related = false;
- req->sconn->smb2.compound_related_in_progress = false;
-
req->current_idx = 1;
- /* Re-arrange the in.vectors. */
- memmove(&req->in.vector[req->current_idx],
- &req->in.vector[idx],
- sizeof(req->in.vector[0])*SMBD_SMB2_NUM_IOV_PER_REQ);
- req->in.vector_count = req->current_idx + SMBD_SMB2_NUM_IOV_PER_REQ;
-
- /* Re-arrange the out.vectors. */
- memmove(&req->out.vector[req->current_idx],
- &req->out.vector[idx],
- 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 = SMBD_SMB2_OUT_HDR_PTR(req);
- flags = (IVAL(outhdr, SMB2_HDR_FLAGS) & ~SMB2_HDR_FLAG_CHAINED);
- SIVAL(outhdr, SMB2_HDR_FLAGS, flags);
+ /*
+ * Re-arrange the in.vectors to remove what
+ * we just sent.
+ */
+ memmove(&req->in.vector[1],
+ &req->in.vector[idx],
+ sizeof(req->in.vector[0])*(req->in.vector_count - idx));
+ req->in.vector_count = 1 + (req->in.vector_count - idx);
+
+ /* Re-arrange the out.vectors to match. */
+ memmove(&req->out.vector[1],
+ &req->out.vector[idx],
+ sizeof(req->out.vector[0])*(req->out.vector_count - idx));
+ req->out.vector_count = 1 + (req->out.vector_count - idx);
+
+ if (req->in.vector_count == 1 + SMBD_SMB2_NUM_IOV_PER_REQ) {
+ /*
+ * We only have one remaining request as
+ * we've processed everything else.
+ * This is no longer a compound request.
+ */
+ req->compound_related = false;
+ req->sconn->smb2.compound_related_in_progress = false;
+ 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);