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