[PATCH] Factor out smbd_smb2_create_file from smbd_smb2_create_send

Ralph Böhme slow at samba.org
Fri Jul 21 10:51:46 UTC 2017


Hi metze,

On Tue, Jul 18, 2017 at 11:13:15PM +0200, Stefan Metzmacher wrote:
> >> From the attic.
> >>
> >> Please review&push if ok. Just passed a private autobuild.
> > 
> > Nice cleanup Ralph, thanks !
> > 
> > Reviewed-by: Jeremy Allison <jra at samba.org>
> 
> Please don't push this yet.
> 
> I've discussed with Ralph that we want to split out
> two functions, one before calling SMB_VFS_CREATE_FILE()
> and one after it. Similar to ntlmssp_server_preauth(),
> ntlmssp_server_check_password() and ntlmssp_server_postauth().

attached. Please review&push if ok.

Cheerio!
-slow
-------------- next part --------------
From 0a5e58eff220c8f3736ad04a67b9c630cdad8c91 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 19 Jul 2017 19:04:46 +0200
Subject: [PATCH 01/12] s3/smbd: factor out smbd_smb2_create_finish()

No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 58 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 54 insertions(+), 4 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index c4fe247..ece7978 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -449,6 +449,15 @@ struct smbd_smb2_create_state {
 	struct smb2_create_blobs *out_context_blobs;
 };
 
+static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state,
+				    struct smbd_smb2_request *smb2req,
+				    struct smb_request *smb1req,
+				    files_struct *result,
+				    const bool replay_operation,
+				    const int in_oplock_level,
+				    const int in_create_disposition,
+				    const int info);
+
 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			struct tevent_context *ev,
 			struct smbd_smb2_request *smb2req,
@@ -628,6 +637,17 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			return tevent_req_post(req, ev);
 		}
 		info = FILE_WAS_OPENED;
+
+		smbd_smb2_create_finish(state,
+					smb2req,
+					smb1req,
+					result,
+					replay_operation,
+					in_oplock_level,
+					in_create_disposition,
+					info);
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
 	} else if (CAN_PRINT(smb1req->conn)) {
 		if (dhnc || dh2c) {
 			/* durable handles are not supported on printers */
@@ -649,6 +669,17 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			return tevent_req_post(req, ev);
 		}
 		info = FILE_WAS_CREATED;
+
+		smbd_smb2_create_finish(state,
+					smb2req,
+					smb1req,
+					result,
+					replay_operation,
+					in_oplock_level,
+					in_create_disposition,
+					info);
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
 	} else {
 		char *fname;
 		struct smb2_create_blob *exta = NULL;
@@ -1353,6 +1384,27 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
+	smbd_smb2_create_finish(state,
+				smb2req,
+				smb1req,
+				result,
+				replay_operation,
+				in_oplock_level,
+				in_create_disposition,
+				info);
+	tevent_req_done(req);
+	return tevent_req_post(req, ev);
+}
+
+static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state,
+				    struct smbd_smb2_request *smb2req,
+				    struct smb_request *smb1req,
+				    files_struct *result,
+				    const bool replay_operation,
+				    const int in_oplock_level,
+				    const int in_create_disposition,
+				    const int info)
+{
 	smb2req->compat_chain_fsp = smb1req->chain_fsp;
 
 	if (replay_operation) {
@@ -1397,11 +1449,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	state->out_file_id_persistent = result->op->global->open_persistent_id;
 	state->out_file_id_volatile = result->op->global->open_volatile_id;
 
-	DEBUG(10,("smbd_smb2_create_send: %s - %s\n",
-		  fsp_str_dbg(result), fsp_fnum_dbg(result)));
+	DBG_DEBUG("%s - %s\n", fsp_str_dbg(result), fsp_fnum_dbg(result));
 
-	tevent_req_done(req);
-	return tevent_req_post(req, ev);
+	return;
 }
 
 static NTSTATUS smbd_smb2_create_recv(struct tevent_req *req,
-- 
2.9.4


From b8af75f9e0b38e699d46a4019673c69975dc751c Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Wed, 19 Jul 2017 19:07:55 +0200
Subject: [PATCH 02/12] s3/smbd: leverage early return added in the previous
 commit

Now that the other cases handled in the if/else blocks do early returns,
we can move the logic handling file opens out of the final else block.

No change in behaviour, best viewed with

$ git show -w COMMIT

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 1153 ++++++++++++++++++++++----------------------
 1 file changed, 576 insertions(+), 577 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index ece7978..72ac5ef 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -484,6 +484,32 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smb2_create_blob *dh2q = NULL;
 	struct smb2_create_blob *rqls = NULL;
 	bool replay_operation = false;
+	char *fname;
+	struct smb2_create_blob *exta = NULL;
+	struct ea_list *ea_list = NULL;
+	struct smb2_create_blob *mxac = NULL;
+	NTTIME max_access_time = 0;
+	struct smb2_create_blob *secd = NULL;
+	struct security_descriptor *sec_desc = NULL;
+	struct smb2_create_blob *alsi = NULL;
+	uint64_t allocation_size = 0;
+	struct smb2_create_blob *twrp = NULL;
+	struct smb2_create_blob *qfid = NULL;
+	struct GUID _create_guid = GUID_zero();
+	struct GUID *create_guid = NULL;
+	bool update_open = false;
+	bool durable_requested = false;
+	uint32_t durable_timeout_msec = 0;
+	bool do_durable_reconnect = false;
+	uint64_t persistent_id = 0;
+	struct smb2_lease lease;
+	struct smb2_lease *lease_ptr = NULL;
+	ssize_t lease_len = -1;
+	bool need_replay_cache = false;
+	struct smbXsrv_open *op = NULL;
+#if 0
+	struct smb2_create_blob *svhdx = NULL;
+#endif
 
 	if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
 		requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
@@ -680,273 +706,247 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					info);
 		tevent_req_done(req);
 		return tevent_req_post(req, ev);
-	} else {
-		char *fname;
-		struct smb2_create_blob *exta = NULL;
-		struct ea_list *ea_list = NULL;
-		struct smb2_create_blob *mxac = NULL;
-		NTTIME max_access_time = 0;
-		struct smb2_create_blob *secd = NULL;
-		struct security_descriptor *sec_desc = NULL;
-		struct smb2_create_blob *alsi = NULL;
-		uint64_t allocation_size = 0;
-		struct smb2_create_blob *twrp = NULL;
-		struct smb2_create_blob *qfid = NULL;
-		struct GUID _create_guid = GUID_zero();
-		struct GUID *create_guid = NULL;
-		bool update_open = false;
-		bool durable_requested = false;
-		uint32_t durable_timeout_msec = 0;
-		bool do_durable_reconnect = false;
-		uint64_t persistent_id = 0;
-		struct smb2_lease lease;
-		struct smb2_lease *lease_ptr = NULL;
-		ssize_t lease_len = -1;
-		bool need_replay_cache = false;
-		struct smbXsrv_open *op = NULL;
-#if 0
-		struct smb2_create_blob *svhdx = NULL;
-#endif
+	}
 
-		exta = smb2_create_blob_find(&in_context_blobs,
-					     SMB2_CREATE_TAG_EXTA);
-		mxac = smb2_create_blob_find(&in_context_blobs,
-					     SMB2_CREATE_TAG_MXAC);
-		secd = smb2_create_blob_find(&in_context_blobs,
-					     SMB2_CREATE_TAG_SECD);
-		alsi = smb2_create_blob_find(&in_context_blobs,
-					     SMB2_CREATE_TAG_ALSI);
-		twrp = smb2_create_blob_find(&in_context_blobs,
-					     SMB2_CREATE_TAG_TWRP);
-		qfid = smb2_create_blob_find(&in_context_blobs,
-					     SMB2_CREATE_TAG_QFID);
+	exta = smb2_create_blob_find(&in_context_blobs,
+				     SMB2_CREATE_TAG_EXTA);
+	mxac = smb2_create_blob_find(&in_context_blobs,
+				     SMB2_CREATE_TAG_MXAC);
+	secd = smb2_create_blob_find(&in_context_blobs,
+				     SMB2_CREATE_TAG_SECD);
+	alsi = smb2_create_blob_find(&in_context_blobs,
+				     SMB2_CREATE_TAG_ALSI);
+	twrp = smb2_create_blob_find(&in_context_blobs,
+				     SMB2_CREATE_TAG_TWRP);
+	qfid = smb2_create_blob_find(&in_context_blobs,
+				     SMB2_CREATE_TAG_QFID);
 #if 0
-		if (smb2req->xconn->protocol >= PROTOCOL_SMB3_02) {
-			/*
-			 * This was introduced with SMB3_02
-			 */
-			svhdx = smb2_create_blob_find(&in_context_blobs,
-						      SVHDX_OPEN_DEVICE_CONTEXT);
-		}
+	if (smb2req->xconn->protocol >= PROTOCOL_SMB3_02) {
+		/*
+		 * This was introduced with SMB3_02
+		 */
+		svhdx = smb2_create_blob_find(&in_context_blobs,
+					      SVHDX_OPEN_DEVICE_CONTEXT);
+	}
 #endif
 
-		fname = talloc_strdup(state, in_name);
-		if (tevent_req_nomem(fname, req)) {
+	fname = talloc_strdup(state, in_name);
+	if (tevent_req_nomem(fname, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (exta) {
+		if (!lp_ea_support(SNUM(smb2req->tcon->compat))) {
+			tevent_req_nterror(req,
+					   NT_STATUS_EAS_NOT_SUPPORTED);
 			return tevent_req_post(req, ev);
 		}
 
-		if (exta) {
-			if (!lp_ea_support(SNUM(smb2req->tcon->compat))) {
-				tevent_req_nterror(req,
-					NT_STATUS_EAS_NOT_SUPPORTED);
-				return tevent_req_post(req, ev);
-			}
+		ea_list = read_nttrans_ea_list(mem_ctx,
+					       (const char *)exta->data.data, exta->data.length);
+		if (!ea_list) {
+			DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
+		}
 
-			ea_list = read_nttrans_ea_list(mem_ctx,
-				(const char *)exta->data.data, exta->data.length);
-			if (!ea_list) {
-				DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
+		/*
+		 * NB. When SMB2+ unix extensions are added,
+		 * we need to relax this check in invalid
+		 * names - we used to not do this if
+		 * lp_posix_pathnames() was false.
+		 */
+		if (ea_list_has_invalid_name(ea_list)) {
+			tevent_req_nterror(req, STATUS_INVALID_EA_NAME);
+			return tevent_req_post(req, ev);
+		}
+	}
 
-			/*
-			 * NB. When SMB2+ unix extensions are added,
-			 * we need to relax this check in invalid
-			 * names - we used to not do this if
-			 * lp_posix_pathnames() was false.
-			 */
-			if (ea_list_has_invalid_name(ea_list)) {
-				tevent_req_nterror(req, STATUS_INVALID_EA_NAME);
-				return tevent_req_post(req, ev);
-			}
+	if (mxac) {
+		if (mxac->data.length == 0) {
+			max_access_time = 0;
+		} else if (mxac->data.length == 8) {
+			max_access_time = BVAL(mxac->data.data, 0);
+		} else {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
 		}
+	}
 
-		if (mxac) {
-			if (mxac->data.length == 0) {
-				max_access_time = 0;
-			} else if (mxac->data.length == 8) {
-				max_access_time = BVAL(mxac->data.data, 0);
-			} else {
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
+	if (secd) {
+		enum ndr_err_code ndr_err;
+
+		sec_desc = talloc_zero(state, struct security_descriptor);
+		if (tevent_req_nomem(sec_desc, req)) {
+			return tevent_req_post(req, ev);
 		}
 
-		if (secd) {
-			enum ndr_err_code ndr_err;
+		ndr_err = ndr_pull_struct_blob(&secd->data,
+					       sec_desc, sec_desc,
+					       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
+		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+			DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
+				 ndr_errstr(ndr_err)));
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
+		}
+	}
 
-			sec_desc = talloc_zero(state, struct security_descriptor);
-			if (tevent_req_nomem(sec_desc, req)) {
-				return tevent_req_post(req, ev);
-			}
+	if (dhnq) {
+		if (dhnq->data.length != 16) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
+		}
 
-			ndr_err = ndr_pull_struct_blob(&secd->data,
-				sec_desc, sec_desc,
-				(ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
-			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-				DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
-					 ndr_errstr(ndr_err)));
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
+		if (dh2q) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
 		}
 
-		if (dhnq) {
-			if (dhnq->data.length != 16) {
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
+		/*
+		 * durable handle request is processed below.
+		 */
+		durable_requested = true;
+		/*
+		 * Set the timeout to 16 mins.
+		 *
+		 * TODO: test this against Windows 2012
+		 *       as the default for durable v2 is 1 min.
+		 */
+		durable_timeout_msec = (16*60*1000);
+	}
 
-			if (dh2q) {
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
+	if (dh2q) {
+		const uint8_t *p = dh2q->data.data;
+		uint32_t durable_v2_timeout = 0;
+		DATA_BLOB create_guid_blob;
+		const uint8_t *hdr;
+		uint32_t flags;
 
-			/*
-			 * durable handle request is processed below.
-			 */
-			durable_requested = true;
-			/*
-			 * Set the timeout to 16 mins.
-			 *
-			 * TODO: test this against Windows 2012
-			 *       as the default for durable v2 is 1 min.
-			 */
-			durable_timeout_msec = (16*60*1000);
+		if (dh2q->data.length != 32) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
 		}
 
-		if (dh2q) {
-			const uint8_t *p = dh2q->data.data;
-			uint32_t durable_v2_timeout = 0;
-			DATA_BLOB create_guid_blob;
-			const uint8_t *hdr;
-			uint32_t flags;
-
-			if (dh2q->data.length != 32) {
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
-
-			if (dhnq) {
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
+		if (dhnq) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
+		}
 
-			durable_v2_timeout = IVAL(p, 0);
-			create_guid_blob = data_blob_const(p + 16, 16);
+		durable_v2_timeout = IVAL(p, 0);
+		create_guid_blob = data_blob_const(p + 16, 16);
 
-			status = GUID_from_ndr_blob(&create_guid_blob,
-						    &_create_guid);
-			if (tevent_req_nterror(req, status)) {
-				return tevent_req_post(req, ev);
-			}
-			create_guid = &_create_guid;
-			/*
-			 * we need to store the create_guid later
-			 */
-			update_open = true;
+		status = GUID_from_ndr_blob(&create_guid_blob,
+					    &_create_guid);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
+		create_guid = &_create_guid;
+		/*
+		 * we need to store the create_guid later
+		 */
+		update_open = true;
 
-			/*
-			 * And we need to create a cache for replaying the
-			 * create.
-			 */
-			need_replay_cache = true;
+		/*
+		 * And we need to create a cache for replaying the
+		 * create.
+		 */
+		need_replay_cache = true;
 
+		/*
+		 * durable handle v2 request processed below
+		 */
+		durable_requested = true;
+		durable_timeout_msec = durable_v2_timeout;
+		if (durable_timeout_msec == 0) {
 			/*
-			 * durable handle v2 request processed below
+			 * Set the timeout to 1 min as default.
+			 *
+			 * This matches Windows 2012.
 			 */
-			durable_requested = true;
-			durable_timeout_msec = durable_v2_timeout;
-			if (durable_timeout_msec == 0) {
-				/*
-				 * Set the timeout to 1 min as default.
-				 *
-				 * This matches Windows 2012.
-				 */
-				durable_timeout_msec = (60*1000);
-			}
+			durable_timeout_msec = (60*1000);
+		}
 
+		/*
+		 * Check for replay operation.
+		 * Only consider it when we have dh2q.
+		 * If we do not have a replay operation, verify that
+		 * the create_guid is not cached for replay.
+		 */
+		hdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
+		flags = IVAL(hdr, SMB2_HDR_FLAGS);
+		replay_operation =
+			flags & SMB2_HDR_FLAG_REPLAY_OPERATION;
+
+		status = smb2srv_open_lookup_replay_cache(
+			smb2req->xconn, create_guid,
+			0 /* now */, &op);
+
+		if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+			replay_operation = false;
+		} else if (tevent_req_nterror(req, status)) {
+			DBG_WARNING("smb2srv_open_lookup_replay_cache "
+				    "failed: %s\n", nt_errstr(status));
+			return tevent_req_post(req, ev);
+		} else if (!replay_operation) {
 			/*
-			 * Check for replay operation.
-			 * Only consider it when we have dh2q.
-			 * If we do not have a replay operation, verify that
-			 * the create_guid is not cached for replay.
+			 * If a create without replay operation flag
+			 * is sent but with a create_guid that is
+			 * currently in the replay cache -- fail.
 			 */
-			hdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
-			flags = IVAL(hdr, SMB2_HDR_FLAGS);
-			replay_operation =
-				flags & SMB2_HDR_FLAG_REPLAY_OPERATION;
-
-			status = smb2srv_open_lookup_replay_cache(
-					smb2req->xconn, create_guid,
-					0 /* now */, &op);
-
-			if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
-				replay_operation = false;
-			} else if (tevent_req_nterror(req, status)) {
-				DBG_WARNING("smb2srv_open_lookup_replay_cache "
-					    "failed: %s\n", nt_errstr(status));
-				return tevent_req_post(req, ev);
-			} else if (!replay_operation) {
-				/*
-				 * If a create without replay operation flag
-				 * is sent but with a create_guid that is
-				 * currently in the replay cache -- fail.
-				 */
-				status = NT_STATUS_DUPLICATE_OBJECTID;
-				(void)tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
-			}
+			status = NT_STATUS_DUPLICATE_OBJECTID;
+			(void)tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
 		}
+	}
 
-		if (dhnc) {
-			persistent_id = BVAL(dhnc->data.data, 0);
-
-			do_durable_reconnect = true;
-		}
+	if (dhnc) {
+		persistent_id = BVAL(dhnc->data.data, 0);
 
-		if (dh2c) {
-			const uint8_t *p = dh2c->data.data;
-			DATA_BLOB create_guid_blob;
+		do_durable_reconnect = true;
+	}
 
-			persistent_id = BVAL(p, 0);
-			create_guid_blob = data_blob_const(p + 16, 16);
+	if (dh2c) {
+		const uint8_t *p = dh2c->data.data;
+		DATA_BLOB create_guid_blob;
 
-			status = GUID_from_ndr_blob(&create_guid_blob,
-						    &_create_guid);
-			if (tevent_req_nterror(req, status)) {
-				return tevent_req_post(req, ev);
-			}
-			create_guid = &_create_guid;
+		persistent_id = BVAL(p, 0);
+		create_guid_blob = data_blob_const(p + 16, 16);
 
-			do_durable_reconnect = true;
+		status = GUID_from_ndr_blob(&create_guid_blob,
+					    &_create_guid);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
 		}
+		create_guid = &_create_guid;
 
-		if (alsi) {
-			if (alsi->data.length != 8) {
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
-			allocation_size = BVAL(alsi->data.data, 0);
+		do_durable_reconnect = true;
+	}
+
+	if (alsi) {
+		if (alsi->data.length != 8) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
 		}
+		allocation_size = BVAL(alsi->data.data, 0);
+	}
 
-		if (twrp) {
-			NTTIME nttime;
-			time_t t;
-			struct tm *tm;
+	if (twrp) {
+		NTTIME nttime;
+		time_t t;
+		struct tm *tm;
 
-			if (twrp->data.length != 8) {
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
+		if (twrp->data.length != 8) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
+		}
 
-			nttime = BVAL(twrp->data.data, 0);
-			t = nt_time_to_unix(nttime);
-			tm = gmtime(&t);
+		nttime = BVAL(twrp->data.data, 0);
+		t = nt_time_to_unix(nttime);
+		tm = gmtime(&t);
 
-			TALLOC_FREE(fname);
-			fname = talloc_asprintf(state,
+		TALLOC_FREE(fname);
+		fname = talloc_asprintf(state,
 					"%s\\@GMT-%04u.%02u.%02u-%02u.%02u.%02u",
 					in_name,
 					tm->tm_year + 1900,
@@ -955,432 +955,431 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					tm->tm_hour,
 					tm->tm_min,
 					tm->tm_sec);
-			if (tevent_req_nomem(fname, req)) {
-				return tevent_req_post(req, ev);
-			}
-			/*
-			 * Tell filename_create_ucf_flags() this
-			 * is an @GMT path.
-			 */
-			smb1req->flags2 |= FLAGS2_REPARSE_PATH;
+		if (tevent_req_nomem(fname, req)) {
+			return tevent_req_post(req, ev);
 		}
+		/*
+		 * Tell filename_create_ucf_flags() this
+		 * is an @GMT path.
+		 */
+		smb1req->flags2 |= FLAGS2_REPARSE_PATH;
+	}
 
-		if (qfid) {
-			if (qfid->data.length != 0) {
-				tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
+	if (qfid) {
+		if (qfid->data.length != 0) {
+			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
 		}
+	}
 
-		if (rqls) {
-			lease_len = smb2_lease_pull(
-				rqls->data.data, rqls->data.length, &lease);
-			if (lease_len == -1) {
-				tevent_req_nterror(
-					req, NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
-			}
-			lease_ptr = &lease;
-
-			if (DEBUGLEVEL >= 10) {
-				DEBUG(10, ("Got lease request size %d\n",
-					   (int)lease_len));
-				NDR_PRINT_DEBUG(smb2_lease, lease_ptr);
-			}
-
-			if (!smb2_lease_key_valid(&lease.lease_key)) {
-				lease_ptr = NULL;
-				requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
-			}
-
-			if ((smb2req->xconn->protocol < PROTOCOL_SMB3_00) &&
-			    (lease.lease_version != 1)) {
-				DEBUG(10, ("v2 lease key only for SMB3\n"));
-				lease_ptr = NULL;
-			}
-
-			/*
-			 * Replay with a lease is only allowed if the
-			 * established open carries a lease with the
-			 * same lease key.
-			 */
-			if (replay_operation) {
-				struct smb2_lease *op_ls =
-						&op->compat->lease->lease;
-				int op_oplock = op->compat->oplock_type;
-
-				if (map_samba_oplock_levels_to_smb2(op_oplock)
-				    != SMB2_OPLOCK_LEVEL_LEASE)
-				{
-					status = NT_STATUS_ACCESS_DENIED;
-					(void)tevent_req_nterror(req, status);
-					return tevent_req_post(req, ev);
-				}
-				if (!smb2_lease_key_equal(&lease.lease_key,
-							  &op_ls->lease_key))
-				{
-					status = NT_STATUS_ACCESS_DENIED;
-					(void)tevent_req_nterror(req, status);
-					return tevent_req_post(req, ev);
-				}
-			}
+	if (rqls) {
+		lease_len = smb2_lease_pull(
+			rqls->data.data, rqls->data.length, &lease);
+		if (lease_len == -1) {
+			tevent_req_nterror(
+				req, NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
 		}
+		lease_ptr = &lease;
 
-		/* these are ignored for SMB2 */
-		in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
-		in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
+		if (DEBUGLEVEL >= 10) {
+			DEBUG(10, ("Got lease request size %d\n",
+				   (int)lease_len));
+			NDR_PRINT_DEBUG(smb2_lease, lease_ptr);
+		}
 
-		in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+		if (!smb2_lease_key_valid(&lease.lease_key)) {
+			lease_ptr = NULL;
+			requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+		}
 
-		DEBUG(10, ("smbd_smb2_create_send: open execution phase\n"));
+		if ((smb2req->xconn->protocol < PROTOCOL_SMB3_00) &&
+		    (lease.lease_version != 1)) {
+			DEBUG(10, ("v2 lease key only for SMB3\n"));
+			lease_ptr = NULL;
+		}
 
 		/*
-		 * For the backend file open procedure, there are
-		 * three possible modes: replay operation (in which case
-		 * there is nothing else to do), durable_reconnect or
-		 * new open.
+		 * Replay with a lease is only allowed if the
+		 * established open carries a lease with the
+		 * same lease key.
 		 */
 		if (replay_operation) {
-			result = op->compat;
-			result->op = op;
-			update_open = false;
-			info = op->create_action;
-		} else if (do_durable_reconnect) {
-			DATA_BLOB new_cookie = data_blob_null;
-			NTTIME now = timeval_to_nttime(&smb2req->request_time);
-
-			status = smb2srv_open_recreate(smb2req->xconn,
-						smb1req->conn->session_info,
-						persistent_id, create_guid,
-						now, &op);
-			if (!NT_STATUS_IS_OK(status)) {
-				DEBUG(3, ("smbd_smb2_create_send: "
-					  "smb2srv_open_recreate failed: %s\n",
-					  nt_errstr(status)));
-				tevent_req_nterror(req, status);
+			struct smb2_lease *op_ls =
+				&op->compat->lease->lease;
+			int op_oplock = op->compat->oplock_type;
+
+			if (map_samba_oplock_levels_to_smb2(op_oplock)
+			    != SMB2_OPLOCK_LEVEL_LEASE)
+			{
+				status = NT_STATUS_ACCESS_DENIED;
+				(void)tevent_req_nterror(req, status);
 				return tevent_req_post(req, ev);
 			}
-
-			DEBUG(10, ("smb2_create_send: %s to recreate the "
-				   "smb2srv_open struct for a durable handle.\n",
-				   op->global->durable ? "succeeded" : "failed"));
-
-			if (!op->global->durable) {
-				talloc_free(op);
-				tevent_req_nterror(req,
-					NT_STATUS_OBJECT_NAME_NOT_FOUND);
+			if (!smb2_lease_key_equal(&lease.lease_key,
+						  &op_ls->lease_key))
+			{
+				status = NT_STATUS_ACCESS_DENIED;
+				(void)tevent_req_nterror(req, status);
 				return tevent_req_post(req, ev);
 			}
+		}
+	}
 
-			status = SMB_VFS_DURABLE_RECONNECT(smb1req->conn,
-						smb1req,
-						op, /* smbXsrv_open input */
-						op->global->backend_cookie,
-						op, /* TALLOC_CTX */
-						&result, &new_cookie);
-			if (!NT_STATUS_IS_OK(status)) {
-				NTSTATUS return_status;
+	/* these are ignored for SMB2 */
+	in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
+	in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
 
-				return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
 
-				DEBUG(3, ("smbd_smb2_create_send: "
-					  "durable_reconnect failed: %s => %s\n",
-					  nt_errstr(status),
-					  nt_errstr(return_status)));
+	DEBUG(10, ("smbd_smb2_create_send: open execution phase\n"));
 
-				tevent_req_nterror(req, return_status);
-				return tevent_req_post(req, ev);
-			}
+	/*
+	 * For the backend file open procedure, there are
+	 * three possible modes: replay operation (in which case
+	 * there is nothing else to do), durable_reconnect or
+	 * new open.
+	 */
+	if (replay_operation) {
+		result = op->compat;
+		result->op = op;
+		update_open = false;
+		info = op->create_action;
+	} else if (do_durable_reconnect) {
+		DATA_BLOB new_cookie = data_blob_null;
+		NTTIME now = timeval_to_nttime(&smb2req->request_time);
+
+		status = smb2srv_open_recreate(smb2req->xconn,
+					       smb1req->conn->session_info,
+					       persistent_id, create_guid,
+					       now, &op);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(3, ("smbd_smb2_create_send: "
+				  "smb2srv_open_recreate failed: %s\n",
+				  nt_errstr(status)));
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
 
-			DEBUG(10, ("result->oplock_type=%u, lease_ptr==%p\n",
-				   (unsigned)result->oplock_type, lease_ptr));
+		DEBUG(10, ("smb2_create_send: %s to recreate the "
+			   "smb2srv_open struct for a durable handle.\n",
+			   op->global->durable ? "succeeded" : "failed"));
 
-			status = smbd_smb2_create_durable_lease_check(
-				smb1req, fname, result, lease_ptr);
-			if (!NT_STATUS_IS_OK(status)) {
-				close_file(smb1req, result, SHUTDOWN_CLOSE);
-				tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
-			}
+		if (!op->global->durable) {
+			talloc_free(op);
+			tevent_req_nterror(req,
+					   NT_STATUS_OBJECT_NAME_NOT_FOUND);
+			return tevent_req_post(req, ev);
+		}
 
-			data_blob_free(&op->global->backend_cookie);
-			op->global->backend_cookie = new_cookie;
+		status = SMB_VFS_DURABLE_RECONNECT(smb1req->conn,
+						   smb1req,
+						   op, /* smbXsrv_open input */
+						   op->global->backend_cookie,
+						   op, /* TALLOC_CTX */
+						   &result, &new_cookie);
+		if (!NT_STATUS_IS_OK(status)) {
+			NTSTATUS return_status;
 
-			op->status = NT_STATUS_OK;
-			op->global->disconnect_time = 0;
+			return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
 
-			/* save the timout for later update */
-			durable_timeout_msec = op->global->durable_timeout_msec;
+			DEBUG(3, ("smbd_smb2_create_send: "
+				  "durable_reconnect failed: %s => %s\n",
+				  nt_errstr(status),
+				  nt_errstr(return_status)));
 
-			update_open = true;
+			tevent_req_nterror(req, return_status);
+			return tevent_req_post(req, ev);
+		}
 
-			info = FILE_WAS_OPENED;
-		} else {
-			struct smb_filename *smb_fname = NULL;
-			uint32_t ucf_flags;
-
-			if (requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
-				if (lease_ptr == NULL) {
-					requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
-				}
-			} else {
-				lease_ptr = NULL;
-			}
+		DEBUG(10, ("result->oplock_type=%u, lease_ptr==%p\n",
+			   (unsigned)result->oplock_type, lease_ptr));
 
-			/*
-			 * For a DFS path the function parse_dfs_path()
-			 * will do the path processing.
-			 */
+		status = smbd_smb2_create_durable_lease_check(
+			smb1req, fname, result, lease_ptr);
+		if (!NT_STATUS_IS_OK(status)) {
+			close_file(smb1req, result, SHUTDOWN_CLOSE);
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
 
-			if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) {
-				/* convert '\\' into '/' */
-				status = check_path_syntax(fname);
-				if (!NT_STATUS_IS_OK(status)) {
-					tevent_req_nterror(req, status);
-					return tevent_req_post(req, ev);
-				}
-			}
+		data_blob_free(&op->global->backend_cookie);
+		op->global->backend_cookie = new_cookie;
 
-			ucf_flags = filename_create_ucf_flags(smb1req, in_create_disposition);
-			status = filename_convert(req,
-						  smb1req->conn,
-						  fname,
-						  ucf_flags,
-						  NULL, /* ppath_contains_wcards */
-						  &smb_fname);
-			if (!NT_STATUS_IS_OK(status)) {
-				tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
-			}
+		op->status = NT_STATUS_OK;
+		op->global->disconnect_time = 0;
 
-			/*
-			 * MS-SMB2: 2.2.13 SMB2 CREATE Request
-			 * ImpersonationLevel ... MUST contain one of the
-			 * following values. The server MUST validate this
-			 * field, but otherwise ignore it.
-			 *
-			 * NB. The source4/torture/smb2/durable_open.c test
-			 * shows this check is only done on real opens, not
-			 * on durable handle-reopens.
-			 */
+		/* save the timout for later update */
+		durable_timeout_msec = op->global->durable_timeout_msec;
 
-			if (in_impersonation_level >
-					SMB2_IMPERSONATION_DELEGATE) {
-				tevent_req_nterror(req,
-					NT_STATUS_BAD_IMPERSONATION_LEVEL);
-				return tevent_req_post(req, ev);
-			}
+		update_open = true;
 
-			/*
-			 * We know we're going to do a local open, so now
-			 * we must be protocol strict. JRA.
-			 *
-			 * MS-SMB2: 3.3.5.9 - Receiving an SMB2 CREATE Request
-			 * If the file name length is greater than zero and the
-			 * first character is a path separator character, the
-			 * server MUST fail the request with
-			 * STATUS_INVALID_PARAMETER.
-			 */
-			if (in_name[0] == '\\' || in_name[0] == '/') {
-				tevent_req_nterror(req,
-					NT_STATUS_INVALID_PARAMETER);
-				return tevent_req_post(req, ev);
+		info = FILE_WAS_OPENED;
+	} else {
+		struct smb_filename *smb_fname = NULL;
+		uint32_t ucf_flags;
+
+		if (requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
+			if (lease_ptr == NULL) {
+				requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 			}
+		} else {
+			lease_ptr = NULL;
+		}
 
-			status = SMB_VFS_CREATE_FILE(smb1req->conn,
-						     smb1req,
-						     0, /* root_dir_fid */
-						     smb_fname,
-						     in_desired_access,
-						     in_share_access,
-						     in_create_disposition,
-						     in_create_options,
-						     in_file_attributes,
-						     map_smb2_oplock_levels_to_samba(requested_oplock_level),
-						     lease_ptr,
-						     allocation_size,
-						     0, /* private_flags */
-						     sec_desc,
-						     ea_list,
-						     &result,
-						     &info,
-						     &in_context_blobs,
-						     state->out_context_blobs);
+		/*
+		 * For a DFS path the function parse_dfs_path()
+		 * will do the path processing.
+		 */
+
+		if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) {
+			/* convert '\\' into '/' */
+			status = check_path_syntax(fname);
 			if (!NT_STATUS_IS_OK(status)) {
-				if (open_was_deferred(smb1req->xconn, smb1req->mid)) {
-					SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
-					return req;
-				}
 				tevent_req_nterror(req, status);
 				return tevent_req_post(req, ev);
 			}
-			op = result->op;
+		}
+
+		ucf_flags = filename_create_ucf_flags(smb1req, in_create_disposition);
+		status = filename_convert(req,
+					  smb1req->conn,
+					  fname,
+					  ucf_flags,
+					  NULL, /* ppath_contains_wcards */
+					  &smb_fname);
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
 		}
 
 		/*
-		 * here we have op == result->op
+		 * MS-SMB2: 2.2.13 SMB2 CREATE Request
+		 * ImpersonationLevel ... MUST contain one of the
+		 * following values. The server MUST validate this
+		 * field, but otherwise ignore it.
+		 *
+		 * NB. The source4/torture/smb2/durable_open.c test
+		 * shows this check is only done on real opens, not
+		 * on durable handle-reopens.
 		 */
 
-		DEBUG(10, ("smbd_smb2_create_send: "
-			   "response construction phase\n"));
-
-		if (mxac) {
-			NTTIME last_write_time;
-
-			last_write_time = unix_timespec_to_nt_time(
-						 result->fsp_name->st.st_ex_mtime);
-			if (last_write_time != max_access_time) {
-				uint8_t p[8];
-				uint32_t max_access_granted;
-				DATA_BLOB blob = data_blob_const(p, sizeof(p));
-
-				status = smbd_calculate_access_mask(smb1req->conn,
-							result->fsp_name,
-							false,
-							SEC_FLAG_MAXIMUM_ALLOWED,
-							&max_access_granted);
-
-				SIVAL(p, 0, NT_STATUS_V(status));
-				SIVAL(p, 4, max_access_granted);
-
-				status = smb2_create_blob_add(
-				    state->out_context_blobs,
-				    state->out_context_blobs,
-				    SMB2_CREATE_TAG_MXAC,
-				    blob);
-				if (!NT_STATUS_IS_OK(status)) {
-					tevent_req_nterror(req, status);
-					return tevent_req_post(req, ev);
-				}
-			}
+		if (in_impersonation_level >
+		    SMB2_IMPERSONATION_DELEGATE) {
+			tevent_req_nterror(req,
+					   NT_STATUS_BAD_IMPERSONATION_LEVEL);
+			return tevent_req_post(req, ev);
 		}
 
-		if (!replay_operation && durable_requested &&
-		    (fsp_lease_type(result) & SMB2_LEASE_HANDLE))
-		{
-			status = SMB_VFS_DURABLE_COOKIE(result,
-						op,
-						&op->global->backend_cookie);
-			if (!NT_STATUS_IS_OK(status)) {
-				op->global->backend_cookie = data_blob_null;
-			}
+		/*
+		 * We know we're going to do a local open, so now
+		 * we must be protocol strict. JRA.
+		 *
+		 * MS-SMB2: 3.3.5.9 - Receiving an SMB2 CREATE Request
+		 * If the file name length is greater than zero and the
+		 * first character is a path separator character, the
+		 * server MUST fail the request with
+		 * STATUS_INVALID_PARAMETER.
+		 */
+		if (in_name[0] == '\\' || in_name[0] == '/') {
+			tevent_req_nterror(req,
+					   NT_STATUS_INVALID_PARAMETER);
+			return tevent_req_post(req, ev);
 		}
-		if (!replay_operation && op->global->backend_cookie.length > 0)
-		{
-			update_open = true;
 
-			op->global->durable = true;
-			op->global->durable_timeout_msec = durable_timeout_msec;
+		status = SMB_VFS_CREATE_FILE(smb1req->conn,
+					     smb1req,
+					     0, /* root_dir_fid */
+					     smb_fname,
+					     in_desired_access,
+					     in_share_access,
+					     in_create_disposition,
+					     in_create_options,
+					     in_file_attributes,
+					     map_smb2_oplock_levels_to_samba(requested_oplock_level),
+					     lease_ptr,
+					     allocation_size,
+					     0, /* private_flags */
+					     sec_desc,
+					     ea_list,
+					     &result,
+					     &info,
+					     &in_context_blobs,
+					     state->out_context_blobs);
+		if (!NT_STATUS_IS_OK(status)) {
+			if (open_was_deferred(smb1req->xconn, smb1req->mid)) {
+				SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
+				return req;
+			}
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
 		}
+		op = result->op;
+	}
 
-		if (update_open) {
-			op->global->create_guid = _create_guid;
-			if (need_replay_cache) {
-				op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE;
-			}
+	/*
+	 * here we have op == result->op
+	 */
 
-			status = smbXsrv_open_update(op);
-			DEBUG(10, ("smb2_create_send: smbXsrv_open_update "
-				   "returned %s\n",
-				   nt_errstr(status)));
-			if (!NT_STATUS_IS_OK(status)) {
-				tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
-			}
-		}
+	DEBUG(10, ("smbd_smb2_create_send: "
+		   "response construction phase\n"));
 
-		if (dhnq && op->global->durable) {
-			uint8_t p[8] = { 0, };
+	if (mxac) {
+		NTTIME last_write_time;
+
+		last_write_time = unix_timespec_to_nt_time(
+			result->fsp_name->st.st_ex_mtime);
+		if (last_write_time != max_access_time) {
+			uint8_t p[8];
+			uint32_t max_access_granted;
 			DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
-			status = smb2_create_blob_add(state->out_context_blobs,
-						      state->out_context_blobs,
-						      SMB2_CREATE_TAG_DHNQ,
-						      blob);
+			status = smbd_calculate_access_mask(smb1req->conn,
+							    result->fsp_name,
+							    false,
+							    SEC_FLAG_MAXIMUM_ALLOWED,
+							    &max_access_granted);
+
+			SIVAL(p, 0, NT_STATUS_V(status));
+			SIVAL(p, 4, max_access_granted);
+
+			status = smb2_create_blob_add(
+				state->out_context_blobs,
+				state->out_context_blobs,
+				SMB2_CREATE_TAG_MXAC,
+				blob);
 			if (!NT_STATUS_IS_OK(status)) {
 				tevent_req_nterror(req, status);
 				return tevent_req_post(req, ev);
 			}
 		}
+	}
 
-		if (dh2q && op->global->durable &&
-		    /*
-		     * For replay operations, we return the dh2q blob
-		     * in the case of oplocks not based on the state of
-		     * the open, but on whether it could have been granted
-		     * for the request data. In the case of leases instead,
-		     * the state of the open is used...
-		     */
-		    (!replay_operation ||
-		     in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH ||
-		     in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE))
-		{
-			uint8_t p[8] = { 0, };
-			DATA_BLOB blob = data_blob_const(p, sizeof(p));
-			uint32_t durable_v2_response_flags = 0;
+	if (!replay_operation && durable_requested &&
+	    (fsp_lease_type(result) & SMB2_LEASE_HANDLE))
+	{
+		status = SMB_VFS_DURABLE_COOKIE(result,
+						op,
+						&op->global->backend_cookie);
+		if (!NT_STATUS_IS_OK(status)) {
+			op->global->backend_cookie = data_blob_null;
+		}
+	}
+	if (!replay_operation && op->global->backend_cookie.length > 0)
+	{
+		update_open = true;
 
-			SIVAL(p, 0, op->global->durable_timeout_msec);
-			SIVAL(p, 4, durable_v2_response_flags);
+		op->global->durable = true;
+		op->global->durable_timeout_msec = durable_timeout_msec;
+	}
 
-			status = smb2_create_blob_add(state->out_context_blobs,
-						      state->out_context_blobs,
-						      SMB2_CREATE_TAG_DH2Q,
-						      blob);
-			if (!NT_STATUS_IS_OK(status)) {
-				tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
-			}
+	if (update_open) {
+		op->global->create_guid = _create_guid;
+		if (need_replay_cache) {
+			op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE;
 		}
 
-		if (qfid) {
-			uint8_t p[32];
-			uint64_t file_index = get_FileIndex(result->conn,
-							&result->fsp_name->st);
-			DATA_BLOB blob = data_blob_const(p, sizeof(p));
+		status = smbXsrv_open_update(op);
+		DEBUG(10, ("smb2_create_send: smbXsrv_open_update "
+			   "returned %s\n",
+			   nt_errstr(status)));
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
+	}
 
-			ZERO_STRUCT(p);
+	if (dhnq && op->global->durable) {
+		uint8_t p[8] = { 0, };
+		DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
-			/* From conversations with Microsoft engineers at
-			   the MS plugfest. The first 8 bytes are the "volume index"
-			   == inode, the second 8 bytes are the "volume id",
-			   == dev. This will be updated in the SMB2 doc. */
-			SBVAL(p, 0, file_index);
-			SIVAL(p, 8, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
+		status = smb2_create_blob_add(state->out_context_blobs,
+					      state->out_context_blobs,
+					      SMB2_CREATE_TAG_DHNQ,
+					      blob);
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
+	}
 
-			status = smb2_create_blob_add(state->out_context_blobs,
-						      state->out_context_blobs,
-						      SMB2_CREATE_TAG_QFID,
-						      blob);
-			if (!NT_STATUS_IS_OK(status)) {
-				tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
-			}
+	if (dh2q && op->global->durable &&
+	    /*
+	     * For replay operations, we return the dh2q blob
+	     * in the case of oplocks not based on the state of
+	     * the open, but on whether it could have been granted
+	     * for the request data. In the case of leases instead,
+	     * the state of the open is used...
+	     */
+	    (!replay_operation ||
+	     in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH ||
+	     in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE))
+	{
+		uint8_t p[8] = { 0, };
+		DATA_BLOB blob = data_blob_const(p, sizeof(p));
+		uint32_t durable_v2_response_flags = 0;
+
+		SIVAL(p, 0, op->global->durable_timeout_msec);
+		SIVAL(p, 4, durable_v2_response_flags);
+
+		status = smb2_create_blob_add(state->out_context_blobs,
+					      state->out_context_blobs,
+					      SMB2_CREATE_TAG_DH2Q,
+					      blob);
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
 		}
+	}
 
-		if ((rqls != NULL) && (result->oplock_type == LEASE_OPLOCK)) {
-			uint8_t buf[52];
+	if (qfid) {
+		uint8_t p[32];
+		uint64_t file_index = get_FileIndex(result->conn,
+						    &result->fsp_name->st);
+		DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
-			lease = result->lease->lease;
+		ZERO_STRUCT(p);
 
-			lease_len = sizeof(buf);
-			if (lease.lease_version == 1) {
-				lease_len = 32;
-			}
+		/* From conversations with Microsoft engineers at
+		   the MS plugfest. The first 8 bytes are the "volume index"
+		   == inode, the second 8 bytes are the "volume id",
+		   == dev. This will be updated in the SMB2 doc. */
+		SBVAL(p, 0, file_index);
+		SIVAL(p, 8, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
 
-			if (!smb2_lease_push(&lease, buf, lease_len)) {
-				tevent_req_nterror(
-					req, NT_STATUS_INTERNAL_ERROR);
-				return tevent_req_post(req, ev);
-			}
+		status = smb2_create_blob_add(state->out_context_blobs,
+					      state->out_context_blobs,
+					      SMB2_CREATE_TAG_QFID,
+					      blob);
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
+	}
 
-			status = smb2_create_blob_add(
-				state, state->out_context_blobs,
-				SMB2_CREATE_TAG_RQLS,
-				data_blob_const(buf, lease_len));
-			if (!NT_STATUS_IS_OK(status)) {
-				tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
-			}
+	if ((rqls != NULL) && (result->oplock_type == LEASE_OPLOCK)) {
+		uint8_t buf[52];
+
+		lease = result->lease->lease;
+
+		lease_len = sizeof(buf);
+		if (lease.lease_version == 1) {
+			lease_len = 32;
+		}
+
+		if (!smb2_lease_push(&lease, buf, lease_len)) {
+			tevent_req_nterror(
+				req, NT_STATUS_INTERNAL_ERROR);
+			return tevent_req_post(req, ev);
+		}
+
+		status = smb2_create_blob_add(
+			state, state->out_context_blobs,
+			SMB2_CREATE_TAG_RQLS,
+			data_blob_const(buf, lease_len));
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
 		}
 	}
 
-- 
2.9.4


From bf3c24054440eb7177daad7a58d0fcc626e75161 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 06:03:34 +0200
Subject: [PATCH 03/12] s3/smbd: prepare smbd_smb2_create_send refactoring

Move some code a few lines up to get it out of the way when doing more
refactoring later. No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 72ac5ef..32a4921 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -708,6 +708,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
+	/* these are ignored for SMB2 */
+	in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
+	in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
+
+	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+
 	exta = smb2_create_blob_find(&in_context_blobs,
 				     SMB2_CREATE_TAG_EXTA);
 	mxac = smb2_create_blob_find(&in_context_blobs,
@@ -1026,12 +1032,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	/* these are ignored for SMB2 */
-	in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
-	in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
-
-	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
-
 	DEBUG(10, ("smbd_smb2_create_send: open execution phase\n"));
 
 	/*
-- 
2.9.4


From acd44fb4092d373d9dcd17a9e1621f74622c108b Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 06:49:46 +0200
Subject: [PATCH 04/12] s3/smbd: use struct initializer for state in
 smbd_smb2_create_send

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 32a4921..fb72345 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -522,7 +522,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	if (req == NULL) {
 		return NULL;
 	}
-	state->smb2req = smb2req;
+	*state = (struct smbd_smb2_create_state) {
+		.smb2req = smb2req,
+	};
 
 	smb1req = smbd_smb2_fake_smb_request(smb2req);
 	if (tevent_req_nomem(smb1req, req)) {
-- 
2.9.4


From d7b6ba8883beffd7a430076a2763d6af30e399d5 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 06:13:49 +0200
Subject: [PATCH 05/12] s3/smbd: move some variables into
 smbd_smb2_create_state

Move some variables into smbd_smb2_create_state, this allows removing
all arguments but state from smbd_smb2_create_finish() in the next
commit.

No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 138 ++++++++++++++++++++++++---------------------
 1 file changed, 73 insertions(+), 65 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index fb72345..946f7dd 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -435,6 +435,13 @@ struct smbd_smb2_create_state {
 	struct timeval request_time;
 	struct file_id id;
 	struct deferred_open_record *open_rec;
+	int in_create_disposition;
+	int in_oplock_level;
+	int requested_oplock_level;
+	int info;
+	bool replay_operation;
+	files_struct *result;
+
 	uint8_t out_oplock_level;
 	uint32_t out_create_action;
 	struct timespec out_creation_ts;
@@ -475,15 +482,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smbd_smb2_create_state *state = NULL;
 	NTSTATUS status;
 	struct smb_request *smb1req = NULL;
-	files_struct *result = NULL;
-	int info;
-	int requested_oplock_level;
 	struct smb2_create_blob *dhnc = NULL;
 	struct smb2_create_blob *dh2c = NULL;
 	struct smb2_create_blob *dhnq = NULL;
 	struct smb2_create_blob *dh2q = NULL;
 	struct smb2_create_blob *rqls = NULL;
-	bool replay_operation = false;
 	char *fname;
 	struct smb2_create_blob *exta = NULL;
 	struct ea_list *ea_list = NULL;
@@ -511,12 +514,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smb2_create_blob *svhdx = NULL;
 #endif
 
-	if(lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
-		requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
-	} else {
-		requested_oplock_level = in_oplock_level;
-	}
-
 	req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_create_state);
 	if (req == NULL) {
@@ -524,8 +521,16 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	}
 	*state = (struct smbd_smb2_create_state) {
 		.smb2req = smb2req,
+		.in_create_disposition = in_create_disposition,
+		.in_oplock_level = in_oplock_level,
 	};
 
+	if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
+		state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+	} else {
+		state->requested_oplock_level = in_oplock_level;
+	}
+
 	smb1req = smbd_smb2_fake_smb_request(smb2req);
 	if (tevent_req_nomem(smb1req, req)) {
 		return tevent_req_post(req, ev);
@@ -659,21 +664,21 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			return tevent_req_post(req, ev);
 		}
 
-		status = open_np_file(smb1req, pipe_name, &result);
+		status = open_np_file(smb1req, pipe_name, &state->result);
 		if (!NT_STATUS_IS_OK(status)) {
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
-		info = FILE_WAS_OPENED;
+		state->info = FILE_WAS_OPENED;
 
 		smbd_smb2_create_finish(state,
 					smb2req,
 					smb1req,
-					result,
-					replay_operation,
-					in_oplock_level,
-					in_create_disposition,
-					info);
+					state->result,
+					state->replay_operation,
+					state->in_oplock_level,
+					state->in_create_disposition,
+					state->info);
 		tevent_req_done(req);
 		return tevent_req_post(req, ev);
 	} else if (CAN_PRINT(smb1req->conn)) {
@@ -683,29 +688,29 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			return tevent_req_post(req, ev);
 		}
 
-		status = file_new(smb1req, smb1req->conn, &result);
+		status = file_new(smb1req, smb1req->conn, &state->result);
 		if(!NT_STATUS_IS_OK(status)) {
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
 
-		status = print_spool_open(result, in_name,
+		status = print_spool_open(state->result, in_name,
 					  smb1req->vuid);
 		if (!NT_STATUS_IS_OK(status)) {
-			file_free(smb1req, result);
+			file_free(smb1req, state->result);
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
-		info = FILE_WAS_CREATED;
+		state->info = FILE_WAS_CREATED;
 
 		smbd_smb2_create_finish(state,
 					smb2req,
 					smb1req,
-					result,
-					replay_operation,
-					in_oplock_level,
-					in_create_disposition,
-					info);
+					state->result,
+					state->replay_operation,
+					state->in_oplock_level,
+					state->in_create_disposition,
+					state->info);
 		tevent_req_done(req);
 		return tevent_req_post(req, ev);
 	}
@@ -883,7 +888,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		 */
 		hdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
 		flags = IVAL(hdr, SMB2_HDR_FLAGS);
-		replay_operation =
+		state->replay_operation =
 			flags & SMB2_HDR_FLAG_REPLAY_OPERATION;
 
 		status = smb2srv_open_lookup_replay_cache(
@@ -891,12 +896,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			0 /* now */, &op);
 
 		if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
-			replay_operation = false;
+			state->replay_operation = false;
 		} else if (tevent_req_nterror(req, status)) {
 			DBG_WARNING("smb2srv_open_lookup_replay_cache "
 				    "failed: %s\n", nt_errstr(status));
 			return tevent_req_post(req, ev);
-		} else if (!replay_operation) {
+		} else if (!state->replay_operation) {
 			/*
 			 * If a create without replay operation flag
 			 * is sent but with a create_guid that is
@@ -998,7 +1003,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		if (!smb2_lease_key_valid(&lease.lease_key)) {
 			lease_ptr = NULL;
-			requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+			state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 		}
 
 		if ((smb2req->xconn->protocol < PROTOCOL_SMB3_00) &&
@@ -1012,7 +1017,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		 * established open carries a lease with the
 		 * same lease key.
 		 */
-		if (replay_operation) {
+		if (state->replay_operation) {
 			struct smb2_lease *op_ls =
 				&op->compat->lease->lease;
 			int op_oplock = op->compat->oplock_type;
@@ -1042,11 +1047,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	 * there is nothing else to do), durable_reconnect or
 	 * new open.
 	 */
-	if (replay_operation) {
-		result = op->compat;
-		result->op = op;
+	if (state->replay_operation) {
+		state->result = op->compat;
+		state->result->op = op;
 		update_open = false;
-		info = op->create_action;
+		state->info = op->create_action;
 	} else if (do_durable_reconnect) {
 		DATA_BLOB new_cookie = data_blob_null;
 		NTTIME now = timeval_to_nttime(&smb2req->request_time);
@@ -1079,7 +1084,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 						   op, /* smbXsrv_open input */
 						   op->global->backend_cookie,
 						   op, /* TALLOC_CTX */
-						   &result, &new_cookie);
+						   &state->result,
+						   &new_cookie);
 		if (!NT_STATUS_IS_OK(status)) {
 			NTSTATUS return_status;
 
@@ -1095,12 +1101,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 
 		DEBUG(10, ("result->oplock_type=%u, lease_ptr==%p\n",
-			   (unsigned)result->oplock_type, lease_ptr));
+			   (unsigned)state->result->oplock_type, lease_ptr));
 
 		status = smbd_smb2_create_durable_lease_check(
-			smb1req, fname, result, lease_ptr);
+			smb1req, fname, state->result, lease_ptr);
 		if (!NT_STATUS_IS_OK(status)) {
-			close_file(smb1req, result, SHUTDOWN_CLOSE);
+			close_file(smb1req, state->result, SHUTDOWN_CLOSE);
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
@@ -1116,14 +1122,14 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		update_open = true;
 
-		info = FILE_WAS_OPENED;
+		state->info = FILE_WAS_OPENED;
 	} else {
 		struct smb_filename *smb_fname = NULL;
 		uint32_t ucf_flags;
 
-		if (requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
+		if (state->requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
 			if (lease_ptr == NULL) {
-				requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+				state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 			}
 		} else {
 			lease_ptr = NULL;
@@ -1143,7 +1149,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			}
 		}
 
-		ucf_flags = filename_create_ucf_flags(smb1req, in_create_disposition);
+		ucf_flags = filename_create_ucf_flags(
+			smb1req, state->in_create_disposition);
 		status = filename_convert(req,
 					  smb1req->conn,
 					  fname,
@@ -1195,17 +1202,18 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					     smb_fname,
 					     in_desired_access,
 					     in_share_access,
-					     in_create_disposition,
+					     state->in_create_disposition,
 					     in_create_options,
 					     in_file_attributes,
-					     map_smb2_oplock_levels_to_samba(requested_oplock_level),
+					     map_smb2_oplock_levels_to_samba(
+						     state->requested_oplock_level),
 					     lease_ptr,
 					     allocation_size,
 					     0, /* private_flags */
 					     sec_desc,
 					     ea_list,
-					     &result,
-					     &info,
+					     &state->result,
+					     &state->info,
 					     &in_context_blobs,
 					     state->out_context_blobs);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1216,7 +1224,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
-		op = result->op;
+		op = state->result->op;
 	}
 
 	/*
@@ -1230,14 +1238,14 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		NTTIME last_write_time;
 
 		last_write_time = unix_timespec_to_nt_time(
-			result->fsp_name->st.st_ex_mtime);
+			state->result->fsp_name->st.st_ex_mtime);
 		if (last_write_time != max_access_time) {
 			uint8_t p[8];
 			uint32_t max_access_granted;
 			DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
 			status = smbd_calculate_access_mask(smb1req->conn,
-							    result->fsp_name,
+							    state->result->fsp_name,
 							    false,
 							    SEC_FLAG_MAXIMUM_ALLOWED,
 							    &max_access_granted);
@@ -1257,17 +1265,17 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (!replay_operation && durable_requested &&
-	    (fsp_lease_type(result) & SMB2_LEASE_HANDLE))
+	if (!state->replay_operation && durable_requested &&
+	    (fsp_lease_type(state->result) & SMB2_LEASE_HANDLE))
 	{
-		status = SMB_VFS_DURABLE_COOKIE(result,
+		status = SMB_VFS_DURABLE_COOKIE(state->result,
 						op,
 						&op->global->backend_cookie);
 		if (!NT_STATUS_IS_OK(status)) {
 			op->global->backend_cookie = data_blob_null;
 		}
 	}
-	if (!replay_operation && op->global->backend_cookie.length > 0)
+	if (!state->replay_operation && op->global->backend_cookie.length > 0)
 	{
 		update_open = true;
 
@@ -1313,7 +1321,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	     * for the request data. In the case of leases instead,
 	     * the state of the open is used...
 	     */
-	    (!replay_operation ||
+	    (!state->replay_operation ||
 	     in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH ||
 	     in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE))
 	{
@@ -1336,8 +1344,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 	if (qfid) {
 		uint8_t p[32];
-		uint64_t file_index = get_FileIndex(result->conn,
-						    &result->fsp_name->st);
+		uint64_t file_index = get_FileIndex(state->result->conn,
+						    &state->result->fsp_name->st);
 		DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
 		ZERO_STRUCT(p);
@@ -1347,7 +1355,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		   == inode, the second 8 bytes are the "volume id",
 		   == dev. This will be updated in the SMB2 doc. */
 		SBVAL(p, 0, file_index);
-		SIVAL(p, 8, result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
+		SIVAL(p, 8, state->result->fsp_name->st.st_ex_dev);/* FileIndexHigh */
 
 		status = smb2_create_blob_add(state->out_context_blobs,
 					      state->out_context_blobs,
@@ -1359,10 +1367,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if ((rqls != NULL) && (result->oplock_type == LEASE_OPLOCK)) {
+	if ((rqls != NULL) && (state->result->oplock_type == LEASE_OPLOCK)) {
 		uint8_t buf[52];
 
-		lease = result->lease->lease;
+		lease = state->result->lease->lease;
 
 		lease_len = sizeof(buf);
 		if (lease.lease_version == 1) {
@@ -1388,11 +1396,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	smbd_smb2_create_finish(state,
 				smb2req,
 				smb1req,
-				result,
-				replay_operation,
-				in_oplock_level,
-				in_create_disposition,
-				info);
+				state->result,
+				state->replay_operation,
+				state->in_oplock_level,
+				state->in_create_disposition,
+				state->info);
 	tevent_req_done(req);
 	return tevent_req_post(req, ev);
 }
-- 
2.9.4


From 8a2baf68578689d00d341bf406b53a445cf63b65 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 11:29:46 +0200
Subject: [PATCH 06/12] s3/smbd: remove unneeded args from
 smbd_smb2_create_finish

Since a previous commit those variables are now stored in state.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 64 +++++++++++++---------------------------------
 1 file changed, 18 insertions(+), 46 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 946f7dd..c5a7347 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -456,14 +456,7 @@ struct smbd_smb2_create_state {
 	struct smb2_create_blobs *out_context_blobs;
 };
 
-static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state,
-				    struct smbd_smb2_request *smb2req,
-				    struct smb_request *smb1req,
-				    files_struct *result,
-				    const bool replay_operation,
-				    const int in_oplock_level,
-				    const int in_create_disposition,
-				    const int info);
+static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state);
 
 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			struct tevent_context *ev,
@@ -671,14 +664,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 		state->info = FILE_WAS_OPENED;
 
-		smbd_smb2_create_finish(state,
-					smb2req,
-					smb1req,
-					state->result,
-					state->replay_operation,
-					state->in_oplock_level,
-					state->in_create_disposition,
-					state->info);
+		smbd_smb2_create_finish(state);
+
 		tevent_req_done(req);
 		return tevent_req_post(req, ev);
 	} else if (CAN_PRINT(smb1req->conn)) {
@@ -703,14 +690,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 		state->info = FILE_WAS_CREATED;
 
-		smbd_smb2_create_finish(state,
-					smb2req,
-					smb1req,
-					state->result,
-					state->replay_operation,
-					state->in_oplock_level,
-					state->in_create_disposition,
-					state->info);
+		smbd_smb2_create_finish(state);
+
 		tevent_req_done(req);
 		return tevent_req_post(req, ev);
 	}
@@ -1393,42 +1374,33 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	smbd_smb2_create_finish(state,
-				smb2req,
-				smb1req,
-				state->result,
-				state->replay_operation,
-				state->in_oplock_level,
-				state->in_create_disposition,
-				state->info);
+	smbd_smb2_create_finish(state);
+
 	tevent_req_done(req);
 	return tevent_req_post(req, ev);
 }
 
-static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state,
-				    struct smbd_smb2_request *smb2req,
-				    struct smb_request *smb1req,
-				    files_struct *result,
-				    const bool replay_operation,
-				    const int in_oplock_level,
-				    const int in_create_disposition,
-				    const int info)
+static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state)
 {
+	struct smbd_smb2_request *smb2req = state->smb2req;
+	struct smb_request *smb1req = state->smb1req;
+	files_struct *result = state->result;
+
 	smb2req->compat_chain_fsp = smb1req->chain_fsp;
 
-	if (replay_operation) {
-		state->out_oplock_level = in_oplock_level;
+	if (state->replay_operation) {
+		state->out_oplock_level = state->in_oplock_level;
 	} else if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
-		state->out_oplock_level	= in_oplock_level;
+		state->out_oplock_level	= state->in_oplock_level;
 	} else {
 		state->out_oplock_level	= map_samba_oplock_levels_to_smb2(result->oplock_type);
 	}
 
-	if ((in_create_disposition == FILE_SUPERSEDE)
-	    && (info == FILE_WAS_OVERWRITTEN)) {
+	if ((state->in_create_disposition == FILE_SUPERSEDE)
+	    && (state->info == FILE_WAS_OVERWRITTEN)) {
 		state->out_create_action = FILE_WAS_SUPERSEDED;
 	} else {
-		state->out_create_action = info;
+		state->out_create_action = state->info;
 	}
 	result->op->create_action = state->out_create_action;
 	state->out_file_attributes = dos_mode(result->conn,
-- 
2.9.4


From 1748f729193cbc638fea8887f014e947a1c8b5ff Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 12:15:19 +0200
Subject: [PATCH 07/12] s3/smbd: move create contexts to state in
 smbd_smb2_create_send

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 173 +++++++++++++++++++++++----------------------
 1 file changed, 87 insertions(+), 86 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index c5a7347..176d2ba 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -442,6 +442,19 @@ struct smbd_smb2_create_state {
 	bool replay_operation;
 	files_struct *result;
 
+	struct smb2_create_blob *dhnc;
+	struct smb2_create_blob *dh2c;
+	struct smb2_create_blob *dhnq;
+	struct smb2_create_blob *dh2q;
+	struct smb2_create_blob *rqls;
+	struct smb2_create_blob *exta;
+	struct smb2_create_blob *mxac;
+	struct smb2_create_blob *secd;
+	struct smb2_create_blob *alsi;
+	struct smb2_create_blob *twrp;
+	struct smb2_create_blob *qfid;
+	struct smb2_create_blob *svhdx;
+
 	uint8_t out_oplock_level;
 	uint32_t out_create_action;
 	struct timespec out_creation_ts;
@@ -475,22 +488,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smbd_smb2_create_state *state = NULL;
 	NTSTATUS status;
 	struct smb_request *smb1req = NULL;
-	struct smb2_create_blob *dhnc = NULL;
-	struct smb2_create_blob *dh2c = NULL;
-	struct smb2_create_blob *dhnq = NULL;
-	struct smb2_create_blob *dh2q = NULL;
-	struct smb2_create_blob *rqls = NULL;
 	char *fname;
-	struct smb2_create_blob *exta = NULL;
 	struct ea_list *ea_list = NULL;
-	struct smb2_create_blob *mxac = NULL;
 	NTTIME max_access_time = 0;
-	struct smb2_create_blob *secd = NULL;
 	struct security_descriptor *sec_desc = NULL;
-	struct smb2_create_blob *alsi = NULL;
 	uint64_t allocation_size = 0;
-	struct smb2_create_blob *twrp = NULL;
-	struct smb2_create_blob *qfid = NULL;
 	struct GUID _create_guid = GUID_zero();
 	struct GUID *create_guid = NULL;
 	bool update_open = false;
@@ -503,9 +505,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	ssize_t lease_len = -1;
 	bool need_replay_cache = false;
 	struct smbXsrv_open *op = NULL;
-#if 0
-	struct smb2_create_blob *svhdx = NULL;
-#endif
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_create_state);
@@ -554,31 +553,33 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	dhnq = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_DHNQ);
-	dhnc = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_DHNC);
-	dh2q = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_DH2Q);
-	dh2c = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_DH2C);
+	state->dhnq = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_DHNQ);
+	state->dhnc = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_DHNC);
+	state->dh2q = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_DH2Q);
+	state->dh2c = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_DH2C);
 	if (smb2req->xconn->smb2.server.capabilities & SMB2_CAP_LEASING) {
-		rqls = smb2_create_blob_find(&in_context_blobs,
-					     SMB2_CREATE_TAG_RQLS);
+		state->rqls = smb2_create_blob_find(&in_context_blobs,
+						    SMB2_CREATE_TAG_RQLS);
 	}
 
-	if ((dhnc && dh2c) || (dhnc && dh2q) || (dh2c && dhnq) ||
-	    (dh2q && dh2c))
+	if (((state->dhnc != NULL) && (state->dh2c != NULL)) ||
+	    ((state->dhnc != NULL) && (state->dh2q != NULL)) ||
+	    ((state->dh2c != NULL) && (state->dhnq != NULL)) ||
+	    ((state->dh2q != NULL) && (state->dh2c != NULL)))
 	{
 		/* not both are allowed at the same time */
 		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 		return tevent_req_post(req, ev);
 	}
 
-	if (dhnc) {
+	if (state->dhnc != NULL) {
 		uint32_t num_blobs_allowed;
 
-		if (dhnc->data.length != 16) {
+		if (state->dhnc->data.length != 16) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
@@ -595,13 +596,13 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		 *  above.)
 		 */
 
-		if (dhnq) {
+		if (state->dhnq != NULL) {
 			num_blobs_allowed = 2;
 		} else {
 			num_blobs_allowed = 1;
 		}
 
-		if (rqls != NULL) {
+		if (state->rqls != NULL) {
 			num_blobs_allowed += 1;
 		}
 
@@ -611,10 +612,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (dh2c) {
+	if (state->dh2c!= NULL) {
 		uint32_t num_blobs_allowed;
 
-		if (dh2c->data.length != 36) {
+		if (state->dh2c->data.length != 36) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
@@ -633,7 +634,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		num_blobs_allowed = 1;
 
-		if (rqls != NULL) {
+		if (state->rqls != NULL) {
 			num_blobs_allowed += 1;
 		}
 
@@ -646,7 +647,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	if (IS_IPC(smb1req->conn)) {
 		const char *pipe_name = in_name;
 
-		if (dhnc || dh2c) {
+		if (state->dhnc != NULL || state->dh2c != NULL) {
 			/* durable handles are not supported on IPC$ */
 			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
 			return tevent_req_post(req, ev);
@@ -669,7 +670,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		tevent_req_done(req);
 		return tevent_req_post(req, ev);
 	} else if (CAN_PRINT(smb1req->conn)) {
-		if (dhnc || dh2c) {
+		if (state->dhnc != NULL || state->dh2c != NULL) {
 			/* durable handles are not supported on printers */
 			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
 			return tevent_req_post(req, ev);
@@ -702,34 +703,32 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
 
-	exta = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_EXTA);
-	mxac = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_MXAC);
-	secd = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_SECD);
-	alsi = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_ALSI);
-	twrp = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_TWRP);
-	qfid = smb2_create_blob_find(&in_context_blobs,
-				     SMB2_CREATE_TAG_QFID);
-#if 0
+	state->exta = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_EXTA);
+	state->mxac = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_MXAC);
+	state->secd = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_SECD);
+	state->alsi = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_ALSI);
+	state->twrp = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_TWRP);
+	state->qfid = smb2_create_blob_find(&in_context_blobs,
+					    SMB2_CREATE_TAG_QFID);
 	if (smb2req->xconn->protocol >= PROTOCOL_SMB3_02) {
 		/*
 		 * This was introduced with SMB3_02
 		 */
-		svhdx = smb2_create_blob_find(&in_context_blobs,
-					      SVHDX_OPEN_DEVICE_CONTEXT);
+		state->svhdx = smb2_create_blob_find(&in_context_blobs,
+						     SVHDX_OPEN_DEVICE_CONTEXT);
 	}
-#endif
 
 	fname = talloc_strdup(state, in_name);
 	if (tevent_req_nomem(fname, req)) {
 		return tevent_req_post(req, ev);
 	}
 
-	if (exta) {
+	if (state->exta != NULL) {
 		if (!lp_ea_support(SNUM(smb2req->tcon->compat))) {
 			tevent_req_nterror(req,
 					   NT_STATUS_EAS_NOT_SUPPORTED);
@@ -737,7 +736,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 
 		ea_list = read_nttrans_ea_list(mem_ctx,
-					       (const char *)exta->data.data, exta->data.length);
+					       (const char *)state->exta->data.data,
+					       state->exta->data.length);
 		if (!ea_list) {
 			DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -756,18 +756,18 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (mxac) {
-		if (mxac->data.length == 0) {
+	if (state->mxac != NULL) {
+		if (state->mxac->data.length == 0) {
 			max_access_time = 0;
-		} else if (mxac->data.length == 8) {
-			max_access_time = BVAL(mxac->data.data, 0);
+		} else if (state->mxac->data.length == 8) {
+			max_access_time = BVAL(state->mxac->data.data, 0);
 		} else {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
 	}
 
-	if (secd) {
+	if (state->secd != NULL) {
 		enum ndr_err_code ndr_err;
 
 		sec_desc = talloc_zero(state, struct security_descriptor);
@@ -775,7 +775,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			return tevent_req_post(req, ev);
 		}
 
-		ndr_err = ndr_pull_struct_blob(&secd->data,
+		ndr_err = ndr_pull_struct_blob(&state->secd->data,
 					       sec_desc, sec_desc,
 					       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
@@ -786,13 +786,13 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (dhnq) {
-		if (dhnq->data.length != 16) {
+	if (state->dhnq != NULL) {
+		if (state->dhnq->data.length != 16) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
 
-		if (dh2q) {
+		if (state->dh2q != NULL) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
@@ -810,19 +810,19 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		durable_timeout_msec = (16*60*1000);
 	}
 
-	if (dh2q) {
-		const uint8_t *p = dh2q->data.data;
+	if (state->dh2q != NULL) {
+		const uint8_t *p = state->dh2q->data.data;
 		uint32_t durable_v2_timeout = 0;
 		DATA_BLOB create_guid_blob;
 		const uint8_t *hdr;
 		uint32_t flags;
 
-		if (dh2q->data.length != 32) {
+		if (state->dh2q->data.length != 32) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
 
-		if (dhnq) {
+		if (state->dhnq != NULL) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
@@ -894,14 +894,14 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (dhnc) {
-		persistent_id = BVAL(dhnc->data.data, 0);
+	if (state->dhnc != NULL) {
+		persistent_id = BVAL(state->dhnc->data.data, 0);
 
 		do_durable_reconnect = true;
 	}
 
-	if (dh2c) {
-		const uint8_t *p = dh2c->data.data;
+	if (state->dh2c != NULL) {
+		const uint8_t *p = state->dh2c->data.data;
 		DATA_BLOB create_guid_blob;
 
 		persistent_id = BVAL(p, 0);
@@ -917,25 +917,25 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		do_durable_reconnect = true;
 	}
 
-	if (alsi) {
-		if (alsi->data.length != 8) {
+	if (state->alsi != NULL) {
+		if (state->alsi->data.length != 8) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
-		allocation_size = BVAL(alsi->data.data, 0);
+		allocation_size = BVAL(state->alsi->data.data, 0);
 	}
 
-	if (twrp) {
+	if (state->twrp != NULL) {
 		NTTIME nttime;
 		time_t t;
 		struct tm *tm;
 
-		if (twrp->data.length != 8) {
+		if (state->twrp->data.length != 8) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
 
-		nttime = BVAL(twrp->data.data, 0);
+		nttime = BVAL(state->twrp->data.data, 0);
 		t = nt_time_to_unix(nttime);
 		tm = gmtime(&t);
 
@@ -959,16 +959,17 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		smb1req->flags2 |= FLAGS2_REPARSE_PATH;
 	}
 
-	if (qfid) {
-		if (qfid->data.length != 0) {
+	if (state->qfid != NULL) {
+		if (state->qfid->data.length != 0) {
 			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
 			return tevent_req_post(req, ev);
 		}
 	}
 
-	if (rqls) {
-		lease_len = smb2_lease_pull(
-			rqls->data.data, rqls->data.length, &lease);
+	if (state->rqls != NULL) {
+		lease_len = smb2_lease_pull(state->rqls->data.data,
+					    state->rqls->data.length,
+					    &lease);
 		if (lease_len == -1) {
 			tevent_req_nterror(
 				req, NT_STATUS_INVALID_PARAMETER);
@@ -1215,7 +1216,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	DEBUG(10, ("smbd_smb2_create_send: "
 		   "response construction phase\n"));
 
-	if (mxac) {
+	if (state->mxac != NULL) {
 		NTTIME last_write_time;
 
 		last_write_time = unix_timespec_to_nt_time(
@@ -1280,7 +1281,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (dhnq && op->global->durable) {
+	if (state->dhnq != NULL && op->global->durable) {
 		uint8_t p[8] = { 0, };
 		DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
@@ -1294,7 +1295,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (dh2q && op->global->durable &&
+	if (state->dh2q != NULL && op->global->durable &&
 	    /*
 	     * For replay operations, we return the dh2q blob
 	     * in the case of oplocks not based on the state of
@@ -1323,7 +1324,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (qfid) {
+	if (state->qfid != NULL) {
 		uint8_t p[32];
 		uint64_t file_index = get_FileIndex(state->result->conn,
 						    &state->result->fsp_name->st);
@@ -1348,7 +1349,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if ((rqls != NULL) && (state->result->oplock_type == LEASE_OPLOCK)) {
+	if ((state->rqls != NULL) && (state->result->oplock_type == LEASE_OPLOCK)) {
 		uint8_t buf[52];
 
 		lease = state->result->lease->lease;
-- 
2.9.4


From 1ddaa0117d29bd1e7e75500f3143adb4904f423e Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 12:51:37 +0200
Subject: [PATCH 08/12] s3/smbd: move create ctx extraction and validation to a
 helper func

No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 226 +++++++++++++++++++++++----------------------
 1 file changed, 118 insertions(+), 108 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 176d2ba..89112d9 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -469,6 +469,122 @@ struct smbd_smb2_create_state {
 	struct smb2_create_blobs *out_context_blobs;
 };
 
+static NTSTATUS smbd_smb2_create_fetch_create_ctx(
+	struct tevent_req *req,
+	struct smb2_create_blobs *in_context_blobs)
+{
+	struct smbd_smb2_create_state *state = tevent_req_data(
+		req, struct smbd_smb2_create_state);
+
+	state->dhnq = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_DHNQ);
+	state->dhnc = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_DHNC);
+	state->dh2q = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_DH2Q);
+	state->dh2c = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_DH2C);
+	if (state->smb2req->xconn->smb2.server.capabilities & SMB2_CAP_LEASING) {
+		state->rqls = smb2_create_blob_find(in_context_blobs,
+						    SMB2_CREATE_TAG_RQLS);
+	}
+
+	if (((state->dhnc != NULL) && (state->dh2c != NULL)) ||
+	    ((state->dhnc != NULL) && (state->dh2q != NULL)) ||
+	    ((state->dh2c != NULL) && (state->dhnq != NULL)) ||
+	    ((state->dh2q != NULL) && (state->dh2c != NULL)))
+	{
+		/* not both are allowed at the same time */
+		return NT_STATUS_INVALID_PARAMETER;
+	}
+
+	if (state->dhnc != NULL) {
+		uint32_t num_blobs_allowed;
+
+		if (state->dhnc->data.length != 16) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		/*
+		 * According to MS-SMB2: 3.3.5.9.7, "Handling the
+		 * SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context",
+		 * we should ignore an additional dhnq blob, but fail
+		 * the request (with status OBJECT_NAME_NOT_FOUND) if
+		 * any other extra create blob has been provided.
+		 *
+		 * (Note that the cases of an additional dh2q or dh2c blob
+		 *  which require a different error code, have been treated
+		 *  above.)
+		 */
+
+		if (state->dhnq != NULL) {
+			num_blobs_allowed = 2;
+		} else {
+			num_blobs_allowed = 1;
+		}
+
+		if (state->rqls != NULL) {
+			num_blobs_allowed += 1;
+		}
+
+		if (in_context_blobs->num_blobs != num_blobs_allowed) {
+			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+		}
+	}
+
+	if (state->dh2c!= NULL) {
+		uint32_t num_blobs_allowed;
+
+		if (state->dh2c->data.length != 36) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		/*
+		 * According to MS-SMB2: 3.3.5.9.12, "Handling the
+		 * SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context",
+		 * we should fail the request with status
+		 * OBJECT_NAME_NOT_FOUND if any other create blob has been
+		 * provided.
+		 *
+		 * (Note that the cases of an additional dhnq, dhnc or dh2q
+		 *  blob which require a different error code, have been
+		 *  treated above.)
+		 */
+
+		num_blobs_allowed = 1;
+
+		if (state->rqls != NULL) {
+			num_blobs_allowed += 1;
+		}
+
+		if (in_context_blobs->num_blobs != num_blobs_allowed) {
+			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+		}
+	}
+
+	state->exta = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_EXTA);
+	state->mxac = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_MXAC);
+	state->secd = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_SECD);
+	state->alsi = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_ALSI);
+	state->twrp = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_TWRP);
+	state->qfid = smb2_create_blob_find(in_context_blobs,
+					    SMB2_CREATE_TAG_QFID);
+	if (state->smb2req->xconn->protocol >= PROTOCOL_SMB3_02) {
+		/*
+		 * This was introduced with SMB3_02
+		 */
+		state->svhdx = smb2_create_blob_find(
+			in_context_blobs, SVHDX_OPEN_DEVICE_CONTEXT);
+	}
+
+	return NT_STATUS_OK;
+}
+
 static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state);
 
 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
@@ -553,97 +669,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	state->dhnq = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_DHNQ);
-	state->dhnc = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_DHNC);
-	state->dh2q = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_DH2Q);
-	state->dh2c = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_DH2C);
-	if (smb2req->xconn->smb2.server.capabilities & SMB2_CAP_LEASING) {
-		state->rqls = smb2_create_blob_find(&in_context_blobs,
-						    SMB2_CREATE_TAG_RQLS);
-	}
-
-	if (((state->dhnc != NULL) && (state->dh2c != NULL)) ||
-	    ((state->dhnc != NULL) && (state->dh2q != NULL)) ||
-	    ((state->dh2c != NULL) && (state->dhnq != NULL)) ||
-	    ((state->dh2q != NULL) && (state->dh2c != NULL)))
-	{
-		/* not both are allowed at the same time */
-		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+	status = smbd_smb2_create_fetch_create_ctx(req, &in_context_blobs);
+	if (tevent_req_nterror(req, status)) {
 		return tevent_req_post(req, ev);
 	}
 
-	if (state->dhnc != NULL) {
-		uint32_t num_blobs_allowed;
-
-		if (state->dhnc->data.length != 16) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
-		}
-
-		/*
-		 * According to MS-SMB2: 3.3.5.9.7, "Handling the
-		 * SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context",
-		 * we should ignore an additional dhnq blob, but fail
-		 * the request (with status OBJECT_NAME_NOT_FOUND) if
-		 * any other extra create blob has been provided.
-		 *
-		 * (Note that the cases of an additional dh2q or dh2c blob
-		 *  which require a different error code, have been treated
-		 *  above.)
-		 */
-
-		if (state->dhnq != NULL) {
-			num_blobs_allowed = 2;
-		} else {
-			num_blobs_allowed = 1;
-		}
-
-		if (state->rqls != NULL) {
-			num_blobs_allowed += 1;
-		}
-
-		if (in_context_blobs.num_blobs != num_blobs_allowed) {
-			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
-			return tevent_req_post(req, ev);
-		}
-	}
-
-	if (state->dh2c!= NULL) {
-		uint32_t num_blobs_allowed;
-
-		if (state->dh2c->data.length != 36) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
-		}
-
-		/*
-		 * According to MS-SMB2: 3.3.5.9.12, "Handling the
-		 * SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context",
-		 * we should fail the request with status
-		 * OBJECT_NAME_NOT_FOUND if any other create blob has been
-		 * provided.
-		 *
-		 * (Note that the cases of an additional dhnq, dhnc or dh2q
-		 *  blob which require a different error code, have been
-		 *  treated above.)
-		 */
-
-		num_blobs_allowed = 1;
-
-		if (state->rqls != NULL) {
-			num_blobs_allowed += 1;
-		}
-
-		if (in_context_blobs.num_blobs != num_blobs_allowed) {
-			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
-			return tevent_req_post(req, ev);
-		}
-	}
-
 	if (IS_IPC(smb1req->conn)) {
 		const char *pipe_name = in_name;
 
@@ -703,26 +733,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
 
-	state->exta = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_EXTA);
-	state->mxac = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_MXAC);
-	state->secd = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_SECD);
-	state->alsi = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_ALSI);
-	state->twrp = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_TWRP);
-	state->qfid = smb2_create_blob_find(&in_context_blobs,
-					    SMB2_CREATE_TAG_QFID);
-	if (smb2req->xconn->protocol >= PROTOCOL_SMB3_02) {
-		/*
-		 * This was introduced with SMB3_02
-		 */
-		state->svhdx = smb2_create_blob_find(&in_context_blobs,
-						     SVHDX_OPEN_DEVICE_CONTEXT);
-	}
-
 	fname = talloc_strdup(state, in_name);
 	if (tevent_req_nomem(fname, req)) {
 		return tevent_req_post(req, ev);
-- 
2.9.4


From fa6cd2071e9b6958bdb154f95eeb8a75dab856f6 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 12:53:16 +0200
Subject: [PATCH 09/12] s3/smbd: move some setup code in smbd_smb2_create_send
 a few lines up

This is just one of the last steps before splitting out large code parts
into _before() and _after() functions. No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 89112d9..be5f78c 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -664,6 +664,17 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	TALLOC_FREE(smb2req->subreq);
 	smb2req->subreq = req;
 
+	/* these are ignored for SMB2 */
+	in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
+	in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
+
+	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+
+	fname = talloc_strdup(state, in_name);
+	if (tevent_req_nomem(fname, req)) {
+		return tevent_req_post(req, ev);
+	}
+
 	state->out_context_blobs = talloc_zero(state, struct smb2_create_blobs);
 	if (tevent_req_nomem(state->out_context_blobs, req)) {
 		return tevent_req_post(req, ev);
@@ -727,17 +738,6 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		return tevent_req_post(req, ev);
 	}
 
-	/* these are ignored for SMB2 */
-	in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
-	in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
-
-	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
-
-	fname = talloc_strdup(state, in_name);
-	if (tevent_req_nomem(fname, req)) {
-		return tevent_req_post(req, ev);
-	}
-
 	if (state->exta != NULL) {
 		if (!lp_ea_support(SNUM(smb2req->tcon->compat))) {
 			tevent_req_nterror(req,
-- 
2.9.4


From 37188455328fcdf49990be6affaa441f7b660339 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 16:14:31 +0200
Subject: [PATCH 10/12] s3/smbd: split out smbd_smb2_create_before_exec

Split out smbd_smb2_create_before_exec from smbd_smb2_create_send. Also
move all required variables into smbd_smb2_create_state.

No change in behaviour, best viewed with:

$ git show --diff-algorithm=histogram COMMIT

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 607 +++++++++++++++++++++++----------------------
 1 file changed, 305 insertions(+), 302 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index be5f78c..250d4ff 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -440,6 +440,22 @@ struct smbd_smb2_create_state {
 	int requested_oplock_level;
 	int info;
 	bool replay_operation;
+	NTTIME max_access_time;
+	struct ea_list *ea_list;
+	struct security_descriptor *sec_desc;
+	bool durable_requested;
+	uint32_t durable_timeout_msec;
+	struct GUID _create_guid;
+	struct GUID *create_guid;
+	bool update_open;
+	bool need_replay_cache;
+	struct smbXsrv_open *op;
+	uint64_t persistent_id;
+	bool do_durable_reconnect;
+	uint64_t allocation_size;
+	char *fname;
+	struct smb2_lease lease;
+	struct smb2_lease *lease_ptr;
 	files_struct *result;
 
 	struct smb2_create_blob *dhnc;
@@ -585,173 +601,24 @@ static NTSTATUS smbd_smb2_create_fetch_create_ctx(
 	return NT_STATUS_OK;
 }
 
-static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state);
-
-static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
-			struct tevent_context *ev,
-			struct smbd_smb2_request *smb2req,
-			uint8_t in_oplock_level,
-			uint32_t in_impersonation_level,
-			uint32_t in_desired_access,
-			uint32_t in_file_attributes,
-			uint32_t in_share_access,
-			uint32_t in_create_disposition,
-			uint32_t in_create_options,
-			const char *in_name,
-			struct smb2_create_blobs in_context_blobs)
+static NTSTATUS smbd_smb2_create_before_exec(struct smbd_smb2_create_state *state)
 {
-	struct tevent_req *req = NULL;
-	struct smbd_smb2_create_state *state = NULL;
+	struct smb_request *smb1req = state->smb1req;
+	struct smbd_smb2_request *smb2req = state->smb2req;
 	NTSTATUS status;
-	struct smb_request *smb1req = NULL;
-	char *fname;
-	struct ea_list *ea_list = NULL;
-	NTTIME max_access_time = 0;
-	struct security_descriptor *sec_desc = NULL;
-	uint64_t allocation_size = 0;
-	struct GUID _create_guid = GUID_zero();
-	struct GUID *create_guid = NULL;
-	bool update_open = false;
-	bool durable_requested = false;
-	uint32_t durable_timeout_msec = 0;
-	bool do_durable_reconnect = false;
-	uint64_t persistent_id = 0;
-	struct smb2_lease lease;
-	struct smb2_lease *lease_ptr = NULL;
-	ssize_t lease_len = -1;
-	bool need_replay_cache = false;
-	struct smbXsrv_open *op = NULL;
-
-	req = tevent_req_create(mem_ctx, &state,
-				struct smbd_smb2_create_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	*state = (struct smbd_smb2_create_state) {
-		.smb2req = smb2req,
-		.in_create_disposition = in_create_disposition,
-		.in_oplock_level = in_oplock_level,
-	};
-
-	if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
-		state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
-	} else {
-		state->requested_oplock_level = in_oplock_level;
-	}
-
-	smb1req = smbd_smb2_fake_smb_request(smb2req);
-	if (tevent_req_nomem(smb1req, req)) {
-		return tevent_req_post(req, ev);
-	}
-	state->smb1req = smb1req;
-
-	if (smb2req->subreq == NULL) {
-		DEBUG(10,("smbd_smb2_create: name[%s]\n",
-			in_name));
-	} else {
-		struct smbd_smb2_create_state *old_state = tevent_req_data(
-			smb2req->subreq, struct smbd_smb2_create_state);
-
-		DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
-			in_name ));
-
-		state->id = old_state->id;
-		state->request_time = old_state->request_time;
-		state->open_rec = talloc_move(state, &old_state->open_rec);
-		state->open_was_deferred = old_state->open_was_deferred;
-	}
-
-	TALLOC_FREE(smb2req->subreq);
-	smb2req->subreq = req;
-
-	/* these are ignored for SMB2 */
-	in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
-	in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
-
-	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
-
-	fname = talloc_strdup(state, in_name);
-	if (tevent_req_nomem(fname, req)) {
-		return tevent_req_post(req, ev);
-	}
-
-	state->out_context_blobs = talloc_zero(state, struct smb2_create_blobs);
-	if (tevent_req_nomem(state->out_context_blobs, req)) {
-		return tevent_req_post(req, ev);
-	}
-
-	status = smbd_smb2_create_fetch_create_ctx(req, &in_context_blobs);
-	if (tevent_req_nterror(req, status)) {
-		return tevent_req_post(req, ev);
-	}
-
-	if (IS_IPC(smb1req->conn)) {
-		const char *pipe_name = in_name;
-
-		if (state->dhnc != NULL || state->dh2c != NULL) {
-			/* durable handles are not supported on IPC$ */
-			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
-			return tevent_req_post(req, ev);
-		}
-
-		if (!lp_nt_pipe_support()) {
-			tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
-			return tevent_req_post(req, ev);
-		}
-
-		status = open_np_file(smb1req, pipe_name, &state->result);
-		if (!NT_STATUS_IS_OK(status)) {
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
-		}
-		state->info = FILE_WAS_OPENED;
-
-		smbd_smb2_create_finish(state);
-
-		tevent_req_done(req);
-		return tevent_req_post(req, ev);
-	} else if (CAN_PRINT(smb1req->conn)) {
-		if (state->dhnc != NULL || state->dh2c != NULL) {
-			/* durable handles are not supported on printers */
-			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
-			return tevent_req_post(req, ev);
-		}
-
-		status = file_new(smb1req, smb1req->conn, &state->result);
-		if(!NT_STATUS_IS_OK(status)) {
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
-		}
-
-		status = print_spool_open(state->result, in_name,
-					  smb1req->vuid);
-		if (!NT_STATUS_IS_OK(status)) {
-			file_free(smb1req, state->result);
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
-		}
-		state->info = FILE_WAS_CREATED;
-
-		smbd_smb2_create_finish(state);
-
-		tevent_req_done(req);
-		return tevent_req_post(req, ev);
-	}
 
 	if (state->exta != NULL) {
 		if (!lp_ea_support(SNUM(smb2req->tcon->compat))) {
-			tevent_req_nterror(req,
-					   NT_STATUS_EAS_NOT_SUPPORTED);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_EAS_NOT_SUPPORTED;
 		}
 
-		ea_list = read_nttrans_ea_list(mem_ctx,
-					       (const char *)state->exta->data.data,
-					       state->exta->data.length);
-		if (!ea_list) {
-			DEBUG(10,("smbd_smb2_create_send: read_ea_name_list failed.\n"));
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+		state->ea_list = read_nttrans_ea_list(
+			state,
+			(const char *)state->exta->data.data,
+			state->exta->data.length);
+		if (state->ea_list == NULL) {
+			DBG_DEBUG("read_ea_name_list failed.\n");
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 
 		/*
@@ -760,64 +627,60 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		 * names - we used to not do this if
 		 * lp_posix_pathnames() was false.
 		 */
-		if (ea_list_has_invalid_name(ea_list)) {
-			tevent_req_nterror(req, STATUS_INVALID_EA_NAME);
-			return tevent_req_post(req, ev);
+		if (ea_list_has_invalid_name(state->ea_list)) {
+			return STATUS_INVALID_EA_NAME;
 		}
 	}
 
 	if (state->mxac != NULL) {
 		if (state->mxac->data.length == 0) {
-			max_access_time = 0;
+			state->max_access_time = 0;
 		} else if (state->mxac->data.length == 8) {
-			max_access_time = BVAL(state->mxac->data.data, 0);
+			state->max_access_time = BVAL(state->mxac->data.data, 0);
 		} else {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 	}
 
 	if (state->secd != NULL) {
 		enum ndr_err_code ndr_err;
 
-		sec_desc = talloc_zero(state, struct security_descriptor);
-		if (tevent_req_nomem(sec_desc, req)) {
-			return tevent_req_post(req, ev);
+		state->sec_desc = talloc_zero(state, struct security_descriptor);
+		if (state->sec_desc == NULL) {
+			return NT_STATUS_NO_MEMORY;
 		}
 
 		ndr_err = ndr_pull_struct_blob(&state->secd->data,
-					       sec_desc, sec_desc,
+					       state->sec_desc,
+					       state->sec_desc,
 					       (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
 		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
-			DEBUG(2,("ndr_pull_security_descriptor failed: %s\n",
-				 ndr_errstr(ndr_err)));
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			DBG_NOTICE("ndr_pull_security_descriptor failed: %s\n",
+				   ndr_errstr(ndr_err));
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 	}
 
 	if (state->dhnq != NULL) {
 		if (state->dhnq->data.length != 16) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 
 		if (state->dh2q != NULL) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 
 		/*
 		 * durable handle request is processed below.
 		 */
-		durable_requested = true;
+		state->durable_requested = true;
 		/*
 		 * Set the timeout to 16 mins.
 		 *
 		 * TODO: test this against Windows 2012
 		 *       as the default for durable v2 is 1 min.
 		 */
-		durable_timeout_msec = (16*60*1000);
+		state->durable_timeout_msec = (16*60*1000);
 	}
 
 	if (state->dh2q != NULL) {
@@ -828,47 +691,46 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		uint32_t flags;
 
 		if (state->dh2q->data.length != 32) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 
 		if (state->dhnq != NULL) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 
 		durable_v2_timeout = IVAL(p, 0);
 		create_guid_blob = data_blob_const(p + 16, 16);
 
 		status = GUID_from_ndr_blob(&create_guid_blob,
-					    &_create_guid);
-		if (tevent_req_nterror(req, status)) {
-			return tevent_req_post(req, ev);
+					    &state->_create_guid);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
 		}
-		create_guid = &_create_guid;
+		state->create_guid = &state->_create_guid;
+
 		/*
 		 * we need to store the create_guid later
 		 */
-		update_open = true;
+		state->update_open = true;
 
 		/*
 		 * And we need to create a cache for replaying the
 		 * create.
 		 */
-		need_replay_cache = true;
+		state->need_replay_cache = true;
 
 		/*
 		 * durable handle v2 request processed below
 		 */
-		durable_requested = true;
-		durable_timeout_msec = durable_v2_timeout;
-		if (durable_timeout_msec == 0) {
+		state->durable_requested = true;
+		state->durable_timeout_msec = durable_v2_timeout;
+		if (state->durable_timeout_msec == 0) {
 			/*
 			 * Set the timeout to 1 min as default.
 			 *
 			 * This matches Windows 2012.
 			 */
-			durable_timeout_msec = (60*1000);
+			state->durable_timeout_msec = (60*1000);
 		}
 
 		/*
@@ -882,86 +744,83 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		state->replay_operation =
 			flags & SMB2_HDR_FLAG_REPLAY_OPERATION;
 
-		status = smb2srv_open_lookup_replay_cache(
-			smb2req->xconn, create_guid,
-			0 /* now */, &op);
-
+		status = smb2srv_open_lookup_replay_cache(smb2req->xconn,
+							  state->create_guid,
+							  0 /* now */,
+							  &state->op);
 		if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
 			state->replay_operation = false;
-		} else if (tevent_req_nterror(req, status)) {
+		} else if (!NT_STATUS_IS_OK(status)) {
 			DBG_WARNING("smb2srv_open_lookup_replay_cache "
 				    "failed: %s\n", nt_errstr(status));
-			return tevent_req_post(req, ev);
+			return status;
 		} else if (!state->replay_operation) {
 			/*
 			 * If a create without replay operation flag
 			 * is sent but with a create_guid that is
 			 * currently in the replay cache -- fail.
 			 */
-			status = NT_STATUS_DUPLICATE_OBJECTID;
-			(void)tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_DUPLICATE_OBJECTID;
 		}
 	}
 
 	if (state->dhnc != NULL) {
-		persistent_id = BVAL(state->dhnc->data.data, 0);
-
-		do_durable_reconnect = true;
+		state->persistent_id = BVAL(state->dhnc->data.data, 0);
+		state->do_durable_reconnect = true;
 	}
 
 	if (state->dh2c != NULL) {
 		const uint8_t *p = state->dh2c->data.data;
 		DATA_BLOB create_guid_blob;
 
-		persistent_id = BVAL(p, 0);
+		state->persistent_id = BVAL(p, 0);
 		create_guid_blob = data_blob_const(p + 16, 16);
 
 		status = GUID_from_ndr_blob(&create_guid_blob,
-					    &_create_guid);
-		if (tevent_req_nterror(req, status)) {
-			return tevent_req_post(req, ev);
+					    &state->_create_guid);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
 		}
-		create_guid = &_create_guid;
 
-		do_durable_reconnect = true;
+		state->create_guid = &state->_create_guid;
+		state->do_durable_reconnect = true;
 	}
 
 	if (state->alsi != NULL) {
 		if (state->alsi->data.length != 8) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
-		allocation_size = BVAL(state->alsi->data.data, 0);
+		state->allocation_size = BVAL(state->alsi->data.data, 0);
 	}
 
 	if (state->twrp != NULL) {
 		NTTIME nttime;
 		time_t t;
 		struct tm *tm;
+		char *tmpname = state->fname;
 
 		if (state->twrp->data.length != 8) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 
 		nttime = BVAL(state->twrp->data.data, 0);
 		t = nt_time_to_unix(nttime);
 		tm = gmtime(&t);
 
-		TALLOC_FREE(fname);
-		fname = talloc_asprintf(state,
-					"%s\\@GMT-%04u.%02u.%02u-%02u.%02u.%02u",
-					in_name,
-					tm->tm_year + 1900,
-					tm->tm_mon + 1,
-					tm->tm_mday,
-					tm->tm_hour,
-					tm->tm_min,
-					tm->tm_sec);
-		if (tevent_req_nomem(fname, req)) {
-			return tevent_req_post(req, ev);
+		state->fname = talloc_asprintf(
+			state,
+			"%s\\@GMT-%04u.%02u.%02u-%02u.%02u.%02u",
+			state->fname,
+			tm->tm_year + 1900,
+			tm->tm_mon + 1,
+			tm->tm_mday,
+			tm->tm_hour,
+			tm->tm_min,
+			tm->tm_sec);
+		if (state->fname == NULL) {
+			return NT_STATUS_NO_MEMORY;
 		}
+		TALLOC_FREE(tmpname);
 		/*
 		 * Tell filename_create_ucf_flags() this
 		 * is an @GMT path.
@@ -971,37 +830,36 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 	if (state->qfid != NULL) {
 		if (state->qfid->data.length != 0) {
-			tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
 	}
 
 	if (state->rqls != NULL) {
+		ssize_t lease_len = -1;
+
 		lease_len = smb2_lease_pull(state->rqls->data.data,
 					    state->rqls->data.length,
-					    &lease);
+					    &state->lease);
 		if (lease_len == -1) {
-			tevent_req_nterror(
-				req, NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INVALID_PARAMETER;
 		}
-		lease_ptr = &lease;
+		state->lease_ptr = &state->lease;
 
 		if (DEBUGLEVEL >= 10) {
-			DEBUG(10, ("Got lease request size %d\n",
-				   (int)lease_len));
-			NDR_PRINT_DEBUG(smb2_lease, lease_ptr);
+			DBG_DEBUG("Got lease request size %d\n", (int)lease_len);
+			NDR_PRINT_DEBUG(smb2_lease, state->lease_ptr);
 		}
 
-		if (!smb2_lease_key_valid(&lease.lease_key)) {
-			lease_ptr = NULL;
+		if (!smb2_lease_key_valid(&state->lease.lease_key)) {
+			state->lease_ptr = NULL;
 			state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 		}
 
 		if ((smb2req->xconn->protocol < PROTOCOL_SMB3_00) &&
-		    (lease.lease_version != 1)) {
-			DEBUG(10, ("v2 lease key only for SMB3\n"));
-			lease_ptr = NULL;
+		    (state->lease.lease_version != 1))
+		{
+			DBG_DEBUG("v2 lease key only for SMB3\n");
+			state->lease_ptr = NULL;
 		}
 
 		/*
@@ -1011,26 +869,166 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		 */
 		if (state->replay_operation) {
 			struct smb2_lease *op_ls =
-				&op->compat->lease->lease;
-			int op_oplock = op->compat->oplock_type;
+				&state->op->compat->lease->lease;
+			int op_oplock = state->op->compat->oplock_type;
 
 			if (map_samba_oplock_levels_to_smb2(op_oplock)
 			    != SMB2_OPLOCK_LEVEL_LEASE)
 			{
-				status = NT_STATUS_ACCESS_DENIED;
-				(void)tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
+				return NT_STATUS_ACCESS_DENIED;
 			}
-			if (!smb2_lease_key_equal(&lease.lease_key,
+			if (!smb2_lease_key_equal(&state->lease.lease_key,
 						  &op_ls->lease_key))
 			{
-				status = NT_STATUS_ACCESS_DENIED;
-				(void)tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
+				return NT_STATUS_ACCESS_DENIED;
 			}
 		}
 	}
 
+	return NT_STATUS_OK;
+}
+
+static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state);
+
+static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
+			struct tevent_context *ev,
+			struct smbd_smb2_request *smb2req,
+			uint8_t in_oplock_level,
+			uint32_t in_impersonation_level,
+			uint32_t in_desired_access,
+			uint32_t in_file_attributes,
+			uint32_t in_share_access,
+			uint32_t in_create_disposition,
+			uint32_t in_create_options,
+			const char *in_name,
+			struct smb2_create_blobs in_context_blobs)
+{
+	struct tevent_req *req = NULL;
+	struct smbd_smb2_create_state *state = NULL;
+	NTSTATUS status;
+	struct smb_request *smb1req = NULL;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct smbd_smb2_create_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	*state = (struct smbd_smb2_create_state) {
+		.smb2req = smb2req,
+		.in_create_disposition = in_create_disposition,
+		.in_oplock_level = in_oplock_level,
+	};
+
+	if (lp_fake_oplocks(SNUM(smb2req->tcon->compat))) {
+		state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+	} else {
+		state->requested_oplock_level = in_oplock_level;
+	}
+
+	smb1req = smbd_smb2_fake_smb_request(smb2req);
+	if (tevent_req_nomem(smb1req, req)) {
+		return tevent_req_post(req, ev);
+	}
+	state->smb1req = smb1req;
+
+	if (smb2req->subreq == NULL) {
+		DEBUG(10,("smbd_smb2_create: name[%s]\n",
+			in_name));
+	} else {
+		struct smbd_smb2_create_state *old_state = tevent_req_data(
+			smb2req->subreq, struct smbd_smb2_create_state);
+
+		DEBUG(10,("smbd_smb2_create_send: reentrant for file %s\n",
+			in_name ));
+
+		state->id = old_state->id;
+		state->request_time = old_state->request_time;
+		state->open_rec = talloc_move(state, &old_state->open_rec);
+		state->open_was_deferred = old_state->open_was_deferred;
+	}
+
+	TALLOC_FREE(smb2req->subreq);
+	smb2req->subreq = req;
+
+	/* these are ignored for SMB2 */
+	in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
+	in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
+
+	in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
+
+	state->fname = talloc_strdup(state, in_name);
+	if (tevent_req_nomem(state->fname, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	state->out_context_blobs = talloc_zero(state, struct smb2_create_blobs);
+	if (tevent_req_nomem(state->out_context_blobs, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	status = smbd_smb2_create_fetch_create_ctx(req, &in_context_blobs);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	if (IS_IPC(smb1req->conn)) {
+		const char *pipe_name = in_name;
+
+		if (state->dhnc != NULL || state->dh2c != NULL) {
+			/* durable handles are not supported on IPC$ */
+			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+			return tevent_req_post(req, ev);
+		}
+
+		if (!lp_nt_pipe_support()) {
+			tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+			return tevent_req_post(req, ev);
+		}
+
+		status = open_np_file(smb1req, pipe_name, &state->result);
+		if (!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
+		state->info = FILE_WAS_OPENED;
+
+		smbd_smb2_create_finish(state);
+
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	} else if (CAN_PRINT(smb1req->conn)) {
+		if (state->dhnc != NULL || state->dh2c != NULL) {
+			/* durable handles are not supported on printers */
+			tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+			return tevent_req_post(req, ev);
+		}
+
+		status = file_new(smb1req, smb1req->conn, &state->result);
+		if(!NT_STATUS_IS_OK(status)) {
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
+
+		status = print_spool_open(state->result, in_name,
+					  smb1req->vuid);
+		if (!NT_STATUS_IS_OK(status)) {
+			file_free(smb1req, state->result);
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
+		}
+		state->info = FILE_WAS_CREATED;
+
+		smbd_smb2_create_finish(state);
+
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	status = smbd_smb2_create_before_exec(state);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
 	DEBUG(10, ("smbd_smb2_create_send: open execution phase\n"));
 
 	/*
@@ -1040,18 +1038,20 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	 * new open.
 	 */
 	if (state->replay_operation) {
-		state->result = op->compat;
-		state->result->op = op;
-		update_open = false;
-		state->info = op->create_action;
-	} else if (do_durable_reconnect) {
+		state->result = state->op->compat;
+		state->result->op = state->op;
+		state->update_open = false;
+		state->info = state->op->create_action;
+	} else if (state->do_durable_reconnect) {
 		DATA_BLOB new_cookie = data_blob_null;
 		NTTIME now = timeval_to_nttime(&smb2req->request_time);
 
 		status = smb2srv_open_recreate(smb2req->xconn,
 					       smb1req->conn->session_info,
-					       persistent_id, create_guid,
-					       now, &op);
+					       state->persistent_id,
+					       state->create_guid,
+					       now,
+					       &state->op);
 		if (!NT_STATUS_IS_OK(status)) {
 			DEBUG(3, ("smbd_smb2_create_send: "
 				  "smb2srv_open_recreate failed: %s\n",
@@ -1062,10 +1062,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		DEBUG(10, ("smb2_create_send: %s to recreate the "
 			   "smb2srv_open struct for a durable handle.\n",
-			   op->global->durable ? "succeeded" : "failed"));
+			   state->op->global->durable ? "succeeded" : "failed"));
 
-		if (!op->global->durable) {
-			talloc_free(op);
+		if (!state->op->global->durable) {
+			talloc_free(state->op);
 			tevent_req_nterror(req,
 					   NT_STATUS_OBJECT_NAME_NOT_FOUND);
 			return tevent_req_post(req, ev);
@@ -1073,9 +1073,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		status = SMB_VFS_DURABLE_RECONNECT(smb1req->conn,
 						   smb1req,
-						   op, /* smbXsrv_open input */
-						   op->global->backend_cookie,
-						   op, /* TALLOC_CTX */
+						   state->op, /* smbXsrv_open input */
+						   state->op->global->backend_cookie,
+						   state->op, /* TALLOC_CTX */
 						   &state->result,
 						   &new_cookie);
 		if (!NT_STATUS_IS_OK(status)) {
@@ -1093,26 +1093,26 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 
 		DEBUG(10, ("result->oplock_type=%u, lease_ptr==%p\n",
-			   (unsigned)state->result->oplock_type, lease_ptr));
+			   (unsigned)state->result->oplock_type, state->lease_ptr));
 
 		status = smbd_smb2_create_durable_lease_check(
-			smb1req, fname, state->result, lease_ptr);
+			smb1req, state->fname, state->result, state->lease_ptr);
 		if (!NT_STATUS_IS_OK(status)) {
 			close_file(smb1req, state->result, SHUTDOWN_CLOSE);
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
 
-		data_blob_free(&op->global->backend_cookie);
-		op->global->backend_cookie = new_cookie;
+		data_blob_free(&state->op->global->backend_cookie);
+		state->op->global->backend_cookie = new_cookie;
 
-		op->status = NT_STATUS_OK;
-		op->global->disconnect_time = 0;
+		state->op->status = NT_STATUS_OK;
+		state->op->global->disconnect_time = 0;
 
 		/* save the timout for later update */
-		durable_timeout_msec = op->global->durable_timeout_msec;
+		state->durable_timeout_msec = state->op->global->durable_timeout_msec;
 
-		update_open = true;
+		state->update_open = true;
 
 		state->info = FILE_WAS_OPENED;
 	} else {
@@ -1120,11 +1120,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		uint32_t ucf_flags;
 
 		if (state->requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
-			if (lease_ptr == NULL) {
+			if (state->lease_ptr == NULL) {
 				state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 			}
 		} else {
-			lease_ptr = NULL;
+			state->lease_ptr = NULL;
 		}
 
 		/*
@@ -1134,7 +1134,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) {
 			/* convert '\\' into '/' */
-			status = check_path_syntax(fname);
+			status = check_path_syntax(state->fname);
 			if (!NT_STATUS_IS_OK(status)) {
 				tevent_req_nterror(req, status);
 				return tevent_req_post(req, ev);
@@ -1145,7 +1145,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			smb1req, state->in_create_disposition);
 		status = filename_convert(req,
 					  smb1req->conn,
-					  fname,
+					  state->fname,
 					  ucf_flags,
 					  NULL, /* ppath_contains_wcards */
 					  &smb_fname);
@@ -1199,11 +1199,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					     in_file_attributes,
 					     map_smb2_oplock_levels_to_samba(
 						     state->requested_oplock_level),
-					     lease_ptr,
-					     allocation_size,
+					     state->lease_ptr,
+					     state->allocation_size,
 					     0, /* private_flags */
-					     sec_desc,
-					     ea_list,
+					     state->sec_desc,
+					     state->ea_list,
 					     &state->result,
 					     &state->info,
 					     &in_context_blobs,
@@ -1216,7 +1216,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
-		op = state->result->op;
+		state->op = state->result->op;
 	}
 
 	/*
@@ -1231,7 +1231,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		last_write_time = unix_timespec_to_nt_time(
 			state->result->fsp_name->st.st_ex_mtime);
-		if (last_write_time != max_access_time) {
+		if (last_write_time != state->max_access_time) {
 			uint8_t p[8];
 			uint32_t max_access_granted;
 			DATA_BLOB blob = data_blob_const(p, sizeof(p));
@@ -1257,31 +1257,32 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (!state->replay_operation && durable_requested &&
+	if (!state->replay_operation && state->durable_requested &&
 	    (fsp_lease_type(state->result) & SMB2_LEASE_HANDLE))
 	{
-		status = SMB_VFS_DURABLE_COOKIE(state->result,
-						op,
-						&op->global->backend_cookie);
+		status = SMB_VFS_DURABLE_COOKIE(
+			state->result,
+			state->op,
+			&state->op->global->backend_cookie);
 		if (!NT_STATUS_IS_OK(status)) {
-			op->global->backend_cookie = data_blob_null;
+			state->op->global->backend_cookie = data_blob_null;
 		}
 	}
-	if (!state->replay_operation && op->global->backend_cookie.length > 0)
+	if (!state->replay_operation && state->op->global->backend_cookie.length > 0)
 	{
-		update_open = true;
+		state->update_open = true;
 
-		op->global->durable = true;
-		op->global->durable_timeout_msec = durable_timeout_msec;
+		state->op->global->durable = true;
+		state->op->global->durable_timeout_msec = state->durable_timeout_msec;
 	}
 
-	if (update_open) {
-		op->global->create_guid = _create_guid;
-		if (need_replay_cache) {
-			op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE;
+	if (state->update_open) {
+		state->op->global->create_guid = state->_create_guid;
+		if (state->need_replay_cache) {
+			state->op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE;
 		}
 
-		status = smbXsrv_open_update(op);
+		status = smbXsrv_open_update(state->op);
 		DEBUG(10, ("smb2_create_send: smbXsrv_open_update "
 			   "returned %s\n",
 			   nt_errstr(status)));
@@ -1291,7 +1292,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (state->dhnq != NULL && op->global->durable) {
+	if (state->dhnq != NULL && state->op->global->durable) {
 		uint8_t p[8] = { 0, };
 		DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
@@ -1305,7 +1306,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 	}
 
-	if (state->dh2q != NULL && op->global->durable &&
+	if (state->dh2q != NULL && state->op->global->durable &&
 	    /*
 	     * For replay operations, we return the dh2q blob
 	     * in the case of oplocks not based on the state of
@@ -1321,7 +1322,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		DATA_BLOB blob = data_blob_const(p, sizeof(p));
 		uint32_t durable_v2_response_flags = 0;
 
-		SIVAL(p, 0, op->global->durable_timeout_msec);
+		SIVAL(p, 0, state->op->global->durable_timeout_msec);
 		SIVAL(p, 4, durable_v2_response_flags);
 
 		status = smb2_create_blob_add(state->out_context_blobs,
@@ -1361,6 +1362,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 	if ((state->rqls != NULL) && (state->result->oplock_type == LEASE_OPLOCK)) {
 		uint8_t buf[52];
+		struct smb2_lease lease;
+		size_t lease_len;
 
 		lease = state->result->lease->lease;
 
-- 
2.9.4


From c1334991583811396127aa009086e9a6c734efbe Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 16:38:21 +0200
Subject: [PATCH 11/12] s3/smbd: factor out smbd_smb2_create_after_exec from
 smbd_smb2_create_send

No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 65 +++++++++++++++++++++++++---------------------
 1 file changed, 35 insertions(+), 30 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 250d4ff..15e45f9 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -888,6 +888,7 @@ static NTSTATUS smbd_smb2_create_before_exec(struct smbd_smb2_create_state *stat
 	return NT_STATUS_OK;
 }
 
+static NTSTATUS smbd_smb2_create_after_exec(struct smbd_smb2_create_state *state);
 static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state);
 
 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
@@ -1219,13 +1220,27 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		state->op = state->result->op;
 	}
 
+	status = smbd_smb2_create_after_exec(state);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	smbd_smb2_create_finish(state);
+
+	tevent_req_done(req);
+	return tevent_req_post(req, ev);
+}
+
+static NTSTATUS smbd_smb2_create_after_exec(struct smbd_smb2_create_state *state)
+{
+	NTSTATUS status;
+
+	DBG_DEBUG("response construction phase\n");
+
 	/*
-	 * here we have op == result->op
+	 * here we have state->op == state->result->op
 	 */
 
-	DEBUG(10, ("smbd_smb2_create_send: "
-		   "response construction phase\n"));
-
 	if (state->mxac != NULL) {
 		NTTIME last_write_time;
 
@@ -1236,11 +1251,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			uint32_t max_access_granted;
 			DATA_BLOB blob = data_blob_const(p, sizeof(p));
 
-			status = smbd_calculate_access_mask(smb1req->conn,
-							    state->result->fsp_name,
-							    false,
-							    SEC_FLAG_MAXIMUM_ALLOWED,
-							    &max_access_granted);
+			status = smbd_calculate_access_mask(
+				state->smb1req->conn,
+				state->result->fsp_name,
+				false,
+				SEC_FLAG_MAXIMUM_ALLOWED,
+				&max_access_granted);
 
 			SIVAL(p, 0, NT_STATUS_V(status));
 			SIVAL(p, 4, max_access_granted);
@@ -1251,8 +1267,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 				SMB2_CREATE_TAG_MXAC,
 				blob);
 			if (!NT_STATUS_IS_OK(status)) {
-				tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
+				return status;
 			}
 		}
 	}
@@ -1287,8 +1302,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			   "returned %s\n",
 			   nt_errstr(status)));
 		if (!NT_STATUS_IS_OK(status)) {
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
+			return status;
 		}
 	}
 
@@ -1301,8 +1315,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					      SMB2_CREATE_TAG_DHNQ,
 					      blob);
 		if (!NT_STATUS_IS_OK(status)) {
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
+			return status;
 		}
 	}
 
@@ -1315,8 +1328,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	     * the state of the open is used...
 	     */
 	    (!state->replay_operation ||
-	     in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH ||
-	     in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE))
+	     state->in_oplock_level == SMB2_OPLOCK_LEVEL_BATCH ||
+	     state->in_oplock_level == SMB2_OPLOCK_LEVEL_LEASE))
 	{
 		uint8_t p[8] = { 0, };
 		DATA_BLOB blob = data_blob_const(p, sizeof(p));
@@ -1330,8 +1343,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					      SMB2_CREATE_TAG_DH2Q,
 					      blob);
 		if (!NT_STATUS_IS_OK(status)) {
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
+			return status;
 		}
 	}
 
@@ -1355,8 +1367,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 					      SMB2_CREATE_TAG_QFID,
 					      blob);
 		if (!NT_STATUS_IS_OK(status)) {
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
+			return status;
 		}
 	}
 
@@ -1373,9 +1384,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 
 		if (!smb2_lease_push(&lease, buf, lease_len)) {
-			tevent_req_nterror(
-				req, NT_STATUS_INTERNAL_ERROR);
-			return tevent_req_post(req, ev);
+			return NT_STATUS_INTERNAL_ERROR;
 		}
 
 		status = smb2_create_blob_add(
@@ -1383,15 +1392,11 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			SMB2_CREATE_TAG_RQLS,
 			data_blob_const(buf, lease_len));
 		if (!NT_STATUS_IS_OK(status)) {
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
+			return status;
 		}
 	}
 
-	smbd_smb2_create_finish(state);
-
-	tevent_req_done(req);
-	return tevent_req_post(req, ev);
+	return NT_STATUS_OK;
 }
 
 static void smbd_smb2_create_finish(struct smbd_smb2_create_state *state)
-- 
2.9.4


From 71859550d2f339a790619f8e2a24dd9b8300e405 Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Thu, 20 Jul 2017 16:45:35 +0200
Subject: [PATCH 12/12] s3/smbd: use early returns in smbd_smb2_create_send

Now that we have the nice smbd_smb2_create_after_exec() and
smbd_smb2_create_finish() functions, use early returns for the create
replay and durable handle reconnect case.

No change in behaviour.

Signed-off-by: Ralph Boehme <slow at samba.org>
---
 source3/smbd/smb2_create.c | 194 ++++++++++++++++++++++++---------------------
 1 file changed, 105 insertions(+), 89 deletions(-)

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index 15e45f9..d5024a7 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -908,6 +908,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 	struct smbd_smb2_create_state *state = NULL;
 	NTSTATUS status;
 	struct smb_request *smb1req = NULL;
+	struct smb_filename *smb_fname = NULL;
+	uint32_t ucf_flags;
 
 	req = tevent_req_create(mem_ctx, &state,
 				struct smbd_smb2_create_state);
@@ -1043,6 +1045,17 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		state->result->op = state->op;
 		state->update_open = false;
 		state->info = state->op->create_action;
+
+		status = smbd_smb2_create_after_exec(state);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
+
+		smbd_smb2_create_finish(state);
+
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+
 	} else if (state->do_durable_reconnect) {
 		DATA_BLOB new_cookie = data_blob_null;
 		NTTIME now = timeval_to_nttime(&smb2req->request_time);
@@ -1112,114 +1125,117 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
 		/* save the timout for later update */
 		state->durable_timeout_msec = state->op->global->durable_timeout_msec;
-
 		state->update_open = true;
-
 		state->info = FILE_WAS_OPENED;
-	} else {
-		struct smb_filename *smb_fname = NULL;
-		uint32_t ucf_flags;
 
-		if (state->requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
-			if (state->lease_ptr == NULL) {
-				state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
-			}
-		} else {
-			state->lease_ptr = NULL;
+		status = smbd_smb2_create_after_exec(state);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
 		}
 
-		/*
-		 * For a DFS path the function parse_dfs_path()
-		 * will do the path processing.
-		 */
+		smbd_smb2_create_finish(state);
 
-		if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) {
-			/* convert '\\' into '/' */
-			status = check_path_syntax(state->fname);
-			if (!NT_STATUS_IS_OK(status)) {
-				tevent_req_nterror(req, status);
-				return tevent_req_post(req, ev);
-			}
+		tevent_req_done(req);
+		return tevent_req_post(req, ev);
+	}
+
+	if (state->requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
+		if (state->lease_ptr == NULL) {
+			state->requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 		}
+	} else {
+		state->lease_ptr = NULL;
+	}
 
-		ucf_flags = filename_create_ucf_flags(
-			smb1req, state->in_create_disposition);
-		status = filename_convert(req,
-					  smb1req->conn,
-					  state->fname,
-					  ucf_flags,
-					  NULL, /* ppath_contains_wcards */
-					  &smb_fname);
+	/*
+	 * For a DFS path the function parse_dfs_path()
+	 * will do the path processing.
+	 */
+
+	if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) {
+		/* convert '\\' into '/' */
+		status = check_path_syntax(state->fname);
 		if (!NT_STATUS_IS_OK(status)) {
 			tevent_req_nterror(req, status);
 			return tevent_req_post(req, ev);
 		}
+	}
 
-		/*
-		 * MS-SMB2: 2.2.13 SMB2 CREATE Request
-		 * ImpersonationLevel ... MUST contain one of the
-		 * following values. The server MUST validate this
-		 * field, but otherwise ignore it.
-		 *
-		 * NB. The source4/torture/smb2/durable_open.c test
-		 * shows this check is only done on real opens, not
-		 * on durable handle-reopens.
-		 */
+	ucf_flags = filename_create_ucf_flags(
+		smb1req, state->in_create_disposition);
+	status = filename_convert(req,
+				  smb1req->conn,
+				  state->fname,
+				  ucf_flags,
+				  NULL, /* ppath_contains_wcards */
+				  &smb_fname);
+	if (!NT_STATUS_IS_OK(status)) {
+		tevent_req_nterror(req, status);
+		return tevent_req_post(req, ev);
+	}
 
-		if (in_impersonation_level >
-		    SMB2_IMPERSONATION_DELEGATE) {
-			tevent_req_nterror(req,
-					   NT_STATUS_BAD_IMPERSONATION_LEVEL);
-			return tevent_req_post(req, ev);
-		}
+	/*
+	 * MS-SMB2: 2.2.13 SMB2 CREATE Request
+	 * ImpersonationLevel ... MUST contain one of the
+	 * following values. The server MUST validate this
+	 * field, but otherwise ignore it.
+	 *
+	 * NB. The source4/torture/smb2/durable_open.c test
+	 * shows this check is only done on real opens, not
+	 * on durable handle-reopens.
+	 */
 
-		/*
-		 * We know we're going to do a local open, so now
-		 * we must be protocol strict. JRA.
-		 *
-		 * MS-SMB2: 3.3.5.9 - Receiving an SMB2 CREATE Request
-		 * If the file name length is greater than zero and the
-		 * first character is a path separator character, the
-		 * server MUST fail the request with
-		 * STATUS_INVALID_PARAMETER.
-		 */
-		if (in_name[0] == '\\' || in_name[0] == '/') {
-			tevent_req_nterror(req,
-					   NT_STATUS_INVALID_PARAMETER);
-			return tevent_req_post(req, ev);
-		}
+	if (in_impersonation_level > SMB2_IMPERSONATION_DELEGATE) {
+		tevent_req_nterror(req, NT_STATUS_BAD_IMPERSONATION_LEVEL);
+		return tevent_req_post(req, ev);
+	}
 
-		status = SMB_VFS_CREATE_FILE(smb1req->conn,
-					     smb1req,
-					     0, /* root_dir_fid */
-					     smb_fname,
-					     in_desired_access,
-					     in_share_access,
-					     state->in_create_disposition,
-					     in_create_options,
-					     in_file_attributes,
-					     map_smb2_oplock_levels_to_samba(
-						     state->requested_oplock_level),
-					     state->lease_ptr,
-					     state->allocation_size,
-					     0, /* private_flags */
-					     state->sec_desc,
-					     state->ea_list,
-					     &state->result,
-					     &state->info,
-					     &in_context_blobs,
-					     state->out_context_blobs);
-		if (!NT_STATUS_IS_OK(status)) {
-			if (open_was_deferred(smb1req->xconn, smb1req->mid)) {
-				SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
-				return req;
-			}
-			tevent_req_nterror(req, status);
-			return tevent_req_post(req, ev);
+	/*
+	 * We know we're going to do a local open, so now
+	 * we must be protocol strict. JRA.
+	 *
+	 * MS-SMB2: 3.3.5.9 - Receiving an SMB2 CREATE Request
+	 * If the file name length is greater than zero and the
+	 * first character is a path separator character, the
+	 * server MUST fail the request with
+	 * STATUS_INVALID_PARAMETER.
+	 */
+	if (in_name[0] == '\\' || in_name[0] == '/') {
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+		return tevent_req_post(req, ev);
+	}
+
+	status = SMB_VFS_CREATE_FILE(smb1req->conn,
+				     smb1req,
+				     0, /* root_dir_fid */
+				     smb_fname,
+				     in_desired_access,
+				     in_share_access,
+				     state->in_create_disposition,
+				     in_create_options,
+				     in_file_attributes,
+				     map_smb2_oplock_levels_to_samba(
+					     state->requested_oplock_level),
+				     state->lease_ptr,
+				     state->allocation_size,
+				     0, /* private_flags */
+				     state->sec_desc,
+				     state->ea_list,
+				     &state->result,
+				     &state->info,
+				     &in_context_blobs,
+				     state->out_context_blobs);
+	if (!NT_STATUS_IS_OK(status)) {
+		if (open_was_deferred(smb1req->xconn, smb1req->mid)) {
+			SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
+			return req;
 		}
-		state->op = state->result->op;
+		tevent_req_nterror(req, status);
+		return tevent_req_post(req, ev);
 	}
 
+	state->op = state->result->op;
+
 	status = smbd_smb2_create_after_exec(state);
 	if (tevent_req_nterror(req, status)) {
 		return tevent_req_post(req, ev);
-- 
2.9.4



More information about the samba-technical mailing list