uint32_t retry_msecs;
uint16_t lock_count;
struct smbd_lock_element *locks;
+ uint8_t lock_sequence_value;
+ uint8_t *lock_sequence_element;
};
static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
}
}
+static void smbd_smb2_lock_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state);
static void smbd_smb2_lock_try(struct tevent_req *req);
static void smbd_smb2_lock_retry(struct tevent_req *subreq);
static bool smbd_smb2_lock_cancel(struct tevent_req *req);
uint16_t i;
struct smbd_lock_element *locks;
NTSTATUS status;
+ bool check_lock_sequence = false;
+ uint32_t lock_sequence_bucket = 0;
req = tevent_req_create(mem_ctx, &state,
struct smbd_smb2_lock_state);
state->smb2req = smb2req;
smb2req->subreq = req; /* So we can find this when going async. */
+ tevent_req_set_cleanup_fn(req, smbd_smb2_lock_cleanup);
+
state->smb1req = smbd_smb2_fake_smb_request(smb2req);
if (tevent_req_nomem(state->smb1req, req)) {
return tevent_req_post(req, ev);
DEBUG(10,("smbd_smb2_lock_send: %s - %s\n",
fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
+ /*
+ * Windows sets check_lock_sequence = true
+ * only for resilient and persistent handles.
+ *
+ * [MS-SMB2] 3.3.5.14 Receiving an SMB2 LOCK Request
+ *
+ * ...
+ *
+ * If the LockSequence value in the SMB2 LOCK Request (section 2.2.26)
+ * is not zero, and either one of the following conditions is TRUE,
+ * the server SHOULD verify whether the lock/unlock request with that
+ * LockSequence value has been successfully processed before:
+ * * Connection.Dialect is "2.1" and Open.IsResilient is TRUE.
+ * * Connection.Dialect belongs to the SMB 3.x dialect family.<318>
+ *
+ * ...
+ *
+ * <318> Section 3.3.5.14: Windows 8, Windows Server 2012, Windows 8.1,
+ * and Windows Server 2012 R2 do not verify the LockSequence value in
+ * the SMB2 LOCK Request (section 2.2.26) when both Open.IsResilient
+ * and Open.IsPersistent are FALSE.
+ *
+ * Note <318> also applies to all versions (at least) up to
+ * Windows Server 2019.
+ *
+ * Hopefully this will be fixed in future Windows versions and they
+ * will avoid Note <318>.
+ *
+ * We implement what the specification says.
+ */
+ if (smb2req->xconn->protocol >= PROTOCOL_SMB2_22) {
+ check_lock_sequence = true;
+ }
+
+ if (check_lock_sequence) {
+ state->lock_sequence_value = in_lock_sequence & 0xF;
+ lock_sequence_bucket = in_lock_sequence >> 4;
+ }
+ if ((lock_sequence_bucket > 0) &&
+ (lock_sequence_bucket <= sizeof(fsp->op->global->lock_sequence_array)))
+ {
+ uint32_t idx = lock_sequence_bucket - 1;
+ uint8_t *array = fsp->op->global->lock_sequence_array;
+
+ state->lock_sequence_element = &array[idx];
+ }
+
+ if (state->lock_sequence_element != NULL) {
+ if (*state->lock_sequence_element == state->lock_sequence_value)
+ {
+ DBG_INFO("replayed smb2 lock request detected: "
+ "file %s, value %u, bucket %u\n",
+ fsp_str_dbg(fsp),
+ (unsigned)state->lock_sequence_value,
+ (unsigned)lock_sequence_bucket);
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+ *state->lock_sequence_element = 0xFF;
+ }
+
locks = talloc_array(state, struct smbd_lock_element, in_lock_count);
if (locks == NULL) {
tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return req;
}
+static void smbd_smb2_lock_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
+{
+ struct smbd_smb2_lock_state *state = tevent_req_data(
+ req, struct smbd_smb2_lock_state);
+
+ if (req_state != TEVENT_REQ_DONE) {
+ return;
+ }
+
+ if (state->lock_sequence_element != NULL) {
+ *state->lock_sequence_element = state->lock_sequence_value;
+ }
+}
+
static void smbd_smb2_lock_update_retry_msecs(
struct smbd_smb2_lock_state *state)
{