Revert "smbd: implement smbd_impersonate_{conn_vuid,conn_sess,root,guest}_create...
[samba.git] / source3 / smbd / smb2_create.c
index e323db3c402b68fe97fea09161e9724849de1626..fdd04ac0331f1239a80ff2ee3e18b2c3dba8662a 100644 (file)
@@ -29,6 +29,9 @@
 #include "../lib/util/tevent_ntstatus.h"
 #include "messages.h"
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_SMB2
+
 int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
 {
        switch(in_oplock_level) {
@@ -225,7 +228,7 @@ NTSTATUS smbd_smb2_request_process_create(struct smbd_smb2_request *smb2req)
        }
 
        tsubreq = smbd_smb2_create_send(smb2req,
-                                      smb2req->sconn->ev_ctx,
+                                      smb2req->ev_ctx,
                                       smb2req,
                                       in_oplock_level,
                                       in_impersonation_level,
@@ -378,6 +381,7 @@ static NTSTATUS smbd_smb2_create_durable_lease_check(struct smb_request *smb1req
        const char *requested_filename, const struct files_struct *fsp,
        const struct smb2_lease *lease_ptr)
 {
+       char *filename = NULL;
        struct smb_filename *smb_fname = NULL;
        uint32_t ucf_flags;
        NTSTATUS status;
@@ -404,10 +408,23 @@ static NTSTATUS smbd_smb2_create_durable_lease_check(struct smb_request *smb1req
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
+       filename = talloc_strdup(talloc_tos(), requested_filename);
+       if (filename == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* This also converts '\' to '/' */
+       status = check_path_syntax(filename);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(filename);
+               return status;
+       }
+
        ucf_flags = filename_create_ucf_flags(smb1req, FILE_OPEN);
        status = filename_convert(talloc_tos(), fsp->conn,
-                                 requested_filename, ucf_flags,
-                                 NULL, &smb_fname);
+                                 filename, ucf_flags,
+                                 NULL, NULL, &smb_fname);
+       TALLOC_FREE(filename);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10, ("filename_convert returned %s\n",
                           nt_errstr(status)));
@@ -441,6 +458,40 @@ struct smbd_smb2_create_state {
        uint8_t in_oplock_level;
        uint32_t in_create_disposition;
        int requested_oplock_level;
+       int info;
+       char *fname;
+       struct ea_list *ea_list;
+       NTTIME max_access_time;
+       struct security_descriptor *sec_desc;
+       uint64_t allocation_size;
+       struct GUID _create_guid;
+       struct GUID *create_guid;
+       bool update_open;
+       bool durable_requested;
+       uint32_t durable_timeout_msec;
+       bool do_durable_reconnect;
+       uint64_t persistent_id;
+       struct smb2_lease lease;
+       struct smb2_lease *lease_ptr;
+       ssize_t lease_len;
+       bool need_replay_cache;
+       struct smbXsrv_open *op;
+       time_t twrp_time;
+       time_t *twrp_timep;
+
+       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;
@@ -455,14 +506,125 @@ struct smbd_smb2_create_state {
        struct smb2_create_blobs *out_context_blobs;
 };
 
-static void smbd_smb2_create_finish(struct tevent_req *req,
-                                   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 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_before_exec(struct tevent_req *req);
+static void smbd_smb2_create_after_exec(struct tevent_req *req);
+static void smbd_smb2_create_finish(struct tevent_req *req);
 
 static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                        struct tevent_context *ev,
@@ -481,38 +643,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;
-       int info;
-       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 = 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
+       struct smb_filename *smb_fname = NULL;
+       uint32_t ucf_flags;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct smbd_smb2_create_state);
@@ -533,14 +665,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
        state->smb1req = smb1req;
 
        if (smb2req->subreq == NULL) {
-               DEBUG(10,("smbd_smb2_create: name[%s]\n",
-                       in_name));
+               DBG_DEBUG("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 ));
+               DBG_DEBUG("reentrant for file %s\n", in_name);
 
                state->id = old_state->id;
                state->request_time = old_state->request_time;
@@ -563,8 +693,8 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
 
        in_file_attributes &= ~FILE_FLAG_POSIX_SEMANTICS;
 
-       fname = talloc_strdup(state, in_name);
-       if (tevent_req_nomem(fname, req)) {
+       state->fname = talloc_strdup(state, in_name);
+       if (tevent_req_nomem(state->fname, req)) {
                return tevent_req_post(req, state->ev);
        }
 
@@ -573,194 +703,299 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, state->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);
-       if (smb2req->xconn->smb2.server.capabilities & SMB2_CAP_LEASING) {
-               rqls = smb2_create_blob_find(&in_context_blobs,
-                                            SMB2_CREATE_TAG_RQLS);
-       }
-
-       if ((dhnc && dh2c) || (dhnc && dh2q) || (dh2c && dhnq) ||
-           (dh2q && dh2c))
-       {
-               /* 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, state->ev);
        }
 
-       if (dhnc) {
-               uint32_t num_blobs_allowed;
+       if (IS_IPC(smb1req->conn)) {
+               const char *pipe_name = in_name;
 
-               if (dhnc->data.length != 16) {
-                       tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               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, state->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 (dhnq) {
-                       num_blobs_allowed = 2;
-               } else {
-                       num_blobs_allowed = 1;
+               if (!lp_nt_pipe_support()) {
+                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+                       return tevent_req_post(req, state->ev);
                }
 
-               if (rqls != NULL) {
-                       num_blobs_allowed += 1;
+               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, state->ev);
                }
+               state->info = FILE_WAS_OPENED;
+
+               smbd_smb2_create_finish(req);
+               return req;
 
-               if (in_context_blobs.num_blobs != num_blobs_allowed) {
+       } 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, state->ev);
                }
-       }
 
-       if (dh2c) {
-               uint32_t num_blobs_allowed;
+               status = file_new(smb1req, smb1req->conn, &state->result);
+               if(!NT_STATUS_IS_OK(status)) {
+                       tevent_req_nterror(req, status);
+                       return tevent_req_post(req, state->ev);
+               }
 
-               if (dh2c->data.length != 36) {
-                       tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               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, state->ev);
                }
+               state->info = FILE_WAS_CREATED;
 
-               /*
-                * 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.)
-                */
+               smbd_smb2_create_finish(req);
+               return req;
+       }
 
-               num_blobs_allowed = 1;
+       smbd_smb2_create_before_exec(req);
+       if (!tevent_req_is_in_progress(req)) {
+               return tevent_req_post(req, state->ev);
+       }
 
-               if (rqls != NULL) {
-                       num_blobs_allowed += 1;
+       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 (state->replay_operation) {
+               state->result = state->op->compat;
+               state->result->op = state->op;
+               state->update_open = false;
+               state->info = state->op->create_action;
+
+               smbd_smb2_create_after_exec(req);
+               if (!tevent_req_is_in_progress(req)) {
+                       return req;
                }
 
-               if (in_context_blobs.num_blobs != num_blobs_allowed) {
-                       tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+               smbd_smb2_create_finish(req);
+               return req;
+
+       } 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,
+                                              state->persistent_id,
+                                              state->create_guid,
+                                              now,
+                                              &state->op);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DBG_NOTICE("smb2srv_open_recreate failed: %s\n",
+                                  nt_errstr(status));
+                       tevent_req_nterror(req, status);
                        return tevent_req_post(req, state->ev);
                }
-       }
 
-       if (IS_IPC(smb1req->conn)) {
-               const char *pipe_name = in_name;
+               DBG_DEBUG("%s to recreate durable handle\n",
+                         state->op->global->durable ? "succeeded" : "failed");
 
-               if (dhnc || dh2c) {
-                       /* durable handles are not supported on IPC$ */
-                       tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
+               if (!state->op->global->durable) {
+                       talloc_free(state->op);
+                       tevent_req_nterror(req,
+                                          NT_STATUS_OBJECT_NAME_NOT_FOUND);
                        return tevent_req_post(req, state->ev);
                }
 
-               if (!lp_nt_pipe_support()) {
-                       tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+               status = SMB_VFS_DURABLE_RECONNECT(smb1req->conn,
+                                                  smb1req,
+                                                  state->op, /* smbXsrv_open input */
+                                                  state->op->global->backend_cookie,
+                                                  state->op, /* TALLOC_CTX */
+                                                  &state->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));
+
+                       tevent_req_nterror(req, return_status);
                        return tevent_req_post(req, state->ev);
                }
 
-               status = open_np_file(smb1req, pipe_name, &state->result);
+               DBG_DEBUG("oplock_type=%u, lease_ptr==%p\n",
+                         (unsigned)state->result->oplock_type, state->lease_ptr);
+
+               status = smbd_smb2_create_durable_lease_check(
+                       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, state->ev);
                }
-               info = FILE_WAS_OPENED;
-
-               smbd_smb2_create_finish(req,
-                                       smb2req,
-                                       smb1req,
-                                       state->result,
-                                       state->replay_operation,
-                                       state->in_oplock_level,
-                                       state->in_create_disposition,
-                                       info);
-               return req;
 
-       } else if (CAN_PRINT(smb1req->conn)) {
-               if (dhnc || dh2c) {
-                       /* durable handles are not supported on printers */
-                       tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
-                       return tevent_req_post(req, state->ev);
+               data_blob_free(&state->op->global->backend_cookie);
+               state->op->global->backend_cookie = new_cookie;
+
+               state->op->status = NT_STATUS_OK;
+               state->op->global->disconnect_time = 0;
+
+               /* 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;
+
+               smbd_smb2_create_after_exec(req);
+               if (!tevent_req_is_in_progress(req)) {
+                       return req;
                }
 
-               status = file_new(smb1req, smb1req->conn, &state->result);
-               if(!NT_STATUS_IS_OK(status)) {
-                       tevent_req_nterror(req, status);
-                       return tevent_req_post(req, state->ev);
+               smbd_smb2_create_finish(req);
+               return req;
+       }
+
+       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 = print_spool_open(state->result, in_name,
-                                         smb1req->vuid);
+       /*
+        * 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)) {
-                       file_free(smb1req, state->result);
                        tevent_req_nterror(req, status);
                        return tevent_req_post(req, state->ev);
                }
-               info = FILE_WAS_CREATED;
-
-               smbd_smb2_create_finish(req,
-                                       smb2req,
-                                       smb1req,
-                                       state->result,
-                                       state->replay_operation,
-                                       state->in_oplock_level,
-                                       state->in_create_disposition,
-                                       info);
-               return req;
        }
 
-       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);
+       ucf_flags = filename_create_ucf_flags(
+               smb1req, state->in_create_disposition);
+       status = filename_convert(req,
+                                 smb1req->conn,
+                                 state->fname,
+                                 ucf_flags,
+                                 state->twrp_timep,
+                                 NULL, /* ppath_contains_wcards */
+                                 &smb_fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return tevent_req_post(req, state->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, state->ev);
        }
-#endif
 
-       if (exta) {
+       /*
+        * 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, state->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, state->ev);
+       }
+       state->op = state->result->op;
+
+       smbd_smb2_create_after_exec(req);
+       if (!tevent_req_is_in_progress(req)) {
+               return req;
+       }
+
+       smbd_smb2_create_finish(req);
+       return req;
+}
+
+static void smbd_smb2_create_before_exec(struct tevent_req *req)
+{
+       struct smbd_smb2_create_state *state = tevent_req_data(
+               req, struct smbd_smb2_create_state);
+       struct smb_request *smb1req = state->smb1req;
+       struct smbd_smb2_request *smb2req = state->smb2req;
+       NTSTATUS status;
+
+       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, state->ev);
+                       tevent_req_nterror(req, NT_STATUS_EAS_NOT_SUPPORTED);
+                       return;
                }
 
-               ea_list = read_nttrans_ea_list(mem_ctx,
-                                              (const char *)exta->data.data, exta->data.length);
-               if (!ea_list) {
+               state->ea_list = read_nttrans_ea_list(
+                       state,
+                       (const char *)state->exta->data.data,
+                       state->exta->data.length);
+               if (state->ea_list == NULL) {
                        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, state->ev);
+                       return;
                }
 
                /*
@@ -769,115 +1004,116 @@ 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)) {
+               if (ea_list_has_invalid_name(state->ea_list)) {
                        tevent_req_nterror(req, STATUS_INVALID_EA_NAME);
-                       return tevent_req_post(req, state->ev);
+                       return;
                }
        }
 
-       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);
+       if (state->mxac != NULL) {
+               if (state->mxac->data.length == 0) {
+                       state->max_access_time = 0;
+               } else if (state->mxac->data.length == 8) {
+                       state->max_access_time = BVAL(state->mxac->data.data, 0);
                } else {
                        tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-                       return tevent_req_post(req, state->ev);
+                       return;
                }
        }
 
-       if (secd) {
+       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, state->ev);
+               state->sec_desc = talloc_zero(state, struct security_descriptor);
+               if (tevent_req_nomem(state->sec_desc, req)) {
+                       return;
                }
 
-               ndr_err = ndr_pull_struct_blob(&secd->data,
-                                              sec_desc, sec_desc,
+               ndr_err = ndr_pull_struct_blob(&state->secd->data,
+                                              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, state->ev);
+                       return;
                }
        }
 
-       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, state->ev);
+                       return;
                }
 
-               if (dh2q) {
+               if (state->dh2q != NULL) {
                        tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-                       return tevent_req_post(req, state->ev);
+                       return;
                }
 
                /*
                 * 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 (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, state->ev);
+                       return;
                }
 
-               if (dhnq) {
+               if (state->dhnq != NULL) {
                        tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
-                       return tevent_req_post(req, state->ev);
+                       return;
                }
 
                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);
+                                           &state->_create_guid);
                if (tevent_req_nterror(req, status)) {
-                       return tevent_req_post(req, state->ev);
+                       return;
                }
-               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);
                }
 
                /*
@@ -891,16 +1127,16 @@ 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)) {
                        DBG_WARNING("smb2srv_open_lookup_replay_cache "
                                    "failed: %s\n", nt_errstr(status));
-                       return tevent_req_post(req, state->ev);
+                       return;
                } else if (!state->replay_operation) {
                        /*
                         * If a create without replay operation flag
@@ -909,107 +1145,91 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                         */
                        status = NT_STATUS_DUPLICATE_OBJECTID;
                        (void)tevent_req_nterror(req, status);
-                       return tevent_req_post(req, state->ev);
+                       return;
                }
        }
 
-       if (dhnc) {
-               persistent_id = BVAL(dhnc->data.data, 0);
-
-               do_durable_reconnect = true;
+       if (state->dhnc != NULL) {
+               state->persistent_id = BVAL(state->dhnc->data.data, 0);
+               state->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);
+               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);
+                                           &state->_create_guid);
                if (tevent_req_nterror(req, status)) {
-                       return tevent_req_post(req, state->ev);
+                       return;
                }
-               create_guid = &_create_guid;
 
-               do_durable_reconnect = true;
+               state->create_guid = &state->_create_guid;
+               state->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, state->ev);
+                       return;
                }
-               allocation_size = BVAL(alsi->data.data, 0);
+               state->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, state->ev);
+                       return;
                }
 
-               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, state->ev);
-               }
-               /*
-                * Tell filename_create_ucf_flags() this
-                * is an @GMT path.
-                */
+               nttime = BVAL(state->twrp->data.data, 0);
+               state->twrp_time = nt_time_to_unix(nttime);
+               state->twrp_timep = &state->twrp_time;
+
                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, state->ev);
+                       return;
                }
        }
 
-       if (rqls) {
-               lease_len = smb2_lease_pull(
-                       rqls->data.data, rqls->data.length, &lease);
+       if (state->rqls != NULL) {
+               ssize_t lease_len = -1;
+
+               lease_len = smb2_lease_pull(state->rqls->data.data,
+                                           state->rqls->data.length,
+                                           &state->lease);
                if (lease_len == -1) {
                        tevent_req_nterror(
                                req, NT_STATUS_INVALID_PARAMETER);
-                       return tevent_req_post(req, state->ev);
+                       return;
                }
-               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);
+                       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)) {
+                   (state->lease.lease_version != 1))
+               {
                        DEBUG(10, ("v2 lease key only for SMB3\n"));
-                       lease_ptr = NULL;
+                       state->lease_ptr = NULL;
                }
 
                /*
@@ -1019,227 +1239,49 @@ 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, state->ev);
+                               return;
                        }
-                       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, state->ev);
+                               return;
                        }
                }
        }
 
-       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 (state->replay_operation) {
-               state->result = op->compat;
-               state->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, state->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, state->ev);
-               }
-
-               status = SMB_VFS_DURABLE_RECONNECT(smb1req->conn,
-                                                  smb1req,
-                                                  op, /* smbXsrv_open input */
-                                                  op->global->backend_cookie,
-                                                  op, /* TALLOC_CTX */
-                                                  &state->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, state->ev);
-               }
-
-               DEBUG(10, ("result->oplock_type=%u, lease_ptr==%p\n",
-                          (unsigned)state->result->oplock_type, lease_ptr));
-
-               status = smbd_smb2_create_durable_lease_check(
-                       smb1req, fname, state->result, 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, state->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 (state->requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
-                       if (lease_ptr == NULL) {
-                               state->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, state->ev);
-                       }
-               }
-
-               ucf_flags = filename_create_ucf_flags(
-                       smb1req, state->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, state->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, state->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, state->ev);
-               }
+       return;
+}
 
-               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),
-                                            lease_ptr,
-                                            allocation_size,
-                                            0, /* private_flags */
-                                            sec_desc,
-                                            ea_list,
-                                            &state->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, state->ev);
-               }
-               op = state->result->op;
-       }
+static void smbd_smb2_create_after_exec(struct tevent_req *req)
+{
+       struct smbd_smb2_create_state *state = tevent_req_data(
+               req, struct smbd_smb2_create_state);
+       struct smb_request *smb1req = state->smb1req;
+       NTSTATUS status;
 
        /*
-        * here we have op == state->result->op
+        * here we have op == result->op
         */
 
        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(
                        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));
@@ -1260,46 +1302,49 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                blob);
                        if (!NT_STATUS_IS_OK(status)) {
                                tevent_req_nterror(req, status);
-                               return tevent_req_post(req, state->ev);
+                               tevent_req_post(req, state->ev);
+                               return;
                        }
                }
        }
 
-       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)));
                if (!NT_STATUS_IS_OK(status)) {
                        tevent_req_nterror(req, status);
-                       return tevent_req_post(req, state->ev);
+                       tevent_req_post(req, state->ev);
+                       return;
                }
        }
 
-       if (dhnq && 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));
 
@@ -1309,11 +1354,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                              blob);
                if (!NT_STATUS_IS_OK(status)) {
                        tevent_req_nterror(req, status);
-                       return tevent_req_post(req, state->ev);
+                       tevent_req_post(req, state->ev);
+                       return;
                }
        }
 
-       if (dh2q && 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
@@ -1329,7 +1375,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,
@@ -1338,11 +1384,12 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                              blob);
                if (!NT_STATUS_IS_OK(status)) {
                        tevent_req_nterror(req, status);
-                       return tevent_req_post(req, state->ev);
+                       tevent_req_post(req, state->ev);
+                       return;
                }
        }
 
-       if (qfid) {
+       if (state->qfid != NULL) {
                uint8_t p[32];
                uint64_t file_index = get_FileIndex(state->result->conn,
                                                    &state->result->fsp_name->st);
@@ -1363,12 +1410,15 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                              blob);
                if (!NT_STATUS_IS_OK(status)) {
                        tevent_req_nterror(req, status);
-                       return tevent_req_post(req, state->ev);
+                       tevent_req_post(req, state->ev);
+                       return;
                }
        }
 
-       if ((rqls != NULL) && (state->result->oplock_type == LEASE_OPLOCK)) {
+       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;
 
@@ -1380,7 +1430,8 @@ 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, state->ev);
+                       tevent_req_post(req, state->ev);
+                       return;
                }
 
                status = smb2_create_blob_add(
@@ -1389,48 +1440,37 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                        data_blob_const(buf, lease_len));
                if (!NT_STATUS_IS_OK(status)) {
                        tevent_req_nterror(req, status);
-                       return tevent_req_post(req, state->ev);
+                       tevent_req_post(req, state->ev);
+                       return;
                }
        }
 
-       smbd_smb2_create_finish(req,
-                               smb2req,
-                               smb1req,
-                               state->result,
-                               state->replay_operation,
-                               state->in_oplock_level,
-                               state->in_create_disposition,
-                               info);
-       return req;
+       return;
 }
 
-static void smbd_smb2_create_finish(struct tevent_req *req,
-                                   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 tevent_req *req)
 {
        struct smbd_smb2_create_state *state = tevent_req_data(
                req, struct smbd_smb2_create_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,
@@ -1719,7 +1759,7 @@ bool schedule_deferred_open_message_smb2(
                (unsigned long long)mid ));
 
        tevent_schedule_immediate(state->im,
-                       smb2req->sconn->ev_ctx,
+                       smb2req->ev_ctx,
                        smbd_smb2_create_request_dispatch_immediate,
                        smb2req);
 
@@ -1751,7 +1791,7 @@ static bool smbd_smb2_create_cancel(struct tevent_req *req)
 
        remove_deferred_open_message_smb2_internal(smb2req, mid);
 
-       tevent_req_defer_callback(req, smb2req->sconn->ev_ctx);
+       tevent_req_defer_callback(req, smb2req->ev_ctx);
        tevent_req_nterror(req, NT_STATUS_CANCELLED);
        return true;
 }