[PATCH] Factor out smbd_smb2_create_file from smbd_smb2_create_send

Ralph Böhme slow at samba.org
Sat Jul 15 20:07:02 UTC 2017


Hi!

From the attic.

Please review&push if ok. Just passed a private autobuild.

Cheerio!
-slow
-------------- next part --------------
From 3e6a39a8810854610995b8642cb4166ecc19b9ea Mon Sep 17 00:00:00 2001
From: Ralph Boehme <slow at samba.org>
Date: Sat, 15 Jul 2017 15:23:46 +0200
Subject: [PATCH] s3/smbd: factor out smbd_smb2_create_file from
 smbd_smb2_create_send

No change in behaviour, smbd_smb2_create_send() has grown really large
with insane indentation levels, so this had to be split up.

Best viewed with

$ git show -w

One subtlety to note is the new use of NT_STATUS_RETRY as return code
from smbd_smb2_create_file() to tell the caller smbd_smb2_create_send()
an open was deferred and cause it to directly return the tevent request.

While at it, update the DEBUG macros to the new form.

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

diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index c4fe247..969bb16 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -449,6 +449,705 @@ struct smbd_smb2_create_state {
 	struct smb2_create_blobs *out_context_blobs;
 };
 
+static NTSTATUS smbd_smb2_create_file(
+	TALLOC_CTX *mem_ctx,
+	struct tevent_context *ev,
+	struct smbd_smb2_request *smb2req,
+	const uint8_t in_oplock_level,
+	const uint32_t in_impersonation_level,
+	const uint32_t in_desired_access,
+	const uint32_t in_share_access,
+	const uint32_t in_create_disposition,
+	const char *in_name,
+	const struct smb2_create_blobs in_context_blobs,
+	struct smbd_smb2_create_state *state,
+	struct smb_request *smb1req,
+	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,
+	uint32_t *_in_file_attributes,
+	uint32_t *_in_create_options,
+	int *_requested_oplock_level,
+	bool *_replay_operation,
+	int *_info,
+	files_struct **_result)
+{
+	char *fname = NULL;
+	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
+	files_struct *result = NULL;
+	uint32_t in_file_attributes = *_in_file_attributes;
+	uint32_t in_create_options = *_in_create_options;
+	int requested_oplock_level = *_requested_oplock_level;
+	bool replay_operation = *_replay_operation;
+	int info;
+	NTSTATUS status;
+
+	*_result = NULL;
+	*_info = 0;
+
+	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);
+	}
+#endif
+
+	fname = talloc_strdup(state, in_name);
+	if (fname == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	if (exta) {
+		if (!lp_ea_support(SNUM(smb2req->tcon->compat))) {
+			return NT_STATUS_EAS_NOT_SUPPORTED;
+		}
+
+		ea_list = read_nttrans_ea_list(mem_ctx,
+					       (const char *)exta->data.data,
+					       exta->data.length);
+		if (ea_list == NULL) {
+			DBG_ERR("read_ea_name_list failed.\n");
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		/*
+		 * 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)) {
+			return STATUS_INVALID_EA_NAME;
+		}
+	}
+
+	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 {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+	}
+
+	if (secd) {
+		enum ndr_err_code ndr_err;
+
+		sec_desc = talloc_zero(state, struct security_descriptor);
+		if (sec_desc == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+
+		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)) {
+			DBG_NOTICE("ndr_pull_security_descriptor failed: %s\n",
+				   ndr_errstr(ndr_err));
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+	}
+
+	if (dhnq) {
+		if (dhnq->data.length != 16) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		if (dh2q) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		/*
+		 * 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) {
+		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) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		if (dhnq) {
+			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 (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+		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;
+
+		/*
+		 * durable handle v2 request processed below
+		 */
+		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);
+		}
+
+		/*
+		 * 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 (!NT_STATUS_IS_OK(status)) {
+			DBG_WARNING("smb2srv_open_lookup_replay_cache "
+				    "failed: %s\n", nt_errstr(status));
+			return status;
+		} 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.
+			 */
+			return NT_STATUS_DUPLICATE_OBJECTID;
+		}
+	}
+
+	if (dhnc) {
+		persistent_id = BVAL(dhnc->data.data, 0);
+
+		do_durable_reconnect = true;
+	}
+
+	if (dh2c) {
+		const uint8_t *p = dh2c->data.data;
+		DATA_BLOB create_guid_blob;
+
+		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 (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+		create_guid = &_create_guid;
+
+		do_durable_reconnect = true;
+	}
+
+	if (alsi) {
+		if (alsi->data.length != 8) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+		allocation_size = BVAL(alsi->data.data, 0);
+	}
+
+	if (twrp) {
+		NTTIME nttime;
+		time_t t;
+		struct tm *tm;
+
+		if (twrp->data.length != 8) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		nttime = BVAL(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 (fname == NULL) {
+			return NT_STATUS_NO_MEMORY;
+		}
+		/*
+		 * Tell filename_create_ucf_flags() this
+		 * is an @GMT path.
+		 */
+		smb1req->flags2 |= FLAGS2_REPARSE_PATH;
+	}
+
+	if (qfid) {
+		if (qfid->data.length != 0) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+	}
+
+	if (rqls) {
+		lease_len = smb2_lease_pull(rqls->data.data,
+					    rqls->data.length,
+					    &lease);
+		if (lease_len == -1) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+		lease_ptr = &lease;
+
+		if (DEBUGLEVEL >= 10) {
+			DBG_DEBUG("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))
+		{
+			DBG_DEBUG("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)
+			{
+				return NT_STATUS_ACCESS_DENIED;
+			}
+			if (!smb2_lease_key_equal(&lease.lease_key,
+						  &op_ls->lease_key))
+			{
+				return NT_STATUS_ACCESS_DENIED;
+			}
+		}
+	}
+
+	/* 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;
+
+	DBG_DEBUG("open execution phase\n");
+
+	/*
+	 * 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)) {
+			DBG_NOTICE("smb2srv_open_recreate failed: %s\n",
+				  nt_errstr(status));
+			return status;
+		}
+
+		DBG_DEBUG("durable handle recreate %s\n",
+			   op->global->durable ? "succeeded" : "failed");
+
+		if (!op->global->durable) {
+			talloc_free(op);
+			return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+		}
+
+		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;
+
+			return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+			DBG_NOTICE("durable_reconnect failed: %s => %s\n",
+				   nt_errstr(status),
+				   nt_errstr(return_status));
+			return return_status;
+		}
+
+		DBG_DEBUG("result->oplock_type=%u, lease_ptr==%p\n",
+			  (unsigned)result->oplock_type, lease_ptr);
+
+		status = smbd_smb2_create_durable_lease_check(
+			smb1req, fname, result, lease_ptr);
+		if (!NT_STATUS_IS_OK(status)) {
+			close_file(smb1req, result, SHUTDOWN_CLOSE);
+			return status;
+		}
+
+		data_blob_free(&op->global->backend_cookie);
+		op->global->backend_cookie = new_cookie;
+
+		op->status = NT_STATUS_OK;
+		op->global->disconnect_time = 0;
+
+		/* save the timout for later update */
+		durable_timeout_msec = op->global->durable_timeout_msec;
+
+		update_open = true;
+
+		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;
+		}
+
+		/*
+		 * 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)) {
+				return status;
+			}
+		}
+
+		ucf_flags = filename_create_ucf_flags(smb1req, in_create_disposition);
+		status = filename_convert(state,
+					  smb1req->conn,
+					  fname,
+					  ucf_flags,
+					  NULL, /* ppath_contains_wcards */
+					  &smb_fname);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+
+		/*
+		 * 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.
+		 */
+
+		if (in_impersonation_level > SMB2_IMPERSONATION_DELEGATE) {
+			return NT_STATUS_BAD_IMPERSONATION_LEVEL;
+		}
+
+		/*
+		 * 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] == '/') {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		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 NT_STATUS_RETRY;
+			}
+			return status;
+		}
+		op = result->op;
+	}
+
+	/*
+	 * here we have op == result->op
+	 */
+
+	DBG_DEBUG("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)) {
+				return status;
+			}
+		}
+	}
+
+	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;
+
+		op->global->durable = true;
+		op->global->durable_timeout_msec = durable_timeout_msec;
+	}
+
+	if (update_open) {
+		op->global->create_guid = _create_guid;
+		if (need_replay_cache) {
+			op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE;
+		}
+
+		status = smbXsrv_open_update(op);
+		if (!NT_STATUS_IS_OK(status)) {
+			DBG_ERR("smbXsrv_open_update returned %s\n",
+				nt_errstr(status));
+			return status;
+		}
+	}
+
+	if (dhnq && op->global->durable) {
+		uint8_t p[8] = { 0, };
+		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);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+	}
+
+	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)) {
+			return status;
+		}
+	}
+
+	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));
+
+		ZERO_STRUCT(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_QFID,
+					      blob);
+		if (!NT_STATUS_IS_OK(status)) {
+			return status;
+		}
+	}
+
+	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)) {
+			return NT_STATUS_INTERNAL_ERROR;
+		}
+
+		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)) {
+			return status;
+		}
+	}
+
+	*_in_file_attributes = in_file_attributes;
+	*_in_create_options = in_create_options;
+	*_requested_oplock_level = requested_oplock_level;
+	*_replay_operation = replay_operation;
+	*_result = result;
+	*_info = info;
+	return NT_STATUS_OK;
+}
+
 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 			struct tevent_context *ev,
 			struct smbd_smb2_request *smb2req,
@@ -650,706 +1349,35 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 		}
 		info = FILE_WAS_CREATED;
 	} 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);
-#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);
-		}
-#endif
-
-		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);
-			}
-
-			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);
-			}
-		}
-
-		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);
-			}
-
-			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 (dhnq) {
-			if (dhnq->data.length != 16) {
-				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);
-			}
-
-			/*
-			 * 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) {
-			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);
-			}
-
-			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;
-
-			/*
-			 * 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) {
-				/*
-				 * Set the timeout to 1 min as default.
-				 *
-				 * This matches Windows 2012.
-				 */
-				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) {
-				/*
-				 * 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);
-			}
-		}
-
-		if (dhnc) {
-			persistent_id = BVAL(dhnc->data.data, 0);
-
-			do_durable_reconnect = true;
-		}
-
-		if (dh2c) {
-			const uint8_t *p = dh2c->data.data;
-			DATA_BLOB create_guid_blob;
-
-			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);
-			}
-			create_guid = &_create_guid;
-
-			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->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);
-
-			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);
-			}
-			/*
-			 * 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 (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);
-				}
-			}
-		}
-
-		/* 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"));
-
-		/*
-		 * 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, ("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);
-				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;
-
-				return_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
-
-				DEBUG(3, ("smbd_smb2_create_send: "
-					  "durable_reconnect failed: %s => %s\n",
-					  nt_errstr(status),
-					  nt_errstr(return_status)));
-
-				tevent_req_nterror(req, return_status);
-				return tevent_req_post(req, ev);
-			}
-
-			DEBUG(10, ("result->oplock_type=%u, lease_ptr==%p\n",
-				   (unsigned)result->oplock_type, lease_ptr));
-
-			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);
-			}
-
-			data_blob_free(&op->global->backend_cookie);
-			op->global->backend_cookie = new_cookie;
-
-			op->status = NT_STATUS_OK;
-			op->global->disconnect_time = 0;
-
-			/* save the timout for later update */
-			durable_timeout_msec = op->global->durable_timeout_msec;
-
-			update_open = true;
-
-			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;
-			}
-
-			/*
-			 * 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)) {
-					tevent_req_nterror(req, status);
-					return tevent_req_post(req, ev);
-				}
-			}
-
-			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);
-			}
-
-			/*
-			 * 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.
-			 */
-
-			if (in_impersonation_level >
-					SMB2_IMPERSONATION_DELEGATE) {
-				tevent_req_nterror(req,
-					NT_STATUS_BAD_IMPERSONATION_LEVEL);
-				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,
-						     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;
-		}
-
-		/*
-		 * here we have op == result->op
-		 */
-
-		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 (!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;
-
-			op->global->durable = true;
-			op->global->durable_timeout_msec = durable_timeout_msec;
-		}
-
-		if (update_open) {
-			op->global->create_guid = _create_guid;
-			if (need_replay_cache) {
-				op->flags |= SMBXSRV_OPEN_NEED_REPLAY_CACHE;
-			}
-
-			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);
-			}
-		}
-
-		if (dhnq && op->global->durable) {
-			uint8_t p[8] = { 0, };
-			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);
-			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 (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));
-
-			ZERO_STRUCT(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_QFID,
-						      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];
-
-			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);
+		status = smbd_smb2_create_file(mem_ctx,
+					       ev,
+					       smb2req,
+					       in_oplock_level,
+					       in_impersonation_level,
+					       in_desired_access,
+					       in_share_access,
+					       in_create_disposition,
+					       in_name,
+					       in_context_blobs,
+					       state,
+					       smb1req,
+					       dhnc,
+					       dh2c,
+					       dhnq,
+					       dh2q,
+					       rqls,
+					       &in_file_attributes,
+					       &in_create_options,
+					       &requested_oplock_level,
+					       &replay_operation,
+					       &info,
+					       &result);
+		if (!NT_STATUS_IS_OK(status)) {
+			if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+				return req;
 			}
+			tevent_req_nterror(req, status);
+			return tevent_req_post(req, ev);
 		}
 	}
 
-- 
2.9.4



More information about the samba-technical mailing list