1a90cf9f2SGordon Ross /*
2a90cf9f2SGordon Ross  * This file and its contents are supplied under the terms of the
3a90cf9f2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4a90cf9f2SGordon Ross  * You may only use this file in accordance with the terms of version
5a90cf9f2SGordon Ross  * 1.0 of the CDDL.
6a90cf9f2SGordon Ross  *
7a90cf9f2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8a90cf9f2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9a90cf9f2SGordon Ross  * http://www.illumos.org/license/CDDL.
10a90cf9f2SGordon Ross  */
11a90cf9f2SGordon Ross 
12a90cf9f2SGordon Ross /*
138d94f651SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
14*19fa1385SGordon Ross  * Copyright 2022-2024 RackTop Systems, Inc.
15a90cf9f2SGordon Ross  */
16a90cf9f2SGordon Ross 
17a90cf9f2SGordon Ross /*
18a90cf9f2SGordon Ross  * Dispatch function for SMB2_CREATE
19a90cf9f2SGordon Ross  * [MS-SMB2] 2.2.13
20a90cf9f2SGordon Ross  */
21a90cf9f2SGordon Ross 
22a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
23a90cf9f2SGordon Ross #include <smbsrv/smb_fsops.h>
24a90cf9f2SGordon Ross 
25811599a4SMatt Barden #define	DH_PERSISTENT	SMB2_DHANDLE_FLAG_PERSISTENT
26811599a4SMatt Barden 
2794047d49SGordon Ross /*
2894047d49SGordon Ross  * Compile-time check that the SMB2_LEASE_... definitions
2994047d49SGordon Ross  * match the (internal) equivalents from ntifs.h
3094047d49SGordon Ross  */
3194047d49SGordon Ross #if SMB2_LEASE_NONE != OPLOCK_LEVEL_NONE
3294047d49SGordon Ross #error "SMB2_LEASE_NONE"
3394047d49SGordon Ross #endif
3494047d49SGordon Ross #if SMB2_LEASE_READ_CACHING != OPLOCK_LEVEL_CACHE_READ
3594047d49SGordon Ross #error "SMB2_LEASE_READ_CACHING"
3694047d49SGordon Ross #endif
3794047d49SGordon Ross #if SMB2_LEASE_HANDLE_CACHING != OPLOCK_LEVEL_CACHE_HANDLE
3894047d49SGordon Ross #error "SMB2_LEASE_HANDLE_CACHING"
3994047d49SGordon Ross #endif
4094047d49SGordon Ross #if SMB2_LEASE_WRITE_CACHING != OPLOCK_LEVEL_CACHE_WRITE
4194047d49SGordon Ross #error "SMB2_LEASE_WRITE_CACHING"
4294047d49SGordon Ross #endif
4394047d49SGordon Ross 
44a90cf9f2SGordon Ross /*
45a90cf9f2SGordon Ross  * Some flags used locally to keep track of which Create Context
46a90cf9f2SGordon Ross  * names have been provided and/or requested.
47a90cf9f2SGordon Ross  */
48a90cf9f2SGordon Ross #define	CCTX_EA_BUFFER			1
49a90cf9f2SGordon Ross #define	CCTX_SD_BUFFER			2
50a90cf9f2SGordon Ross #define	CCTX_DH_REQUEST			4
51a90cf9f2SGordon Ross #define	CCTX_DH_RECONNECT		8
52a90cf9f2SGordon Ross #define	CCTX_ALLOCATION_SIZE		0x10
53a90cf9f2SGordon Ross #define	CCTX_QUERY_MAX_ACCESS		0x20
54a90cf9f2SGordon Ross #define	CCTX_TIMEWARP_TOKEN		0x40
55a90cf9f2SGordon Ross #define	CCTX_QUERY_ON_DISK_ID		0x80
56a90cf9f2SGordon Ross #define	CCTX_REQUEST_LEASE		0x100
57d082c877SGordon Ross #define	CCTX_AAPL_EXT			0x200
58811599a4SMatt Barden #define	CCTX_DH_REQUEST_V2		0x400
59811599a4SMatt Barden #define	CCTX_DH_RECONNECT_V2		0x800
60a90cf9f2SGordon Ross 
61a90cf9f2SGordon Ross typedef struct smb2_create_ctx_elem {
62a90cf9f2SGordon Ross 	uint32_t cce_len;
63a90cf9f2SGordon Ross 	mbuf_chain_t cce_mbc;
64a90cf9f2SGordon Ross } smb2_create_ctx_elem_t;
65a90cf9f2SGordon Ross 
66a90cf9f2SGordon Ross typedef struct smb2_create_ctx {
6793bc28dbSGordon Ross 	mbuf_chain_t cc_in_mbc;
68a90cf9f2SGordon Ross 	uint_t	cc_in_flags;	/* CCTX_... */
69a90cf9f2SGordon Ross 	uint_t	cc_out_flags;	/* CCTX_... */
70a90cf9f2SGordon Ross 	/* Elements we may see in the request. */
71a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_ext_attr;
72a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_sec_desc;
73a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_dh_request;
74a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_dh_reconnect;
75a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_alloc_size;
76a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_time_warp;
77a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_req_lease;
78d082c877SGordon Ross 	smb2_create_ctx_elem_t cc_in_aapl;
79811599a4SMatt Barden 	smb2_create_ctx_elem_t cc_in_dh_request_v2;
80811599a4SMatt Barden 	smb2_create_ctx_elem_t cc_in_dh_reconnect_v2;
81a8661d6dSAndrew Stormont 	smb2_create_ctx_elem_t cc_in_max_access;
82a90cf9f2SGordon Ross 	/* Elements we my place in the response */
83a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_out_max_access;
84a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_out_file_id;
85d082c877SGordon Ross 	smb2_create_ctx_elem_t cc_out_aapl;
8694047d49SGordon Ross 	smb2_create_ctx_elem_t cc_out_req_lease;
87811599a4SMatt Barden 	smb2_create_ctx_elem_t cc_out_dh_request;
88811599a4SMatt Barden 	smb2_create_ctx_elem_t cc_out_dh_request_v2;
89a90cf9f2SGordon Ross } smb2_create_ctx_t;
90a90cf9f2SGordon Ross 
91a90cf9f2SGordon Ross static uint32_t smb2_decode_create_ctx(
9293bc28dbSGordon Ross 	smb_request_t *, smb2_create_ctx_t *);
93a90cf9f2SGordon Ross static uint32_t smb2_encode_create_ctx(
9493bc28dbSGordon Ross 	smb_request_t *, smb2_create_ctx_t *);
95a90cf9f2SGordon Ross static int smb2_encode_create_ctx_elem(
96a90cf9f2SGordon Ross 	mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
97a90cf9f2SGordon Ross static void smb2_free_create_ctx(smb2_create_ctx_t *);
98a90cf9f2SGordon Ross 
99811599a4SMatt Barden int smb2_enable_dh = 1;
100811599a4SMatt Barden 
101a90cf9f2SGordon Ross smb_sdrc_t
smb2_create(smb_request_t * sr)102a90cf9f2SGordon Ross smb2_create(smb_request_t *sr)
103a90cf9f2SGordon Ross {
104a90cf9f2SGordon Ross 	smb_attr_t *attr;
105a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce;
106a90cf9f2SGordon Ross 	smb2_create_ctx_t cctx;
107a90cf9f2SGordon Ross 	smb_arg_open_t *op = &sr->arg.open;
108a90cf9f2SGordon Ross 	smb_ofile_t *of = NULL;
109a90cf9f2SGordon Ross 	uint16_t StructSize;
110a90cf9f2SGordon Ross 	uint8_t SecurityFlags;
111a90cf9f2SGordon Ross 	uint32_t ImpersonationLevel;
112a90cf9f2SGordon Ross 	uint64_t SmbCreateFlags;
113a90cf9f2SGordon Ross 	uint64_t Reserved4;
114a90cf9f2SGordon Ross 	uint16_t NameOffset;
115a90cf9f2SGordon Ross 	uint16_t NameLength;
116a90cf9f2SGordon Ross 	uint32_t CreateCtxOffset;
117a90cf9f2SGordon Ross 	uint32_t CreateCtxLength;
118811599a4SMatt Barden 	smb2fid_t smb2fid = { 0, 0 };
119a90cf9f2SGordon Ross 	uint32_t status;
120811599a4SMatt Barden 	int dh_flags;
121a90cf9f2SGordon Ross 	int skip;
122a90cf9f2SGordon Ross 	int rc = 0;
123a90cf9f2SGordon Ross 
124a90cf9f2SGordon Ross 	bzero(&cctx, sizeof (cctx));
12593bc28dbSGordon Ross 	op->create_ctx = &cctx;	/* for debugging */
126a90cf9f2SGordon Ross 
127a90cf9f2SGordon Ross 	/*
128a90cf9f2SGordon Ross 	 * Paranoia.  This will set sr->fid_ofile, so
129a90cf9f2SGordon Ross 	 * if we already have one, release it now.
130a90cf9f2SGordon Ross 	 */
131a90cf9f2SGordon Ross 	if (sr->fid_ofile != NULL) {
132a90cf9f2SGordon Ross 		smb_ofile_release(sr->fid_ofile);
133a90cf9f2SGordon Ross 		sr->fid_ofile = NULL;
134a90cf9f2SGordon Ross 	}
135a90cf9f2SGordon Ross 
136a90cf9f2SGordon Ross 	/*
13793bc28dbSGordon Ross 	 * Decode the SMB2 Create request
13893bc28dbSGordon Ross 	 *
13993bc28dbSGordon Ross 	 * Most decode errors return SDRC_ERROR, but
14093bc28dbSGordon Ross 	 * for some we give a more specific error.
14193bc28dbSGordon Ross 	 *
14293bc28dbSGordon Ross 	 * In the "decode section" (starts here) any
14393bc28dbSGordon Ross 	 * errors should either return SDRC_ERROR, or
14493bc28dbSGordon Ross 	 * if any cleanup is needed, goto errout.
145a90cf9f2SGordon Ross 	 */
146a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(
147a90cf9f2SGordon Ross 	    &sr->smb_data, "wbblqqlllllwwll",
148a90cf9f2SGordon Ross 	    &StructSize,		/* w */
149a90cf9f2SGordon Ross 	    &SecurityFlags,		/* b */
15093bc28dbSGordon Ross 	    &op->op_oplock_level,	/* b */
151a90cf9f2SGordon Ross 	    &ImpersonationLevel,	/* l */
152a90cf9f2SGordon Ross 	    &SmbCreateFlags,		/* q */
153a90cf9f2SGordon Ross 	    &Reserved4,			/* q */
154a90cf9f2SGordon Ross 	    &op->desired_access,	/* l */
155a90cf9f2SGordon Ross 	    &op->dattr,			/* l */
156a90cf9f2SGordon Ross 	    &op->share_access,		/* l */
157a90cf9f2SGordon Ross 	    &op->create_disposition,	/* l */
158a90cf9f2SGordon Ross 	    &op->create_options,	/* l */
159a90cf9f2SGordon Ross 	    &NameOffset,		/* w */
160a90cf9f2SGordon Ross 	    &NameLength,		/* w */
161a90cf9f2SGordon Ross 	    &CreateCtxOffset,		/* l */
162a90cf9f2SGordon Ross 	    &CreateCtxLength);		/* l */
163a90cf9f2SGordon Ross 	if (rc != 0 || StructSize != 57)
164a90cf9f2SGordon Ross 		return (SDRC_ERROR);
165a90cf9f2SGordon Ross 
166a90cf9f2SGordon Ross 	/*
167a90cf9f2SGordon Ross 	 * We're normally positioned at the path name now,
168a90cf9f2SGordon Ross 	 * but there could be some padding before it.
169a90cf9f2SGordon Ross 	 */
170a90cf9f2SGordon Ross 	skip = (NameOffset + sr->smb2_cmd_hdr) -
171a90cf9f2SGordon Ross 	    sr->smb_data.chain_offset;
17293bc28dbSGordon Ross 	if (skip < 0)
17393bc28dbSGordon Ross 		return (SDRC_ERROR);
174a90cf9f2SGordon Ross 	if (skip > 0)
175a90cf9f2SGordon Ross 		(void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
176a90cf9f2SGordon Ross 
177a90cf9f2SGordon Ross 	/*
178a90cf9f2SGordon Ross 	 * Get the path name
17993bc28dbSGordon Ross 	 *
18093bc28dbSGordon Ross 	 * Name too long is not technically a decode error,
18193bc28dbSGordon Ross 	 * but it's very rare, so we'll just skip the
18293bc28dbSGordon Ross 	 * dtrace probes for this error case.
183a90cf9f2SGordon Ross 	 */
184a90cf9f2SGordon Ross 	if (NameLength >= SMB_MAXPATHLEN) {
185a90cf9f2SGordon Ross 		status = NT_STATUS_OBJECT_PATH_INVALID;
186a90cf9f2SGordon Ross 		goto errout;
187a90cf9f2SGordon Ross 	}
188a90cf9f2SGordon Ross 	if (NameLength == 0) {
189a8661d6dSAndrew Stormont 		op->fqi.fq_path.pn_path = "";
190a90cf9f2SGordon Ross 	} else {
191a90cf9f2SGordon Ross 		rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
192a90cf9f2SGordon Ross 		    NameLength, &op->fqi.fq_path.pn_path);
193a90cf9f2SGordon Ross 		if (rc) {
194a90cf9f2SGordon Ross 			status = NT_STATUS_OBJECT_PATH_INVALID;
195a90cf9f2SGordon Ross 			goto errout;
196a90cf9f2SGordon Ross 		}
197a8661d6dSAndrew Stormont 		if (op->fqi.fq_path.pn_path[0] == '\\') {
198a8661d6dSAndrew Stormont 			status = NT_STATUS_INVALID_PARAMETER;
199a8661d6dSAndrew Stormont 			goto errout;
200a8661d6dSAndrew Stormont 		}
201a90cf9f2SGordon Ross 	}
202a90cf9f2SGordon Ross 	op->fqi.fq_dnode = sr->tid_tree->t_snode;
203a90cf9f2SGordon Ross 
20493bc28dbSGordon Ross 	/*
20593bc28dbSGordon Ross 	 * If there is a "Create Context" payload, decode it.
20693bc28dbSGordon Ross 	 * This may carry things like a security descriptor,
20793bc28dbSGordon Ross 	 * extended attributes, etc. to be used in create.
20893bc28dbSGordon Ross 	 *
20993bc28dbSGordon Ross 	 * The create ctx buffer must start after the headers
21093bc28dbSGordon Ross 	 * and file name, and must be 8-byte aligned.
21193bc28dbSGordon Ross 	 */
21293bc28dbSGordon Ross 	if (CreateCtxLength != 0) {
21393bc28dbSGordon Ross 		if ((CreateCtxOffset & 7) != 0 ||
21493bc28dbSGordon Ross 		    (CreateCtxOffset + sr->smb2_cmd_hdr) <
21593bc28dbSGordon Ross 		    sr->smb_data.chain_offset) {
21693bc28dbSGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
21793bc28dbSGordon Ross 			goto errout;
21893bc28dbSGordon Ross 		}
21993bc28dbSGordon Ross 
22093bc28dbSGordon Ross 		rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data,
22193bc28dbSGordon Ross 		    sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
22293bc28dbSGordon Ross 		if (rc) {
22393bc28dbSGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
22493bc28dbSGordon Ross 			goto errout;
22593bc28dbSGordon Ross 		}
22693bc28dbSGordon Ross 		status = smb2_decode_create_ctx(sr, &cctx);
22793bc28dbSGordon Ross 		if (status)
22893bc28dbSGordon Ross 			goto errout;
22993bc28dbSGordon Ross 	}
23093bc28dbSGordon Ross 
23193bc28dbSGordon Ross 	/*
23293bc28dbSGordon Ross 	 * Everything is decoded into some internal form, so
23393bc28dbSGordon Ross 	 * in this probe one can look at sr->arg.open etc.
23493bc28dbSGordon Ross 	 *
23593bc28dbSGordon Ross 	 * This marks the end of the "decode" section and the
23693bc28dbSGordon Ross 	 * beginning of the "body" section.  Any errors in
23793bc28dbSGordon Ross 	 * this section should use: goto cmd_done (which is
23893bc28dbSGordon Ross 	 * just before the dtrace "done" probe).
23993bc28dbSGordon Ross 	 */
24093bc28dbSGordon Ross 	DTRACE_SMB2_START(op__Create, smb_request_t *, sr); /* arg.open */
24193bc28dbSGordon Ross 
24293bc28dbSGordon Ross 	/*
24393bc28dbSGordon Ross 	 * Process the incoming create contexts (already decoded),
24493bc28dbSGordon Ross 	 * that need action before the open, starting with the
24593bc28dbSGordon Ross 	 * Durable Handle ones, which may override others.
24693bc28dbSGordon Ross 	 */
24793bc28dbSGordon Ross 
248811599a4SMatt Barden 	/*
249811599a4SMatt Barden 	 * Only disk trees get durable handles.
250811599a4SMatt Barden 	 */
251811599a4SMatt Barden 	if (smb2_enable_dh == 0 ||
252811599a4SMatt Barden 	    (sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
253811599a4SMatt Barden 		cctx.cc_in_flags &=
254811599a4SMatt Barden 		    ~(CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
255811599a4SMatt Barden 		    CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
256811599a4SMatt Barden 	}
257811599a4SMatt Barden 
258811599a4SMatt Barden 	/*
259811599a4SMatt Barden 	 * DH v2 is only valid in SMB3.0 and later.
260811599a4SMatt Barden 	 * If seen in earlier dialects, ignore.
261811599a4SMatt Barden 	 */
262811599a4SMatt Barden 	if (sr->session->dialect < SMB_VERS_3_0) {
263811599a4SMatt Barden 		cctx.cc_in_flags &=
264811599a4SMatt Barden 		    ~(CCTX_DH_REQUEST_V2|CCTX_DH_RECONNECT_V2);
265811599a4SMatt Barden 	}
266811599a4SMatt Barden 
267811599a4SMatt Barden 	/*
268811599a4SMatt Barden 	 * It is an error to specify more than one Durable Handle
269811599a4SMatt Barden 	 * operation in a single create, except when only the v1
270811599a4SMatt Barden 	 * REQUEST and RECONNECT operations are specified. In that
271811599a4SMatt Barden 	 * case, the v1 REQUEST is ignored.
272811599a4SMatt Barden 	 */
273811599a4SMatt Barden 	dh_flags = cctx.cc_in_flags &
274811599a4SMatt Barden 	    (CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
275811599a4SMatt Barden 	    CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
276811599a4SMatt Barden 	if ((dh_flags & (dh_flags - 1)) != 0 &&
277811599a4SMatt Barden 	    dh_flags != (CCTX_DH_REQUEST|CCTX_DH_RECONNECT)) {
278811599a4SMatt Barden 		status = NT_STATUS_INVALID_PARAMETER;
279811599a4SMatt Barden 		goto cmd_done;
280811599a4SMatt Barden 	}
281811599a4SMatt Barden 
282811599a4SMatt Barden 	/*
283811599a4SMatt Barden 	 * Reconnect is special in MANY ways, including the
284811599a4SMatt Barden 	 * somewhat surprising (specified) behavior that
285811599a4SMatt Barden 	 * most other creat parameters are ignored, and
286811599a4SMatt Barden 	 * many create context types are ignored too.
287811599a4SMatt Barden 	 */
288811599a4SMatt Barden 	op->dh_vers = SMB2_NOT_DURABLE;
289811599a4SMatt Barden 	if ((cctx.cc_in_flags &
290811599a4SMatt Barden 	    (CCTX_DH_RECONNECT|CCTX_DH_RECONNECT_V2)) != 0) {
291811599a4SMatt Barden 
292811599a4SMatt Barden 		if ((cctx.cc_in_flags & CCTX_DH_RECONNECT_V2) != 0)
293811599a4SMatt Barden 			op->dh_vers = SMB2_DURABLE_V2;
294811599a4SMatt Barden 		else
295811599a4SMatt Barden 			op->dh_vers = SMB2_DURABLE_V1;
296811599a4SMatt Barden 
297811599a4SMatt Barden 		/* Ignore these create contexts. */
298811599a4SMatt Barden 		cctx.cc_in_flags &=
299811599a4SMatt Barden 		    ~(CCTX_DH_REQUEST |
300811599a4SMatt Barden 		    CCTX_DH_REQUEST_V2 |
301811599a4SMatt Barden 		    CCTX_EA_BUFFER |
302811599a4SMatt Barden 		    CCTX_SD_BUFFER |
303811599a4SMatt Barden 		    CCTX_ALLOCATION_SIZE |
304811599a4SMatt Barden 		    CCTX_TIMEWARP_TOKEN |
305811599a4SMatt Barden 		    CCTX_QUERY_ON_DISK_ID);
306811599a4SMatt Barden 
30794047d49SGordon Ross 		/*
30894047d49SGordon Ross 		 * Reconnect check needs to know if a lease was requested.
30994047d49SGordon Ross 		 * The requested oplock level is ignored in reconnect, so
31094047d49SGordon Ross 		 * using op_oplock_level to convey this info.
31194047d49SGordon Ross 		 */
31294047d49SGordon Ross 		if (cctx.cc_in_flags & CCTX_REQUEST_LEASE)
31394047d49SGordon Ross 			op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
31494047d49SGordon Ross 		else
31594047d49SGordon Ross 			op->op_oplock_level = 0;
31694047d49SGordon Ross 
317811599a4SMatt Barden 		status = smb2_dh_reconnect(sr);
318811599a4SMatt Barden 		if (status != NT_STATUS_SUCCESS)
319811599a4SMatt Barden 			goto cmd_done;
320811599a4SMatt Barden 
321811599a4SMatt Barden 		/*
32294047d49SGordon Ross 		 * Skip most open execution during reconnect,
32394047d49SGordon Ross 		 * but need (reclaimed) oplock state in *op.
324811599a4SMatt Barden 		 */
325811599a4SMatt Barden 		of = sr->fid_ofile;
32694047d49SGordon Ross 		smb2_oplock_reconnect(sr);
327811599a4SMatt Barden 		goto reconnect_done;
328811599a4SMatt Barden 	}
329811599a4SMatt Barden 
330811599a4SMatt Barden 	/*
331811599a4SMatt Barden 	 * Real create (of a new handle, not reconnect)
332811599a4SMatt Barden 	 */
333811599a4SMatt Barden 
33493bc28dbSGordon Ross 	/*
33593bc28dbSGordon Ross 	 * Validate the requested oplock level.
33694047d49SGordon Ross 	 * Conversion to internal form is in smb2_oplock_acquire()
33793bc28dbSGordon Ross 	 */
33893bc28dbSGordon Ross 	switch (op->op_oplock_level) {
33994047d49SGordon Ross 	case SMB2_OPLOCK_LEVEL_NONE:		/* OPLOCK_LEVEL_NONE */
34094047d49SGordon Ross 	case SMB2_OPLOCK_LEVEL_II:		/* OPLOCK_LEVEL_TWO */
34194047d49SGordon Ross 	case SMB2_OPLOCK_LEVEL_EXCLUSIVE:	/* OPLOCK_LEVEL_ONE */
34294047d49SGordon Ross 	case SMB2_OPLOCK_LEVEL_BATCH:		/* OPLOCK_LEVEL_BATCH */
34394047d49SGordon Ross 		/*
34494047d49SGordon Ross 		 * Ignore lease create context (if any)
34594047d49SGordon Ross 		 */
34694047d49SGordon Ross 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
347a90cf9f2SGordon Ross 		break;
34894047d49SGordon Ross 
34994047d49SGordon Ross 	case SMB2_OPLOCK_LEVEL_LEASE:		/* OPLOCK_LEVEL_GRANULAR */
35094047d49SGordon Ross 		/*
35194047d49SGordon Ross 		 * Require a lease create context.
35294047d49SGordon Ross 		 */
35394047d49SGordon Ross 		if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) == 0) {
35494047d49SGordon Ross 			cmn_err(CE_NOTE, "smb2:create, oplock=ff and no lease");
35594047d49SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
35694047d49SGordon Ross 			goto cmd_done;
35794047d49SGordon Ross 		}
35894047d49SGordon Ross 
35994047d49SGordon Ross 		/*
36094047d49SGordon Ross 		 * Validate lease request state
36194047d49SGordon Ross 		 * Only a few valid combinations.
36294047d49SGordon Ross 		 */
36394047d49SGordon Ross 		switch (op->lease_state) {
36494047d49SGordon Ross 		case SMB2_LEASE_NONE:
36594047d49SGordon Ross 		case SMB2_LEASE_READ_CACHING:
36694047d49SGordon Ross 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_HANDLE_CACHING:
36794047d49SGordon Ross 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING:
36894047d49SGordon Ross 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING |
36994047d49SGordon Ross 		    SMB2_LEASE_HANDLE_CACHING:
37094047d49SGordon Ross 			break;
37194047d49SGordon Ross 
37294047d49SGordon Ross 		default:
37394047d49SGordon Ross 			/*
37494047d49SGordon Ross 			 * Invalid lease state flags
37594047d49SGordon Ross 			 * Just force to "none".
37694047d49SGordon Ross 			 */
37794047d49SGordon Ross 			op->lease_state = SMB2_LEASE_NONE;
37894047d49SGordon Ross 			break;
37994047d49SGordon Ross 		}
380a90cf9f2SGordon Ross 		break;
38194047d49SGordon Ross 
38293bc28dbSGordon Ross 	default:
38393bc28dbSGordon Ross 		/* Unknown SMB2 oplock level. */
384a90cf9f2SGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
38593bc28dbSGordon Ross 		goto cmd_done;
386a90cf9f2SGordon Ross 	}
387a90cf9f2SGordon Ross 
388a90cf9f2SGordon Ross 	/*
38993bc28dbSGordon Ross 	 * Only disk trees get oplocks or leases.
39093bc28dbSGordon Ross 	 */
39193bc28dbSGordon Ross 	if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
39293bc28dbSGordon Ross 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
39393bc28dbSGordon Ross 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
39493bc28dbSGordon Ross 	}
39593bc28dbSGordon Ross 
3968d94f651SGordon Ross 	if ((sr->tid_tree->t_flags & SMB_TREE_CA) == 0)
3978d94f651SGordon Ross 		op->dh_v2_flags &= ~DH_PERSISTENT;
3988d94f651SGordon Ross 
399811599a4SMatt Barden 	if ((cctx.cc_in_flags &
400811599a4SMatt Barden 	    (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0) {
401811599a4SMatt Barden 		if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0)
402811599a4SMatt Barden 			op->dh_vers = SMB2_DURABLE_V2;
403811599a4SMatt Barden 		else
404811599a4SMatt Barden 			op->dh_vers = SMB2_DURABLE_V1;
405811599a4SMatt Barden 	}
406811599a4SMatt Barden 
40793bc28dbSGordon Ross 	if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
40893bc28dbSGordon Ross 		status = NT_STATUS_EAS_NOT_SUPPORTED;
40993bc28dbSGordon Ross 		goto cmd_done;
41093bc28dbSGordon Ross 	}
41193bc28dbSGordon Ross 
41293bc28dbSGordon Ross 	/*
41393bc28dbSGordon Ross 	 * ImpersonationLevel (spec. says validate + ignore)
414a8661d6dSAndrew Stormont 	 */
415a8661d6dSAndrew Stormont 	switch (ImpersonationLevel) {
416a8661d6dSAndrew Stormont 	case SMB2_IMPERSONATION_ANONYMOUS:
417a8661d6dSAndrew Stormont 	case SMB2_IMPERSONATION_IDENTIFICATION:
418a8661d6dSAndrew Stormont 	case SMB2_IMPERSONATION_IMPERSONATION:
419a8661d6dSAndrew Stormont 	case SMB2_IMPERSONATION_DELEGATE:
420a8661d6dSAndrew Stormont 		break;
421a8661d6dSAndrew Stormont 	default:
422a8661d6dSAndrew Stormont 		status = NT_STATUS_BAD_IMPERSONATION_LEVEL;
423a8661d6dSAndrew Stormont 		goto cmd_done;
424a8661d6dSAndrew Stormont 	}
425a8661d6dSAndrew Stormont 
426a8661d6dSAndrew Stormont 	/*
427a90cf9f2SGordon Ross 	 * SmbCreateFlags (spec. says ignore)
428a90cf9f2SGordon Ross 	 */
429a90cf9f2SGordon Ross 
430a90cf9f2SGordon Ross 	if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
431a90cf9f2SGordon Ross 	    !(op->desired_access & DELETE)) {
432a90cf9f2SGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
43393bc28dbSGordon Ross 		goto cmd_done;
434a90cf9f2SGordon Ross 	}
435a90cf9f2SGordon Ross 
436a90cf9f2SGordon Ross 	if (op->dattr & FILE_FLAG_WRITE_THROUGH)
437a90cf9f2SGordon Ross 		op->create_options |= FILE_WRITE_THROUGH;
438a90cf9f2SGordon Ross 	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
439a90cf9f2SGordon Ross 		op->create_options |= FILE_DELETE_ON_CLOSE;
440a90cf9f2SGordon Ross 	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
441a90cf9f2SGordon Ross 		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
442a90cf9f2SGordon Ross 	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
443a90cf9f2SGordon Ross 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
44493bc28dbSGordon Ross 	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
44593bc28dbSGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
44693bc28dbSGordon Ross 		goto cmd_done;
447a90cf9f2SGordon Ross 	}
448a90cf9f2SGordon Ross 
449a90cf9f2SGordon Ross 	/*
450a90cf9f2SGordon Ross 	 * The real open call.   Note: this gets attributes into
451a90cf9f2SGordon Ross 	 * op->fqi.fq_fattr (SMB_AT_ALL).  We need those below.
45293bc28dbSGordon Ross 	 * When of != NULL, goto errout closes it.
453a90cf9f2SGordon Ross 	 */
454a90cf9f2SGordon Ross 	status = smb_common_open(sr);
455a90cf9f2SGordon Ross 	if (status != NT_STATUS_SUCCESS)
45693bc28dbSGordon Ross 		goto cmd_done;
45793bc28dbSGordon Ross 	of = sr->fid_ofile;
458a90cf9f2SGordon Ross 
459811599a4SMatt Barden 	/*
460811599a4SMatt Barden 	 * Set the "persistent" part of the file ID
461811599a4SMatt Barden 	 * (only for DISK shares).  Need this even for
462811599a4SMatt Barden 	 * non-durable handles in case we get the ioctl
463811599a4SMatt Barden 	 * to set "resiliency" on this handle.
464811599a4SMatt Barden 	 */
4658d94f651SGordon Ross 	if (of->f_ftype == SMB_FTYPE_DISK) {
4668d94f651SGordon Ross 		if ((op->dh_v2_flags & DH_PERSISTENT) != 0)
4678d94f651SGordon Ross 			smb_ofile_set_persistid_ph(of);
4688d94f651SGordon Ross 		else
4698d94f651SGordon Ross 			smb_ofile_set_persistid_dh(of);
4708d94f651SGordon Ross 	}
47194047d49SGordon Ross 
472*19fa1385SGordon Ross 	/*
473*19fa1385SGordon Ross 	 * Ignore lease or oplock requests for anything other than
474*19fa1385SGordon Ross 	 * plain files. The share type was checked above, but the
475*19fa1385SGordon Ross 	 * node pointer of->f_node is only valid for "disk" files.
476*19fa1385SGordon Ross 	 */
477*19fa1385SGordon Ross 	if (of->f_ftype != SMB_FTYPE_DISK ||
478*19fa1385SGordon Ross 	    !smb_node_is_file(of->f_node)) {
479*19fa1385SGordon Ross 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
480*19fa1385SGordon Ross 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
481*19fa1385SGordon Ross 	}
482*19fa1385SGordon Ross 
48394047d49SGordon Ross 	/*
48494047d49SGordon Ross 	 * [MS-SMB2] 3.3.5.9.8
48594047d49SGordon Ross 	 * Handling the SMB2_CREATE_REQUEST_LEASE Create Context
48694047d49SGordon Ross 	 */
48794047d49SGordon Ross 	if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0) {
4888d94f651SGordon Ross 		status = smb2_lease_create(sr, sr->session->clnt_uuid);
48994047d49SGordon Ross 		if (status != NT_STATUS_SUCCESS) {
49094047d49SGordon Ross 			if (op->action_taken == SMB_OACT_CREATED) {
49194047d49SGordon Ross 				smb_ofile_set_delete_on_close(sr, of);
49294047d49SGordon Ross 			}
49394047d49SGordon Ross 			goto cmd_done;
49494047d49SGordon Ross 		}
49594047d49SGordon Ross 	}
49694047d49SGordon Ross 	if (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
49794047d49SGordon Ross 		smb2_lease_acquire(sr);
49894047d49SGordon Ross 	} else if (op->op_oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
49994047d49SGordon Ross 		smb2_oplock_acquire(sr);
500811599a4SMatt Barden 	}
501811599a4SMatt Barden 
502811599a4SMatt Barden 	/*
503*19fa1385SGordon Ross 	 * If requested and allowed, make this a durable open;
504*19fa1385SGordon Ross 	 * see comment above smb_dh_create_allowed() for more detail.
505811599a4SMatt Barden 	 *
50694047d49SGordon Ross 	 * Otherwise, DH requests are ignored, so we set
50794047d49SGordon Ross 	 * dh_vers = not durable
508811599a4SMatt Barden 	 */
509811599a4SMatt Barden 	if ((cctx.cc_in_flags &
510811599a4SMatt Barden 	    (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0 &&
511*19fa1385SGordon Ross 	    smb_dh_create_allowed(sr, of)) {
512811599a4SMatt Barden 		/*
513811599a4SMatt Barden 		 * OK, make this handle "durable"
514811599a4SMatt Barden 		 */
515811599a4SMatt Barden 		if (op->dh_vers == SMB2_DURABLE_V2) {
516811599a4SMatt Barden 			(void) memcpy(of->dh_create_guid,
517811599a4SMatt Barden 			    op->create_guid, UUID_LEN);
518811599a4SMatt Barden 
5198d94f651SGordon Ross 			if ((op->dh_v2_flags & DH_PERSISTENT) != 0) {
5208d94f651SGordon Ross 				if (smb2_dh_make_persistent(sr, of) == 0) {
5218d94f651SGordon Ross 					of->dh_persist = B_TRUE;
5228d94f651SGordon Ross 				} else {
5238d94f651SGordon Ross 					op->dh_v2_flags = 0;
5248d94f651SGordon Ross 				}
5258d94f651SGordon Ross 			}
526811599a4SMatt Barden 		}
527811599a4SMatt Barden 		if (op->dh_vers != SMB2_NOT_DURABLE) {
528811599a4SMatt Barden 			uint32_t msto;
529811599a4SMatt Barden 
530811599a4SMatt Barden 			of->dh_vers = op->dh_vers;
531811599a4SMatt Barden 			of->dh_expire_time = 0;
532811599a4SMatt Barden 
533811599a4SMatt Barden 			/*
534811599a4SMatt Barden 			 * Client may provide timeout=0 to request
535811599a4SMatt Barden 			 * the default timeout (in mSec.)
536811599a4SMatt Barden 			 */
537811599a4SMatt Barden 			msto = op->dh_timeout;
5388d94f651SGordon Ross 			if (msto == 0) {
5398d94f651SGordon Ross 				msto = (of->dh_persist) ?
5408d94f651SGordon Ross 				    smb2_persist_timeout :
5418d94f651SGordon Ross 				    smb2_dh_def_timeout;
5428d94f651SGordon Ross 			}
543811599a4SMatt Barden 			if (msto > smb2_dh_max_timeout)
544811599a4SMatt Barden 				msto = smb2_dh_max_timeout;
545811599a4SMatt Barden 			op->dh_timeout = msto;
546811599a4SMatt Barden 			of->dh_timeout_offset = MSEC2NSEC(msto);
547811599a4SMatt Barden 		}
548811599a4SMatt Barden 	} else {
549811599a4SMatt Barden 		op->dh_vers = SMB2_NOT_DURABLE;
5508d94f651SGordon Ross 		op->dh_v2_flags = 0;
551811599a4SMatt Barden 	}
552811599a4SMatt Barden 
553a90cf9f2SGordon Ross 	/*
554a90cf9f2SGordon Ross 	 * NB: after the above smb_common_open() success,
555a90cf9f2SGordon Ross 	 * we have a handle allocated (sr->fid_ofile).
556a90cf9f2SGordon Ross 	 * If we don't return success, we must close it.
557a90cf9f2SGordon Ross 	 *
558a90cf9f2SGordon Ross 	 * Using sr->smb_fid as the file handle for now,
559a90cf9f2SGordon Ross 	 * though it could later be something larger,
560a90cf9f2SGordon Ross 	 * (16 bytes) similar to an NFSv4 open handle.
561a90cf9f2SGordon Ross 	 */
562811599a4SMatt Barden reconnect_done:
563811599a4SMatt Barden 	smb2fid.persistent = of->f_persistid;
564a90cf9f2SGordon Ross 	smb2fid.temporal = sr->smb_fid;
565a90cf9f2SGordon Ross 
566a90cf9f2SGordon Ross 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
567a90cf9f2SGordon Ross 	case STYPE_DISKTREE:
568a90cf9f2SGordon Ross 	case STYPE_PRINTQ:
569a90cf9f2SGordon Ross 		if (op->create_options & FILE_DELETE_ON_CLOSE)
57094047d49SGordon Ross 			smb_ofile_set_delete_on_close(sr, of);
571a90cf9f2SGordon Ross 		break;
572a90cf9f2SGordon Ross 	}
573a90cf9f2SGordon Ross 
574a90cf9f2SGordon Ross 	/*
57593bc28dbSGordon Ross 	 * Process any outgoing create contexts that need work
57693bc28dbSGordon Ross 	 * after the open succeeds.  Encode happens later.
577a90cf9f2SGordon Ross 	 */
578a90cf9f2SGordon Ross 	if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
57993bc28dbSGordon Ross 		op->maximum_access = 0;
580a90cf9f2SGordon Ross 		if (of->f_node != NULL) {
58193bc28dbSGordon Ross 			smb_fsop_eaccess(sr, of->f_cr, of->f_node,
58293bc28dbSGordon Ross 			    &op->maximum_access);
583a90cf9f2SGordon Ross 		}
58493bc28dbSGordon Ross 		op->maximum_access |= of->f_granted_access;
585a90cf9f2SGordon Ross 		cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
586a90cf9f2SGordon Ross 	}
58793bc28dbSGordon Ross 
588a90cf9f2SGordon Ross 	if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
589a90cf9f2SGordon Ross 	    of->f_node != NULL) {
59093bc28dbSGordon Ross 		op->op_fsid = SMB_NODE_FSID(of->f_node);
591a90cf9f2SGordon Ross 		cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
592a90cf9f2SGordon Ross 	}
59393bc28dbSGordon Ross 
594d082c877SGordon Ross 	if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) {
595d082c877SGordon Ross 		cce = &cctx.cc_out_aapl;
596d082c877SGordon Ross 		/*
597d082c877SGordon Ross 		 * smb2_aapl_crctx has a variable response depending on
598d082c877SGordon Ross 		 * what the incoming context looks like, so it does all
599d082c877SGordon Ross 		 * the work of building cc_out_aapl, including setting
600d082c877SGordon Ross 		 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode.
601d082c877SGordon Ross 		 * If we see errors getting this, simply omit it from
602d082c877SGordon Ross 		 * the collection of returned create contexts.
603d082c877SGordon Ross 		 */
604d082c877SGordon Ross 		status = smb2_aapl_crctx(sr,
605d082c877SGordon Ross 		    &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc);
606d082c877SGordon Ross 		if (status == 0) {
607d082c877SGordon Ross 			cce->cce_len = cce->cce_mbc.chain_offset;
608d082c877SGordon Ross 			cctx.cc_out_flags |= CCTX_AAPL_EXT;
609d082c877SGordon Ross 		}
610d082c877SGordon Ross 		status = 0;
611d082c877SGordon Ross 	}
61293bc28dbSGordon Ross 
61394047d49SGordon Ross 	/*
61494047d49SGordon Ross 	 * If a lease was requested, and we got one...
61594047d49SGordon Ross 	 */
61694047d49SGordon Ross 	if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0 &&
61794047d49SGordon Ross 	    op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE)
61894047d49SGordon Ross 		cctx.cc_out_flags |= CCTX_REQUEST_LEASE;
61994047d49SGordon Ross 
62094047d49SGordon Ross 	/*
62194047d49SGordon Ross 	 * If a durable handle was requested and we got one...
62294047d49SGordon Ross 	 */
623811599a4SMatt Barden 	if ((cctx.cc_in_flags & CCTX_DH_REQUEST) != 0 &&
624811599a4SMatt Barden 	    of->dh_vers == SMB2_DURABLE_V1) {
625811599a4SMatt Barden 		cctx.cc_out_flags |= CCTX_DH_REQUEST;
626811599a4SMatt Barden 	}
627811599a4SMatt Barden 	if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0 &&
628811599a4SMatt Barden 	    of->dh_vers == SMB2_DURABLE_V2) {
629811599a4SMatt Barden 		cctx.cc_out_flags |= CCTX_DH_REQUEST_V2;
630811599a4SMatt Barden 	}
631811599a4SMatt Barden 
63293bc28dbSGordon Ross 	/*
63393bc28dbSGordon Ross 	 * This marks the end of the "body" section and the
63493bc28dbSGordon Ross 	 * beginning of the "encode" section.  Any errors
63593bc28dbSGordon Ross 	 * encoding the response should use: goto errout
63693bc28dbSGordon Ross 	 */
63793bc28dbSGordon Ross cmd_done:
63893bc28dbSGordon Ross 	/* Want status visible in the done probe. */
63993bc28dbSGordon Ross 	sr->smb2_status = status;
64093bc28dbSGordon Ross 	DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr);
64193bc28dbSGordon Ross 	if (status != NT_STATUS_SUCCESS)
64293bc28dbSGordon Ross 		goto errout;
64393bc28dbSGordon Ross 
64493bc28dbSGordon Ross 	/*
64593bc28dbSGordon Ross 	 * Encode all the create contexts to return.
64693bc28dbSGordon Ross 	 */
647a90cf9f2SGordon Ross 	if (cctx.cc_out_flags) {
648a90cf9f2SGordon Ross 		sr->raw_data.max_bytes = smb2_max_trans;
64993bc28dbSGordon Ross 		status = smb2_encode_create_ctx(sr, &cctx);
650a90cf9f2SGordon Ross 		if (status)
651a90cf9f2SGordon Ross 			goto errout;
652a90cf9f2SGordon Ross 	}
653a90cf9f2SGordon Ross 
65493bc28dbSGordon Ross 	/*
65593bc28dbSGordon Ross 	 * Encode the SMB2 Create reply
656a90cf9f2SGordon Ross 	 */
65793bc28dbSGordon Ross 	attr = &op->fqi.fq_fattr;
658a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
659a90cf9f2SGordon Ross 	    &sr->reply,
660a90cf9f2SGordon Ross 	    "wb.lTTTTqqllqqll",
661a90cf9f2SGordon Ross 	    89,	/* StructSize */	/* w */
66294047d49SGordon Ross 	    op->op_oplock_level,	/* b */
663a90cf9f2SGordon Ross 	    op->action_taken,		/* l */
664a90cf9f2SGordon Ross 	    &attr->sa_crtime,		/* T */
665a90cf9f2SGordon Ross 	    &attr->sa_vattr.va_atime,	/* T */
666a90cf9f2SGordon Ross 	    &attr->sa_vattr.va_mtime,	/* T */
667a90cf9f2SGordon Ross 	    &attr->sa_vattr.va_ctime,	/* T */
668a90cf9f2SGordon Ross 	    attr->sa_allocsz,		/* q */
669a90cf9f2SGordon Ross 	    attr->sa_vattr.va_size,	/* q */
670a90cf9f2SGordon Ross 	    attr->sa_dosattr,		/* l */
671a90cf9f2SGordon Ross 	    0, /* reserved2 */		/* l */
672a90cf9f2SGordon Ross 	    smb2fid.persistent,		/* q */
673a90cf9f2SGordon Ross 	    smb2fid.temporal,		/* q */
674a90cf9f2SGordon Ross 	    0,  /* CreateCtxOffset	   l */
675a90cf9f2SGordon Ross 	    0); /* CreateCtxLength	   l */
676a90cf9f2SGordon Ross 	if (rc != 0) {
677a90cf9f2SGordon Ross 		status = NT_STATUS_UNSUCCESSFUL;
678a90cf9f2SGordon Ross 		goto errout;
679a90cf9f2SGordon Ross 	}
680a90cf9f2SGordon Ross 
681a90cf9f2SGordon Ross 	CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
682a90cf9f2SGordon Ross 	CreateCtxLength = MBC_LENGTH(&sr->raw_data);
683a90cf9f2SGordon Ross 	if (CreateCtxLength != 0) {
684a90cf9f2SGordon Ross 		/*
685a90cf9f2SGordon Ross 		 * Overwrite CreateCtxOffset, CreateCtxLength, pad
686a90cf9f2SGordon Ross 		 */
687a90cf9f2SGordon Ross 		sr->reply.chain_offset -= 8;
688a90cf9f2SGordon Ross 		rc = smb_mbc_encodef(
689a90cf9f2SGordon Ross 		    &sr->reply,
690a90cf9f2SGordon Ross 		    "ll#C",
691a90cf9f2SGordon Ross 		    CreateCtxOffset,	/* l */
692a90cf9f2SGordon Ross 		    CreateCtxLength,	/* l */
693a90cf9f2SGordon Ross 		    CreateCtxLength,	/* # */
694a90cf9f2SGordon Ross 		    &sr->raw_data);	/* C */
695a90cf9f2SGordon Ross 		if (rc != 0) {
696a90cf9f2SGordon Ross 			status = NT_STATUS_UNSUCCESSFUL;
697a90cf9f2SGordon Ross 			goto errout;
698a90cf9f2SGordon Ross 		}
699a90cf9f2SGordon Ross 	} else {
700a90cf9f2SGordon Ross 		(void) smb_mbc_encodef(&sr->reply, ".");
701a90cf9f2SGordon Ross 	}
702a90cf9f2SGordon Ross 
70393bc28dbSGordon Ross 	if (status != 0) {
70493bc28dbSGordon Ross 	errout:
70593bc28dbSGordon Ross 		if (of != NULL)
70693bc28dbSGordon Ross 			smb_ofile_close(of, 0);
70793bc28dbSGordon Ross 		smb2sr_put_error(sr, status);
70893bc28dbSGordon Ross 	}
70993bc28dbSGordon Ross 	if (op->sd != NULL) {
71093bc28dbSGordon Ross 		smb_sd_term(op->sd);
71193bc28dbSGordon Ross 		kmem_free(op->sd, sizeof (*op->sd));
71293bc28dbSGordon Ross 	}
713a90cf9f2SGordon Ross 	if (cctx.cc_out_flags)
714a90cf9f2SGordon Ross 		smb2_free_create_ctx(&cctx);
71593bc28dbSGordon Ross 
716a90cf9f2SGordon Ross 	return (SDRC_SUCCESS);
717a90cf9f2SGordon Ross }
718a90cf9f2SGordon Ross 
719a90cf9f2SGordon Ross /*
720a90cf9f2SGordon Ross  * Decode an SMB2 Create Context buffer into our internal form.
72193bc28dbSGordon Ross  * Avoid policy decisions about what's supported here, just decode.
722a90cf9f2SGordon Ross  */
723a90cf9f2SGordon Ross static uint32_t
smb2_decode_create_ctx(smb_request_t * sr,smb2_create_ctx_t * cc)72493bc28dbSGordon Ross smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
725a90cf9f2SGordon Ross {
72693bc28dbSGordon Ross 	smb_arg_open_t *op = &sr->arg.open;
727a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce;
72893bc28dbSGordon Ross 	mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
729a90cf9f2SGordon Ross 	mbuf_chain_t name_mbc;
730a90cf9f2SGordon Ross 	union {
731a90cf9f2SGordon Ross 		uint32_t i;
732a90cf9f2SGordon Ross 		char ch[4];
733a90cf9f2SGordon Ross 	} cc_name;
734a90cf9f2SGordon Ross 	uint32_t status;
735a90cf9f2SGordon Ross 	int32_t next_off;
736a90cf9f2SGordon Ross 	uint32_t data_len;
737a90cf9f2SGordon Ross 	uint16_t data_off;
738a90cf9f2SGordon Ross 	uint16_t name_off;
739a90cf9f2SGordon Ross 	uint16_t name_len;
740a90cf9f2SGordon Ross 	int top_offset;
741a90cf9f2SGordon Ross 	int rc;
742a90cf9f2SGordon Ross 
74393bc28dbSGordon Ross 	/*
74493bc28dbSGordon Ross 	 * Any break from the loop below before we've decoded
74593bc28dbSGordon Ross 	 * the entire create context means it was malformatted,
74693bc28dbSGordon Ross 	 * so we should return INVALID_PARAMETER.
74793bc28dbSGordon Ross 	 */
748a90cf9f2SGordon Ross 	status = NT_STATUS_INVALID_PARAMETER;
749a90cf9f2SGordon Ross 	for (;;) {
750a90cf9f2SGordon Ross 		cce = NULL;
751a90cf9f2SGordon Ross 		top_offset = in_mbc->chain_offset;
752a90cf9f2SGordon Ross 		rc = smb_mbc_decodef(
753a90cf9f2SGordon Ross 		    in_mbc,
754a90cf9f2SGordon Ross 		    "lww..wl",
755a90cf9f2SGordon Ross 		    &next_off,	/* l */
756a90cf9f2SGordon Ross 		    &name_off,	/* w */
757a90cf9f2SGordon Ross 		    &name_len,	/* w */
758a90cf9f2SGordon Ross 		    /* reserved	  .. */
759a90cf9f2SGordon Ross 		    &data_off,	/* w */
760a90cf9f2SGordon Ross 		    &data_len); /* l */
761a90cf9f2SGordon Ross 		if (rc)
762a90cf9f2SGordon Ross 			break;
763a90cf9f2SGordon Ross 
764a90cf9f2SGordon Ross 		/*
765a90cf9f2SGordon Ross 		 * The Create Context "name", per [MS-SMB] 2.2.13.2
766a90cf9f2SGordon Ross 		 * They're defined as network-order integers for our
767a90cf9f2SGordon Ross 		 * switch below.  We don't have routines to decode
768a90cf9f2SGordon Ross 		 * native order, so read as char[4] then ntohl.
769a90cf9f2SGordon Ross 		 * NB: in SMB3, some of these are 8 bytes.
770a90cf9f2SGordon Ross 		 */
771a90cf9f2SGordon Ross 		if ((top_offset + name_off) < in_mbc->chain_offset)
772a90cf9f2SGordon Ross 			break;
773a90cf9f2SGordon Ross 		rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc,
774a90cf9f2SGordon Ross 		    top_offset + name_off, name_len);
775a90cf9f2SGordon Ross 		if (rc)
776a90cf9f2SGordon Ross 			break;
777a90cf9f2SGordon Ross 		rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name);
778a90cf9f2SGordon Ross 		if (rc)
779a90cf9f2SGordon Ross 			break;
780a90cf9f2SGordon Ross 		cc_name.i = ntohl(cc_name.i);
781a90cf9f2SGordon Ross 
782a90cf9f2SGordon Ross 		switch (cc_name.i) {
783a90cf9f2SGordon Ross 		case SMB2_CREATE_EA_BUFFER:		/* ("ExtA") */
784a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_EA_BUFFER;
785a90cf9f2SGordon Ross 			cce = &cc->cc_in_ext_attr;
786a90cf9f2SGordon Ross 			break;
787a90cf9f2SGordon Ross 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
788a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_SD_BUFFER;
789a90cf9f2SGordon Ross 			cce = &cc->cc_in_sec_desc;
790a90cf9f2SGordon Ross 			break;
791a90cf9f2SGordon Ross 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
792a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_DH_REQUEST;
793a90cf9f2SGordon Ross 			cce = &cc->cc_in_dh_request;
794a90cf9f2SGordon Ross 			break;
795a90cf9f2SGordon Ross 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
796a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_DH_RECONNECT;
797a90cf9f2SGordon Ross 			cce = &cc->cc_in_dh_reconnect;
798a90cf9f2SGordon Ross 			break;
799a90cf9f2SGordon Ross 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
800a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
801a90cf9f2SGordon Ross 			cce = &cc->cc_in_alloc_size;
802a90cf9f2SGordon Ross 			break;
803a90cf9f2SGordon Ross 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
804a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
805a8661d6dSAndrew Stormont 			/* Optional input data for this CC. See below. */
806a8661d6dSAndrew Stormont 			cce = &cc->cc_in_max_access;
807a90cf9f2SGordon Ross 			break;
808a90cf9f2SGordon Ross 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
809a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
810a90cf9f2SGordon Ross 			cce = &cc->cc_in_time_warp;
811a90cf9f2SGordon Ross 			break;
812a90cf9f2SGordon Ross 		case SMB2_CREATE_QUERY_ON_DISK_ID:	/* ("QFid") */
813a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
814a90cf9f2SGordon Ross 			/* no input data for this */
815a90cf9f2SGordon Ross 			break;
816a90cf9f2SGordon Ross 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
817a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_REQUEST_LEASE;
818a90cf9f2SGordon Ross 			cce = &cc->cc_in_req_lease;
819a90cf9f2SGordon Ross 			break;
820d082c877SGordon Ross 		case SMB2_CREATE_CTX_AAPL:		/* ("AAPL") */
821d082c877SGordon Ross 			cc->cc_in_flags |= CCTX_AAPL_EXT;
822d082c877SGordon Ross 			cce = &cc->cc_in_aapl;
823d082c877SGordon Ross 			break;
824811599a4SMatt Barden 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
825811599a4SMatt Barden 			cc->cc_in_flags |= CCTX_DH_REQUEST_V2;
826811599a4SMatt Barden 			cce = &cc->cc_in_dh_request_v2;
827811599a4SMatt Barden 			break;
828811599a4SMatt Barden 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
829811599a4SMatt Barden 			cc->cc_in_flags |= CCTX_DH_RECONNECT_V2;
830811599a4SMatt Barden 			cce = &cc->cc_in_dh_reconnect_v2;
831811599a4SMatt Barden 			break;
8325501be74SGordon Ross 
8335501be74SGordon Ross 		/*
8345501be74SGordon Ross 		 * Known but not implemented context IDs.
8355501be74SGordon Ross 		 * Here just to silence the debug below.
8365501be74SGordon Ross 		 *
8375501be74SGordon Ross 		 * Note: all three of these IDs are actually longer,
8385501be74SGordon Ross 		 * but we start by decoding just the first 4 bytes.
8395501be74SGordon Ross 		 * If/when we recognize these, do another match on
8405501be74SGordon Ross 		 * the full ID after we take this switch case.
8415501be74SGordon Ross 		 */
8425501be74SGordon Ross 		case 0x45bca66a: /* SMB2_CREATE_APP_INSTANCE_ID */
8435501be74SGordon Ross 		case 0xB982D0B7: /* SMB2_CREATE_APP_INSTANCE_VERSION */
844811599a4SMatt Barden 		case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */
8455501be74SGordon Ross 			cce = NULL;
846811599a4SMatt Barden 			break;
8475501be74SGordon Ross 
848a90cf9f2SGordon Ross 		default:
849a90cf9f2SGordon Ross 			/*
850a90cf9f2SGordon Ross 			 * Unknown create context values are normal, and
851a90cf9f2SGordon Ross 			 * should be ignored.  However, in debug mode,
852a90cf9f2SGordon Ross 			 * let's log them so we know which ones we're
853a90cf9f2SGordon Ross 			 * not handling (and may want to add).
854a90cf9f2SGordon Ross 			 */
855a90cf9f2SGordon Ross #ifdef	DEBUG
856a90cf9f2SGordon Ross 			cmn_err(CE_NOTE, "unknown create context ID 0x%x",
857a90cf9f2SGordon Ross 			    cc_name.i);
858a90cf9f2SGordon Ross #endif
859a90cf9f2SGordon Ross 			cce = NULL;
860a90cf9f2SGordon Ross 			break;
861a90cf9f2SGordon Ross 		}
862a90cf9f2SGordon Ross 
86393bc28dbSGordon Ross 		if (cce == NULL || data_len == 0)
86493bc28dbSGordon Ross 			goto next_cc;
86593bc28dbSGordon Ross 
86693bc28dbSGordon Ross 		if ((data_off & 7) != 0)
86793bc28dbSGordon Ross 			break;
86893bc28dbSGordon Ross 		if ((top_offset + data_off) < in_mbc->chain_offset)
86993bc28dbSGordon Ross 			break;
87093bc28dbSGordon Ross 		rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
87193bc28dbSGordon Ross 		    top_offset + data_off, data_len);
87293bc28dbSGordon Ross 		if (rc)
87393bc28dbSGordon Ross 			break;
87493bc28dbSGordon Ross 		cce->cce_len = data_len;
87593bc28dbSGordon Ross 
87693bc28dbSGordon Ross 		/*
87793bc28dbSGordon Ross 		 * Additonal decoding for some create contexts.
87893bc28dbSGordon Ross 		 */
87993bc28dbSGordon Ross 		switch (cc_name.i) {
88093bc28dbSGordon Ross 			uint64_t nttime;
88193bc28dbSGordon Ross 
88293bc28dbSGordon Ross 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
88393bc28dbSGordon Ross 			op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
88493bc28dbSGordon Ross 			if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0)
88593bc28dbSGordon Ross 				goto errout;
88693bc28dbSGordon Ross 			break;
88793bc28dbSGordon Ross 
88893bc28dbSGordon Ross 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
88993bc28dbSGordon Ross 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
89093bc28dbSGordon Ross 			if (rc != 0)
89193bc28dbSGordon Ross 				goto errout;
89293bc28dbSGordon Ross 			break;
89393bc28dbSGordon Ross 
894a8661d6dSAndrew Stormont 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
895a8661d6dSAndrew Stormont 			/*
896a8661d6dSAndrew Stormont 			 * The SMB spec says this can be either 0 bytes
897a8661d6dSAndrew Stormont 			 * (handled above) or an 8 byte timestamp value
898a8661d6dSAndrew Stormont 			 * but does not say what its purpose is.
899a8661d6dSAndrew Stormont 			 *
900a8661d6dSAndrew Stormont 			 * Note: The WPTS expects us to validate that it
901a8661d6dSAndrew Stormont 			 * is at least 8 bytes so we read it and discard
902a8661d6dSAndrew Stormont 			 * it.  If it was too short the decode will fail.
903a8661d6dSAndrew Stormont 			 */
904a8661d6dSAndrew Stormont 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &nttime);
905a8661d6dSAndrew Stormont 			if (rc != 0)
906a8661d6dSAndrew Stormont 				goto errout;
907a8661d6dSAndrew Stormont 			break;
908a8661d6dSAndrew Stormont 
90993bc28dbSGordon Ross 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
91093bc28dbSGordon Ross 			/*
91193bc28dbSGordon Ross 			 * Support for opening "Previous Versions".
91293bc28dbSGordon Ross 			 * [MS-SMB2] 2.2.13.2.7  Data is an NT time.
91393bc28dbSGordon Ross 			 */
91493bc28dbSGordon Ross 			rc = smb_mbc_decodef(&cce->cce_mbc,
91593bc28dbSGordon Ross 			    "q", &nttime);
91693bc28dbSGordon Ross 			if (rc != 0)
91793bc28dbSGordon Ross 				goto errout;
91893bc28dbSGordon Ross 			smb_time_nt_to_unix(nttime, &op->timewarp);
91993bc28dbSGordon Ross 			op->create_timewarp = B_TRUE;
92093bc28dbSGordon Ross 			break;
92193bc28dbSGordon Ross 
92294047d49SGordon Ross 		/*
92394047d49SGordon Ross 		 * Note: This handles both V1 and V2 leases,
92494047d49SGordon Ross 		 * which differ only by their length.
92594047d49SGordon Ross 		 */
92694047d49SGordon Ross 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
92794047d49SGordon Ross 			if (data_len == 52) {
92894047d49SGordon Ross 				op->lease_version = 2;
92994047d49SGordon Ross 			} else if (data_len == 32) {
93094047d49SGordon Ross 				op->lease_version = 1;
93194047d49SGordon Ross 			} else {
93294047d49SGordon Ross 				cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x",
93394047d49SGordon Ross 				    data_len);
93494047d49SGordon Ross 			}
93594047d49SGordon Ross 			rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq",
93694047d49SGordon Ross 			    UUID_LEN,			/* # */
93794047d49SGordon Ross 			    op->lease_key,		/* c */
93894047d49SGordon Ross 			    &op->lease_state,		/* l */
93994047d49SGordon Ross 			    &op->lease_flags,		/* l */
94094047d49SGordon Ross 			    &nttime);	/* (ignored)	   q */
94194047d49SGordon Ross 			if (rc != 0)
94294047d49SGordon Ross 				goto errout;
94394047d49SGordon Ross 			if (op->lease_version == 2) {
94494047d49SGordon Ross 				rc = smb_mbc_decodef(&cce->cce_mbc,
94594047d49SGordon Ross 				    "#cw..",
94694047d49SGordon Ross 				    UUID_LEN,
94794047d49SGordon Ross 				    op->parent_lease_key,
94894047d49SGordon Ross 				    &op->lease_epoch);
94994047d49SGordon Ross 				if (rc != 0)
95094047d49SGordon Ross 					goto errout;
95194047d49SGordon Ross 			} else {
95294047d49SGordon Ross 				bzero(op->parent_lease_key, UUID_LEN);
95394047d49SGordon Ross 			}
95494047d49SGordon Ross 			break;
95594047d49SGordon Ross 
956811599a4SMatt Barden 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
957811599a4SMatt Barden 			rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl",
958811599a4SMatt Barden 			    &op->dh_fileid.persistent,	/* q */
959811599a4SMatt Barden 			    &op->dh_fileid.temporal,	/* q */
960811599a4SMatt Barden 			    UUID_LEN,			/* # */
961811599a4SMatt Barden 			    op->create_guid,		/* c */
962811599a4SMatt Barden 			    &op->dh_v2_flags);		/* l */
963811599a4SMatt Barden 			if (rc != 0)
964811599a4SMatt Barden 				goto errout;
965811599a4SMatt Barden 			break;
966811599a4SMatt Barden 
967811599a4SMatt Barden 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
968811599a4SMatt Barden 			rc = smb_mbc_decodef(&cce->cce_mbc, "qq",
969811599a4SMatt Barden 			    &op->dh_fileid.persistent, /* q */
970811599a4SMatt Barden 			    &op->dh_fileid.temporal); /* q */
971811599a4SMatt Barden 			if (rc != 0)
972811599a4SMatt Barden 				goto errout;
973811599a4SMatt Barden 			bzero(op->create_guid, UUID_LEN);
974811599a4SMatt Barden 			op->dh_v2_flags = 0;
975811599a4SMatt Barden 			break;
976811599a4SMatt Barden 
977811599a4SMatt Barden 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
978811599a4SMatt Barden 			rc = smb_mbc_decodef(&cce->cce_mbc,
979811599a4SMatt Barden 			    "ll8.#c",
980811599a4SMatt Barden 			    &op->dh_timeout,	/* l */
981811599a4SMatt Barden 			    &op->dh_v2_flags,	/* l */
982811599a4SMatt Barden 			    /* reserved */	/* 8. */
983811599a4SMatt Barden 			    UUID_LEN, /* # */
984811599a4SMatt Barden 			    op->create_guid); /* c */
985811599a4SMatt Barden 			if (rc != 0)
986811599a4SMatt Barden 				goto errout;
987811599a4SMatt Barden 			break;
988811599a4SMatt Barden 
989811599a4SMatt Barden 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
990811599a4SMatt Barden 			rc = smb_mbc_decodef(&cce->cce_mbc,
991811599a4SMatt Barden 			    "16."); /* reserved */
992811599a4SMatt Barden 			if (rc != 0)
993811599a4SMatt Barden 				goto errout;
994811599a4SMatt Barden 			op->dh_timeout = 0;	/* default */
995811599a4SMatt Barden 			op->dh_v2_flags = 0;
996811599a4SMatt Barden 			break;
997a90cf9f2SGordon Ross 		}
998a90cf9f2SGordon Ross 
99993bc28dbSGordon Ross 	next_cc:
1000a90cf9f2SGordon Ross 		if (next_off == 0) {
1001a90cf9f2SGordon Ross 			/* Normal loop termination */
1002a90cf9f2SGordon Ross 			status = 0;
1003a90cf9f2SGordon Ross 			break;
1004a90cf9f2SGordon Ross 		}
1005a90cf9f2SGordon Ross 
1006a90cf9f2SGordon Ross 		if ((next_off & 7) != 0)
1007a90cf9f2SGordon Ross 			break;
1008a90cf9f2SGordon Ross 		if ((top_offset + next_off) < in_mbc->chain_offset)
1009a90cf9f2SGordon Ross 			break;
1010a90cf9f2SGordon Ross 		if ((top_offset + next_off) > in_mbc->max_bytes)
1011a90cf9f2SGordon Ross 			break;
1012a90cf9f2SGordon Ross 		in_mbc->chain_offset = top_offset + next_off;
1013a90cf9f2SGordon Ross 	}
1014a90cf9f2SGordon Ross 
101593bc28dbSGordon Ross errout:
1016a90cf9f2SGordon Ross 	return (status);
1017a90cf9f2SGordon Ross }
1018a90cf9f2SGordon Ross 
1019a90cf9f2SGordon Ross /*
1020a90cf9f2SGordon Ross  * Encode an SMB2 Create Context buffer from our internal form.
102193bc28dbSGordon Ross  *
102293bc28dbSGordon Ross  * Build the Create Context to return; first the
102393bc28dbSGordon Ross  * per-element parts, then the aggregated buffer.
102493bc28dbSGordon Ross  *
102593bc28dbSGordon Ross  * No response for these:
102693bc28dbSGordon Ross  *	CCTX_EA_BUFFER
102793bc28dbSGordon Ross  *	CCTX_SD_BUFFER
102893bc28dbSGordon Ross  *	CCTX_ALLOCATION_SIZE
102993bc28dbSGordon Ross  *	CCTX_TIMEWARP_TOKEN
103093bc28dbSGordon Ross  *
103193bc28dbSGordon Ross  * Remember to add code sections to smb2_free_create_ctx()
103293bc28dbSGordon Ross  * for each section here that encodes a context element.
1033a90cf9f2SGordon Ross  */
1034a90cf9f2SGordon Ross static uint32_t
smb2_encode_create_ctx(smb_request_t * sr,smb2_create_ctx_t * cc)103593bc28dbSGordon Ross smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
1036a90cf9f2SGordon Ross {
103793bc28dbSGordon Ross 	smb_arg_open_t *op = &sr->arg.open;
1038a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce;
103993bc28dbSGordon Ross 	mbuf_chain_t *mbc = &sr->raw_data;
1040a90cf9f2SGordon Ross 	int last_top = -1;
1041a90cf9f2SGordon Ross 	int rc;
1042a90cf9f2SGordon Ross 
1043a90cf9f2SGordon Ross 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1044a90cf9f2SGordon Ross 		cce = &cc->cc_out_max_access;
104593bc28dbSGordon Ross 
104693bc28dbSGordon Ross 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
104793bc28dbSGordon Ross 		(void) smb_mbc_encodef(&cce->cce_mbc,
104893bc28dbSGordon Ross 		    "ll", 0, op->maximum_access);
104993bc28dbSGordon Ross 
1050a90cf9f2SGordon Ross 		last_top = mbc->chain_offset;
1051a90cf9f2SGordon Ross 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1052a90cf9f2SGordon Ross 		    SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
1053a90cf9f2SGordon Ross 		if (rc)
1054a90cf9f2SGordon Ross 			return (NT_STATUS_INTERNAL_ERROR);
1055a90cf9f2SGordon Ross 		(void) smb_mbc_poke(mbc, last_top, "l",
1056a90cf9f2SGordon Ross 		    mbc->chain_offset - last_top);
1057a90cf9f2SGordon Ross 	}
1058a90cf9f2SGordon Ross 
1059a90cf9f2SGordon Ross 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1060a90cf9f2SGordon Ross 		cce = &cc->cc_out_file_id;
106193bc28dbSGordon Ross 
106293bc28dbSGordon Ross 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
106393bc28dbSGordon Ross 		(void) smb_mbc_encodef(
106493bc28dbSGordon Ross 		    &cce->cce_mbc, "qll.15.",
106593bc28dbSGordon Ross 		    op->fileid,			/* q */
106693bc28dbSGordon Ross 		    op->op_fsid.val[0],		/* l */
106793bc28dbSGordon Ross 		    op->op_fsid.val[1]);	/* l */
106893bc28dbSGordon Ross 		    /* reserved (16 bytes)	.15. */
106993bc28dbSGordon Ross 
1070a90cf9f2SGordon Ross 		last_top = mbc->chain_offset;
1071a90cf9f2SGordon Ross 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1072a90cf9f2SGordon Ross 		    SMB2_CREATE_QUERY_ON_DISK_ID);
1073a90cf9f2SGordon Ross 		if (rc)
1074a90cf9f2SGordon Ross 			return (NT_STATUS_INTERNAL_ERROR);
1075a90cf9f2SGordon Ross 		(void) smb_mbc_poke(mbc, last_top, "l",
1076a90cf9f2SGordon Ross 		    mbc->chain_offset - last_top);
1077a90cf9f2SGordon Ross 	}
1078a90cf9f2SGordon Ross 
1079d082c877SGordon Ross 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1080d082c877SGordon Ross 		cce = &cc->cc_out_aapl;
108193bc28dbSGordon Ross 		/* cc_out_aapl already encoded */
108293bc28dbSGordon Ross 
1083d082c877SGordon Ross 		last_top = mbc->chain_offset;
1084d082c877SGordon Ross 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1085d082c877SGordon Ross 		    SMB2_CREATE_CTX_AAPL);
1086d082c877SGordon Ross 		if (rc)
1087d082c877SGordon Ross 			return (NT_STATUS_INTERNAL_ERROR);
1088d082c877SGordon Ross 		(void) smb_mbc_poke(mbc, last_top, "l",
1089d082c877SGordon Ross 		    mbc->chain_offset - last_top);
1090d082c877SGordon Ross 	}
1091d082c877SGordon Ross 
109294047d49SGordon Ross 	if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
109394047d49SGordon Ross 		cce = &cc->cc_out_req_lease;
109494047d49SGordon Ross 
109594047d49SGordon Ross 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
109694047d49SGordon Ross 		(void) smb_mbc_encodef(&cce->cce_mbc, "#cllq",
109794047d49SGordon Ross 		    UUID_LEN,			/* # */
109894047d49SGordon Ross 		    op->lease_key,		/* c */
109994047d49SGordon Ross 		    op->lease_state,		/* l */
110094047d49SGordon Ross 		    op->lease_flags,		/* l */
110194047d49SGordon Ross 		    0LL);			/* q */
110294047d49SGordon Ross 		if (op->lease_version == 2) {
110394047d49SGordon Ross 			cce->cce_mbc.max_bytes = cce->cce_len = 52;
110494047d49SGordon Ross 			(void) smb_mbc_encodef(&cce->cce_mbc,
110594047d49SGordon Ross 			    "#cw..",
110694047d49SGordon Ross 			    UUID_LEN,
110794047d49SGordon Ross 			    op->parent_lease_key,
110894047d49SGordon Ross 			    op->lease_epoch);
110994047d49SGordon Ross 		}
111094047d49SGordon Ross 
111194047d49SGordon Ross 		last_top = mbc->chain_offset;
111294047d49SGordon Ross 		rc = smb2_encode_create_ctx_elem(mbc, cce,
111394047d49SGordon Ross 		    SMB2_CREATE_REQUEST_LEASE);
111494047d49SGordon Ross 		if (rc)
111594047d49SGordon Ross 			return (NT_STATUS_INTERNAL_ERROR);
111694047d49SGordon Ross 		(void) smb_mbc_poke(mbc, last_top, "l",
111794047d49SGordon Ross 		    mbc->chain_offset - last_top);
111894047d49SGordon Ross 	}
111994047d49SGordon Ross 
1120811599a4SMatt Barden 	if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1121811599a4SMatt Barden 		cce = &cc->cc_out_dh_request;
1122811599a4SMatt Barden 
1123811599a4SMatt Barden 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1124811599a4SMatt Barden 		(void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL);
1125811599a4SMatt Barden 
1126811599a4SMatt Barden 		last_top = mbc->chain_offset;
1127811599a4SMatt Barden 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1128811599a4SMatt Barden 		    SMB2_CREATE_DURABLE_HANDLE_REQUEST);
1129811599a4SMatt Barden 		if (rc)
1130811599a4SMatt Barden 			return (NT_STATUS_INTERNAL_ERROR);
1131811599a4SMatt Barden 		(void) smb_mbc_poke(mbc, last_top, "l",
1132811599a4SMatt Barden 		    mbc->chain_offset - last_top);
1133811599a4SMatt Barden 	}
1134811599a4SMatt Barden 
1135811599a4SMatt Barden 	if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1136811599a4SMatt Barden 		cce = &cc->cc_out_dh_request_v2;
1137811599a4SMatt Barden 
1138811599a4SMatt Barden 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1139811599a4SMatt Barden 		(void) smb_mbc_encodef(&cce->cce_mbc, "ll",
1140811599a4SMatt Barden 		    op->dh_timeout, op->dh_v2_flags);
1141811599a4SMatt Barden 
1142811599a4SMatt Barden 		last_top = mbc->chain_offset;
1143811599a4SMatt Barden 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1144811599a4SMatt Barden 		    SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);
1145811599a4SMatt Barden 		if (rc)
1146811599a4SMatt Barden 			return (NT_STATUS_INTERNAL_ERROR);
1147811599a4SMatt Barden 		(void) smb_mbc_poke(mbc, last_top, "l",
1148811599a4SMatt Barden 		    mbc->chain_offset - last_top);
1149811599a4SMatt Barden 	}
1150811599a4SMatt Barden 
1151a90cf9f2SGordon Ross 	if (last_top >= 0)
1152a90cf9f2SGordon Ross 		(void) smb_mbc_poke(mbc, last_top, "l", 0);
1153a90cf9f2SGordon Ross 
1154a90cf9f2SGordon Ross 	return (0);
1155a90cf9f2SGordon Ross }
1156a90cf9f2SGordon Ross 
1157a90cf9f2SGordon Ross static int
smb2_encode_create_ctx_elem(mbuf_chain_t * out_mbc,smb2_create_ctx_elem_t * cce,uint32_t id)1158a90cf9f2SGordon Ross smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
115993bc28dbSGordon Ross     smb2_create_ctx_elem_t *cce, uint32_t id)
1160a90cf9f2SGordon Ross {
1161a90cf9f2SGordon Ross 	union {
1162a90cf9f2SGordon Ross 		uint32_t i;
1163a90cf9f2SGordon Ross 		char ch[4];
1164a90cf9f2SGordon Ross 	} cc_name;
1165a90cf9f2SGordon Ross 	int rc;
1166a90cf9f2SGordon Ross 
1167a90cf9f2SGordon Ross 	/* as above */
1168a90cf9f2SGordon Ross 	cc_name.i = htonl(id);
1169a90cf9f2SGordon Ross 
1170a90cf9f2SGordon Ross 	/*
1171a90cf9f2SGordon Ross 	 * This is the header, per [MS-SMB2] 2.2.13.2
1172a90cf9f2SGordon Ross 	 * Sorry about the fixed offsets.  We know we'll
1173a90cf9f2SGordon Ross 	 * layout the data part as [name, payload] and
1174a90cf9f2SGordon Ross 	 * name is a fixed length, so this easy.
1175a90cf9f2SGordon Ross 	 * The final layout looks like this:
117693bc28dbSGordon Ross 	 *	a: this header (16 bytes)
1177a90cf9f2SGordon Ross 	 *	b: the name (4 bytes, 4 pad)
1178a90cf9f2SGordon Ross 	 *	c: the payload (variable)
1179d2488fe8SGordon Ross 	 *	d: padding (to align 8)
1180a90cf9f2SGordon Ross 	 *
1181a90cf9f2SGordon Ross 	 * Note that "Next elem." is filled in later.
1182a90cf9f2SGordon Ross 	 */
1183a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
1184a90cf9f2SGordon Ross 	    out_mbc, "lwwwwl",
1185a90cf9f2SGordon Ross 	    0,		/* Next offset	l */
1186a90cf9f2SGordon Ross 	    16,		/* NameOffset	w */
1187a90cf9f2SGordon Ross 	    4,		/* NameLength	w */
1188a90cf9f2SGordon Ross 	    0,		/* Reserved	w */
1189a90cf9f2SGordon Ross 	    24,		/* DataOffset	w */
119093bc28dbSGordon Ross 	    cce->cce_len); /* DataLen	l */
1191a90cf9f2SGordon Ross 	if (rc)
1192a90cf9f2SGordon Ross 		return (rc);
1193a90cf9f2SGordon Ross 
1194a90cf9f2SGordon Ross 	/*
1195a90cf9f2SGordon Ross 	 * Now the "name" and payload.
1196a90cf9f2SGordon Ross 	 */
1197a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
1198a90cf9f2SGordon Ross 	    out_mbc, "4c4.#C",
1199a90cf9f2SGordon Ross 	    cc_name.ch,		/* 4c4. */
1200a90cf9f2SGordon Ross 	    cce->cce_len,	/* # */
1201a90cf9f2SGordon Ross 	    &cce->cce_mbc);	/* C */
1202a90cf9f2SGordon Ross 
1203d2488fe8SGordon Ross 	(void) smb_mbc_put_align(out_mbc, 8);
1204d2488fe8SGordon Ross 
1205a90cf9f2SGordon Ross 	return (rc);
1206a90cf9f2SGordon Ross }
1207a90cf9f2SGordon Ross 
1208a90cf9f2SGordon Ross static void
smb2_free_create_ctx(smb2_create_ctx_t * cc)1209a90cf9f2SGordon Ross smb2_free_create_ctx(smb2_create_ctx_t *cc)
1210a90cf9f2SGordon Ross {
1211a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce;
1212a90cf9f2SGordon Ross 
1213a90cf9f2SGordon Ross 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1214a90cf9f2SGordon Ross 		cce = &cc->cc_out_max_access;
1215a90cf9f2SGordon Ross 		MBC_FLUSH(&cce->cce_mbc);
1216a90cf9f2SGordon Ross 	}
1217a90cf9f2SGordon Ross 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1218a90cf9f2SGordon Ross 		cce = &cc->cc_out_file_id;
1219a90cf9f2SGordon Ross 		MBC_FLUSH(&cce->cce_mbc);
1220a90cf9f2SGordon Ross 	}
1221d082c877SGordon Ross 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1222d082c877SGordon Ross 		cce = &cc->cc_out_aapl;
1223d082c877SGordon Ross 		MBC_FLUSH(&cce->cce_mbc);
1224d082c877SGordon Ross 	}
122594047d49SGordon Ross 	if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
122694047d49SGordon Ross 		cce = &cc->cc_out_req_lease;
122794047d49SGordon Ross 		MBC_FLUSH(&cce->cce_mbc);
122894047d49SGordon Ross 	}
1229811599a4SMatt Barden 	if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1230811599a4SMatt Barden 		cce = &cc->cc_out_dh_request;
1231811599a4SMatt Barden 		MBC_FLUSH(&cce->cce_mbc);
1232811599a4SMatt Barden 	}
1233811599a4SMatt Barden 	if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1234811599a4SMatt Barden 		cce = &cc->cc_out_dh_request_v2;
1235811599a4SMatt Barden 		MBC_FLUSH(&cce->cce_mbc);
1236811599a4SMatt Barden 	}
1237a90cf9f2SGordon Ross }
1238