[PATCH] Factor out smbd_smb2_create_file from smbd_smb2_create_send
Jeremy Allison
jra at samba.org
Tue Jul 18 21:07:12 UTC 2017
On Sat, Jul 15, 2017 at 10:07:02PM +0200, Ralph Böhme wrote:
> Hi!
>
> From the attic.
>
> Please review&push if ok. Just passed a private autobuild.
Nice cleanup Ralph, thanks !
Reviewed-by: Jeremy Allison <jra at samba.org>
> 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