xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_create.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
14  * Copyright 2022 RackTop Systems, Inc.
15  */
16 
17 /*
18  * Dispatch function for SMB2_CREATE
19  * [MS-SMB2] 2.2.13
20  */
21 
22 #include <smbsrv/smb2_kproto.h>
23 #include <smbsrv/smb_fsops.h>
24 
25 #define	DH_PERSISTENT	SMB2_DHANDLE_FLAG_PERSISTENT
26 
27 /*
28  * Compile-time check that the SMB2_LEASE_... definitions
29  * match the (internal) equivalents from ntifs.h
30  */
31 #if SMB2_LEASE_NONE != OPLOCK_LEVEL_NONE
32 #error "SMB2_LEASE_NONE"
33 #endif
34 #if SMB2_LEASE_READ_CACHING != OPLOCK_LEVEL_CACHE_READ
35 #error "SMB2_LEASE_READ_CACHING"
36 #endif
37 #if SMB2_LEASE_HANDLE_CACHING != OPLOCK_LEVEL_CACHE_HANDLE
38 #error "SMB2_LEASE_HANDLE_CACHING"
39 #endif
40 #if SMB2_LEASE_WRITE_CACHING != OPLOCK_LEVEL_CACHE_WRITE
41 #error "SMB2_LEASE_WRITE_CACHING"
42 #endif
43 
44 /*
45  * Some flags used locally to keep track of which Create Context
46  * names have been provided and/or requested.
47  */
48 #define	CCTX_EA_BUFFER			1
49 #define	CCTX_SD_BUFFER			2
50 #define	CCTX_DH_REQUEST			4
51 #define	CCTX_DH_RECONNECT		8
52 #define	CCTX_ALLOCATION_SIZE		0x10
53 #define	CCTX_QUERY_MAX_ACCESS		0x20
54 #define	CCTX_TIMEWARP_TOKEN		0x40
55 #define	CCTX_QUERY_ON_DISK_ID		0x80
56 #define	CCTX_REQUEST_LEASE		0x100
57 #define	CCTX_AAPL_EXT			0x200
58 #define	CCTX_DH_REQUEST_V2		0x400
59 #define	CCTX_DH_RECONNECT_V2		0x800
60 
61 typedef struct smb2_create_ctx_elem {
62 	uint32_t cce_len;
63 	mbuf_chain_t cce_mbc;
64 } smb2_create_ctx_elem_t;
65 
66 typedef struct smb2_create_ctx {
67 	mbuf_chain_t cc_in_mbc;
68 	uint_t	cc_in_flags;	/* CCTX_... */
69 	uint_t	cc_out_flags;	/* CCTX_... */
70 	/* Elements we may see in the request. */
71 	smb2_create_ctx_elem_t cc_in_ext_attr;
72 	smb2_create_ctx_elem_t cc_in_sec_desc;
73 	smb2_create_ctx_elem_t cc_in_dh_request;
74 	smb2_create_ctx_elem_t cc_in_dh_reconnect;
75 	smb2_create_ctx_elem_t cc_in_alloc_size;
76 	smb2_create_ctx_elem_t cc_in_time_warp;
77 	smb2_create_ctx_elem_t cc_in_req_lease;
78 	smb2_create_ctx_elem_t cc_in_aapl;
79 	smb2_create_ctx_elem_t cc_in_dh_request_v2;
80 	smb2_create_ctx_elem_t cc_in_dh_reconnect_v2;
81 	smb2_create_ctx_elem_t cc_in_max_access;
82 	/* Elements we my place in the response */
83 	smb2_create_ctx_elem_t cc_out_max_access;
84 	smb2_create_ctx_elem_t cc_out_file_id;
85 	smb2_create_ctx_elem_t cc_out_aapl;
86 	smb2_create_ctx_elem_t cc_out_req_lease;
87 	smb2_create_ctx_elem_t cc_out_dh_request;
88 	smb2_create_ctx_elem_t cc_out_dh_request_v2;
89 } smb2_create_ctx_t;
90 
91 static uint32_t smb2_decode_create_ctx(
92 	smb_request_t *, smb2_create_ctx_t *);
93 static uint32_t smb2_encode_create_ctx(
94 	smb_request_t *, smb2_create_ctx_t *);
95 static int smb2_encode_create_ctx_elem(
96 	mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
97 static void smb2_free_create_ctx(smb2_create_ctx_t *);
98 
99 int smb2_enable_dh = 1;
100 
101 smb_sdrc_t
102 smb2_create(smb_request_t *sr)
103 {
104 	smb_attr_t *attr;
105 	smb2_create_ctx_elem_t *cce;
106 	smb2_create_ctx_t cctx;
107 	smb_arg_open_t *op = &sr->arg.open;
108 	smb_ofile_t *of = NULL;
109 	uint16_t StructSize;
110 	uint8_t SecurityFlags;
111 	uint32_t ImpersonationLevel;
112 	uint64_t SmbCreateFlags;
113 	uint64_t Reserved4;
114 	uint16_t NameOffset;
115 	uint16_t NameLength;
116 	uint32_t CreateCtxOffset;
117 	uint32_t CreateCtxLength;
118 	smb2fid_t smb2fid = { 0, 0 };
119 	uint32_t status;
120 	int dh_flags;
121 	int skip;
122 	int rc = 0;
123 
124 	bzero(&cctx, sizeof (cctx));
125 	op->create_ctx = &cctx;	/* for debugging */
126 
127 	/*
128 	 * Paranoia.  This will set sr->fid_ofile, so
129 	 * if we already have one, release it now.
130 	 */
131 	if (sr->fid_ofile != NULL) {
132 		smb_ofile_release(sr->fid_ofile);
133 		sr->fid_ofile = NULL;
134 	}
135 
136 	/*
137 	 * Decode the SMB2 Create request
138 	 *
139 	 * Most decode errors return SDRC_ERROR, but
140 	 * for some we give a more specific error.
141 	 *
142 	 * In the "decode section" (starts here) any
143 	 * errors should either return SDRC_ERROR, or
144 	 * if any cleanup is needed, goto errout.
145 	 */
146 	rc = smb_mbc_decodef(
147 	    &sr->smb_data, "wbblqqlllllwwll",
148 	    &StructSize,		/* w */
149 	    &SecurityFlags,		/* b */
150 	    &op->op_oplock_level,	/* b */
151 	    &ImpersonationLevel,	/* l */
152 	    &SmbCreateFlags,		/* q */
153 	    &Reserved4,			/* q */
154 	    &op->desired_access,	/* l */
155 	    &op->dattr,			/* l */
156 	    &op->share_access,		/* l */
157 	    &op->create_disposition,	/* l */
158 	    &op->create_options,	/* l */
159 	    &NameOffset,		/* w */
160 	    &NameLength,		/* w */
161 	    &CreateCtxOffset,		/* l */
162 	    &CreateCtxLength);		/* l */
163 	if (rc != 0 || StructSize != 57)
164 		return (SDRC_ERROR);
165 
166 	/*
167 	 * We're normally positioned at the path name now,
168 	 * but there could be some padding before it.
169 	 */
170 	skip = (NameOffset + sr->smb2_cmd_hdr) -
171 	    sr->smb_data.chain_offset;
172 	if (skip < 0)
173 		return (SDRC_ERROR);
174 	if (skip > 0)
175 		(void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
176 
177 	/*
178 	 * Get the path name
179 	 *
180 	 * Name too long is not technically a decode error,
181 	 * but it's very rare, so we'll just skip the
182 	 * dtrace probes for this error case.
183 	 */
184 	if (NameLength >= SMB_MAXPATHLEN) {
185 		status = NT_STATUS_OBJECT_PATH_INVALID;
186 		goto errout;
187 	}
188 	if (NameLength == 0) {
189 		op->fqi.fq_path.pn_path = "";
190 	} else {
191 		rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
192 		    NameLength, &op->fqi.fq_path.pn_path);
193 		if (rc) {
194 			status = NT_STATUS_OBJECT_PATH_INVALID;
195 			goto errout;
196 		}
197 		if (op->fqi.fq_path.pn_path[0] == '\\') {
198 			status = NT_STATUS_INVALID_PARAMETER;
199 			goto errout;
200 		}
201 	}
202 	op->fqi.fq_dnode = sr->tid_tree->t_snode;
203 
204 	/*
205 	 * If there is a "Create Context" payload, decode it.
206 	 * This may carry things like a security descriptor,
207 	 * extended attributes, etc. to be used in create.
208 	 *
209 	 * The create ctx buffer must start after the headers
210 	 * and file name, and must be 8-byte aligned.
211 	 */
212 	if (CreateCtxLength != 0) {
213 		if ((CreateCtxOffset & 7) != 0 ||
214 		    (CreateCtxOffset + sr->smb2_cmd_hdr) <
215 		    sr->smb_data.chain_offset) {
216 			status = NT_STATUS_INVALID_PARAMETER;
217 			goto errout;
218 		}
219 
220 		rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data,
221 		    sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
222 		if (rc) {
223 			status = NT_STATUS_INVALID_PARAMETER;
224 			goto errout;
225 		}
226 		status = smb2_decode_create_ctx(sr, &cctx);
227 		if (status)
228 			goto errout;
229 	}
230 
231 	/*
232 	 * Everything is decoded into some internal form, so
233 	 * in this probe one can look at sr->arg.open etc.
234 	 *
235 	 * This marks the end of the "decode" section and the
236 	 * beginning of the "body" section.  Any errors in
237 	 * this section should use: goto cmd_done (which is
238 	 * just before the dtrace "done" probe).
239 	 */
240 	DTRACE_SMB2_START(op__Create, smb_request_t *, sr); /* arg.open */
241 
242 	/*
243 	 * Process the incoming create contexts (already decoded),
244 	 * that need action before the open, starting with the
245 	 * Durable Handle ones, which may override others.
246 	 */
247 
248 	/*
249 	 * Only disk trees get durable handles.
250 	 */
251 	if (smb2_enable_dh == 0 ||
252 	    (sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
253 		cctx.cc_in_flags &=
254 		    ~(CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
255 		    CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
256 	}
257 
258 	/*
259 	 * DH v2 is only valid in SMB3.0 and later.
260 	 * If seen in earlier dialects, ignore.
261 	 */
262 	if (sr->session->dialect < SMB_VERS_3_0) {
263 		cctx.cc_in_flags &=
264 		    ~(CCTX_DH_REQUEST_V2|CCTX_DH_RECONNECT_V2);
265 	}
266 
267 	/*
268 	 * It is an error to specify more than one Durable Handle
269 	 * operation in a single create, except when only the v1
270 	 * REQUEST and RECONNECT operations are specified. In that
271 	 * case, the v1 REQUEST is ignored.
272 	 */
273 	dh_flags = cctx.cc_in_flags &
274 	    (CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
275 	    CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
276 	if ((dh_flags & (dh_flags - 1)) != 0 &&
277 	    dh_flags != (CCTX_DH_REQUEST|CCTX_DH_RECONNECT)) {
278 		status = NT_STATUS_INVALID_PARAMETER;
279 		goto cmd_done;
280 	}
281 
282 	/*
283 	 * Reconnect is special in MANY ways, including the
284 	 * somewhat surprising (specified) behavior that
285 	 * most other creat parameters are ignored, and
286 	 * many create context types are ignored too.
287 	 */
288 	op->dh_vers = SMB2_NOT_DURABLE;
289 	if ((cctx.cc_in_flags &
290 	    (CCTX_DH_RECONNECT|CCTX_DH_RECONNECT_V2)) != 0) {
291 
292 		if ((cctx.cc_in_flags & CCTX_DH_RECONNECT_V2) != 0)
293 			op->dh_vers = SMB2_DURABLE_V2;
294 		else
295 			op->dh_vers = SMB2_DURABLE_V1;
296 
297 		/* Ignore these create contexts. */
298 		cctx.cc_in_flags &=
299 		    ~(CCTX_DH_REQUEST |
300 		    CCTX_DH_REQUEST_V2 |
301 		    CCTX_EA_BUFFER |
302 		    CCTX_SD_BUFFER |
303 		    CCTX_ALLOCATION_SIZE |
304 		    CCTX_TIMEWARP_TOKEN |
305 		    CCTX_QUERY_ON_DISK_ID);
306 
307 		/*
308 		 * Reconnect check needs to know if a lease was requested.
309 		 * The requested oplock level is ignored in reconnect, so
310 		 * using op_oplock_level to convey this info.
311 		 */
312 		if (cctx.cc_in_flags & CCTX_REQUEST_LEASE)
313 			op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
314 		else
315 			op->op_oplock_level = 0;
316 
317 		status = smb2_dh_reconnect(sr);
318 		if (status != NT_STATUS_SUCCESS)
319 			goto cmd_done;
320 
321 		/*
322 		 * Skip most open execution during reconnect,
323 		 * but need (reclaimed) oplock state in *op.
324 		 */
325 		of = sr->fid_ofile;
326 		smb2_oplock_reconnect(sr);
327 		goto reconnect_done;
328 	}
329 
330 	/*
331 	 * Real create (of a new handle, not reconnect)
332 	 */
333 
334 	/*
335 	 * Validate the requested oplock level.
336 	 * Conversion to internal form is in smb2_oplock_acquire()
337 	 */
338 	switch (op->op_oplock_level) {
339 	case SMB2_OPLOCK_LEVEL_NONE:		/* OPLOCK_LEVEL_NONE */
340 	case SMB2_OPLOCK_LEVEL_II:		/* OPLOCK_LEVEL_TWO */
341 	case SMB2_OPLOCK_LEVEL_EXCLUSIVE:	/* OPLOCK_LEVEL_ONE */
342 	case SMB2_OPLOCK_LEVEL_BATCH:		/* OPLOCK_LEVEL_BATCH */
343 		/*
344 		 * Ignore lease create context (if any)
345 		 */
346 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
347 		break;
348 
349 	case SMB2_OPLOCK_LEVEL_LEASE:		/* OPLOCK_LEVEL_GRANULAR */
350 		/*
351 		 * Require a lease create context.
352 		 */
353 		if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) == 0) {
354 			cmn_err(CE_NOTE, "smb2:create, oplock=ff and no lease");
355 			status = NT_STATUS_INVALID_PARAMETER;
356 			goto cmd_done;
357 		}
358 
359 		/*
360 		 * Validate lease request state
361 		 * Only a few valid combinations.
362 		 */
363 		switch (op->lease_state) {
364 		case SMB2_LEASE_NONE:
365 		case SMB2_LEASE_READ_CACHING:
366 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_HANDLE_CACHING:
367 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING:
368 		case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING |
369 		    SMB2_LEASE_HANDLE_CACHING:
370 			break;
371 
372 		default:
373 			/*
374 			 * Invalid lease state flags
375 			 * Just force to "none".
376 			 */
377 			op->lease_state = SMB2_LEASE_NONE;
378 			break;
379 		}
380 		break;
381 
382 	default:
383 		/* Unknown SMB2 oplock level. */
384 		status = NT_STATUS_INVALID_PARAMETER;
385 		goto cmd_done;
386 	}
387 
388 	/*
389 	 * Only disk trees get oplocks or leases.
390 	 */
391 	if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
392 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
393 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
394 	}
395 
396 	if ((sr->tid_tree->t_flags & SMB_TREE_CA) == 0)
397 		op->dh_v2_flags &= ~DH_PERSISTENT;
398 
399 	if ((cctx.cc_in_flags &
400 	    (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0) {
401 		if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0)
402 			op->dh_vers = SMB2_DURABLE_V2;
403 		else
404 			op->dh_vers = SMB2_DURABLE_V1;
405 	}
406 
407 	if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
408 		status = NT_STATUS_EAS_NOT_SUPPORTED;
409 		goto cmd_done;
410 	}
411 
412 	/*
413 	 * ImpersonationLevel (spec. says validate + ignore)
414 	 */
415 	switch (ImpersonationLevel) {
416 	case SMB2_IMPERSONATION_ANONYMOUS:
417 	case SMB2_IMPERSONATION_IDENTIFICATION:
418 	case SMB2_IMPERSONATION_IMPERSONATION:
419 	case SMB2_IMPERSONATION_DELEGATE:
420 		break;
421 	default:
422 		status = NT_STATUS_BAD_IMPERSONATION_LEVEL;
423 		goto cmd_done;
424 	}
425 
426 	/*
427 	 * SmbCreateFlags (spec. says ignore)
428 	 */
429 
430 	if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
431 	    !(op->desired_access & DELETE)) {
432 		status = NT_STATUS_INVALID_PARAMETER;
433 		goto cmd_done;
434 	}
435 
436 	if (op->dattr & FILE_FLAG_WRITE_THROUGH)
437 		op->create_options |= FILE_WRITE_THROUGH;
438 	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
439 		op->create_options |= FILE_DELETE_ON_CLOSE;
440 	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
441 		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
442 	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
443 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
444 	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
445 		status = NT_STATUS_INVALID_PARAMETER;
446 		goto cmd_done;
447 	}
448 
449 	/*
450 	 * The real open call.   Note: this gets attributes into
451 	 * op->fqi.fq_fattr (SMB_AT_ALL).  We need those below.
452 	 * When of != NULL, goto errout closes it.
453 	 */
454 	status = smb_common_open(sr);
455 	if (status != NT_STATUS_SUCCESS)
456 		goto cmd_done;
457 	of = sr->fid_ofile;
458 
459 	/*
460 	 * Set the "persistent" part of the file ID
461 	 * (only for DISK shares).  Need this even for
462 	 * non-durable handles in case we get the ioctl
463 	 * to set "resiliency" on this handle.
464 	 */
465 	if (of->f_ftype == SMB_FTYPE_DISK) {
466 		if ((op->dh_v2_flags & DH_PERSISTENT) != 0)
467 			smb_ofile_set_persistid_ph(of);
468 		else
469 			smb_ofile_set_persistid_dh(of);
470 	}
471 
472 	/*
473 	 * [MS-SMB2] 3.3.5.9.8
474 	 * Handling the SMB2_CREATE_REQUEST_LEASE Create Context
475 	 */
476 	if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0) {
477 		status = smb2_lease_create(sr, sr->session->clnt_uuid);
478 		if (status != NT_STATUS_SUCCESS) {
479 			if (op->action_taken == SMB_OACT_CREATED) {
480 				smb_ofile_set_delete_on_close(sr, of);
481 			}
482 			goto cmd_done;
483 		}
484 	}
485 	if (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
486 		smb2_lease_acquire(sr);
487 	} else if (op->op_oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
488 		smb2_oplock_acquire(sr);
489 	}
490 
491 	/*
492 	 * Make this a durable open, but only if:
493 	 * (durable handle requested and...)
494 	 *
495 	 * 1. op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH
496 	 * 2. A lease is requested with handle caching
497 	 *    - for v1, the lease must not be on a directory
498 	 * 3. For v2, flags has "persistent" (tree is CA)
499 	 *    (when tree not CA, turned off persist above)
500 	 *
501 	 * Otherwise, DH requests are ignored, so we set
502 	 * dh_vers = not durable
503 	 */
504 	if ((cctx.cc_in_flags &
505 	    (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0 &&
506 	    smb_node_is_file(of->f_node) &&
507 	    ((op->dh_v2_flags & DH_PERSISTENT) != 0 ||
508 	    (op->op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH) ||
509 	    (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE &&
510 	    (op->lease_state & OPLOCK_LEVEL_CACHE_HANDLE) != 0))) {
511 		/*
512 		 * OK, make this handle "durable"
513 		 */
514 		if (op->dh_vers == SMB2_DURABLE_V2) {
515 			(void) memcpy(of->dh_create_guid,
516 			    op->create_guid, UUID_LEN);
517 
518 			if ((op->dh_v2_flags & DH_PERSISTENT) != 0) {
519 				if (smb2_dh_make_persistent(sr, of) == 0) {
520 					of->dh_persist = B_TRUE;
521 				} else {
522 					op->dh_v2_flags = 0;
523 				}
524 			}
525 		}
526 		if (op->dh_vers != SMB2_NOT_DURABLE) {
527 			uint32_t msto;
528 
529 			of->dh_vers = op->dh_vers;
530 			of->dh_expire_time = 0;
531 
532 			/*
533 			 * Client may provide timeout=0 to request
534 			 * the default timeout (in mSec.)
535 			 */
536 			msto = op->dh_timeout;
537 			if (msto == 0) {
538 				msto = (of->dh_persist) ?
539 				    smb2_persist_timeout :
540 				    smb2_dh_def_timeout;
541 			}
542 			if (msto > smb2_dh_max_timeout)
543 				msto = smb2_dh_max_timeout;
544 			op->dh_timeout = msto;
545 			of->dh_timeout_offset = MSEC2NSEC(msto);
546 		}
547 	} else {
548 		op->dh_vers = SMB2_NOT_DURABLE;
549 		op->dh_v2_flags = 0;
550 	}
551 
552 	/*
553 	 * NB: after the above smb_common_open() success,
554 	 * we have a handle allocated (sr->fid_ofile).
555 	 * If we don't return success, we must close it.
556 	 *
557 	 * Using sr->smb_fid as the file handle for now,
558 	 * though it could later be something larger,
559 	 * (16 bytes) similar to an NFSv4 open handle.
560 	 */
561 reconnect_done:
562 	smb2fid.persistent = of->f_persistid;
563 	smb2fid.temporal = sr->smb_fid;
564 
565 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
566 	case STYPE_DISKTREE:
567 	case STYPE_PRINTQ:
568 		if (op->create_options & FILE_DELETE_ON_CLOSE)
569 			smb_ofile_set_delete_on_close(sr, of);
570 		break;
571 	}
572 
573 	/*
574 	 * Process any outgoing create contexts that need work
575 	 * after the open succeeds.  Encode happens later.
576 	 */
577 	if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
578 		op->maximum_access = 0;
579 		if (of->f_node != NULL) {
580 			smb_fsop_eaccess(sr, of->f_cr, of->f_node,
581 			    &op->maximum_access);
582 		}
583 		op->maximum_access |= of->f_granted_access;
584 		cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
585 	}
586 
587 	if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
588 	    of->f_node != NULL) {
589 		op->op_fsid = SMB_NODE_FSID(of->f_node);
590 		cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
591 	}
592 
593 	if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) {
594 		cce = &cctx.cc_out_aapl;
595 		/*
596 		 * smb2_aapl_crctx has a variable response depending on
597 		 * what the incoming context looks like, so it does all
598 		 * the work of building cc_out_aapl, including setting
599 		 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode.
600 		 * If we see errors getting this, simply omit it from
601 		 * the collection of returned create contexts.
602 		 */
603 		status = smb2_aapl_crctx(sr,
604 		    &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc);
605 		if (status == 0) {
606 			cce->cce_len = cce->cce_mbc.chain_offset;
607 			cctx.cc_out_flags |= CCTX_AAPL_EXT;
608 		}
609 		status = 0;
610 	}
611 
612 	/*
613 	 * If a lease was requested, and we got one...
614 	 */
615 	if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0 &&
616 	    op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE)
617 		cctx.cc_out_flags |= CCTX_REQUEST_LEASE;
618 
619 	/*
620 	 * If a durable handle was requested and we got one...
621 	 */
622 	if ((cctx.cc_in_flags & CCTX_DH_REQUEST) != 0 &&
623 	    of->dh_vers == SMB2_DURABLE_V1) {
624 		cctx.cc_out_flags |= CCTX_DH_REQUEST;
625 	}
626 	if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0 &&
627 	    of->dh_vers == SMB2_DURABLE_V2) {
628 		cctx.cc_out_flags |= CCTX_DH_REQUEST_V2;
629 	}
630 
631 	/*
632 	 * This marks the end of the "body" section and the
633 	 * beginning of the "encode" section.  Any errors
634 	 * encoding the response should use: goto errout
635 	 */
636 cmd_done:
637 	/* Want status visible in the done probe. */
638 	sr->smb2_status = status;
639 	DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr);
640 	if (status != NT_STATUS_SUCCESS)
641 		goto errout;
642 
643 	/*
644 	 * Encode all the create contexts to return.
645 	 */
646 	if (cctx.cc_out_flags) {
647 		sr->raw_data.max_bytes = smb2_max_trans;
648 		status = smb2_encode_create_ctx(sr, &cctx);
649 		if (status)
650 			goto errout;
651 	}
652 
653 	/*
654 	 * Encode the SMB2 Create reply
655 	 */
656 	attr = &op->fqi.fq_fattr;
657 	rc = smb_mbc_encodef(
658 	    &sr->reply,
659 	    "wb.lTTTTqqllqqll",
660 	    89,	/* StructSize */	/* w */
661 	    op->op_oplock_level,	/* b */
662 	    op->action_taken,		/* l */
663 	    &attr->sa_crtime,		/* T */
664 	    &attr->sa_vattr.va_atime,	/* T */
665 	    &attr->sa_vattr.va_mtime,	/* T */
666 	    &attr->sa_vattr.va_ctime,	/* T */
667 	    attr->sa_allocsz,		/* q */
668 	    attr->sa_vattr.va_size,	/* q */
669 	    attr->sa_dosattr,		/* l */
670 	    0, /* reserved2 */		/* l */
671 	    smb2fid.persistent,		/* q */
672 	    smb2fid.temporal,		/* q */
673 	    0,  /* CreateCtxOffset	   l */
674 	    0); /* CreateCtxLength	   l */
675 	if (rc != 0) {
676 		status = NT_STATUS_UNSUCCESSFUL;
677 		goto errout;
678 	}
679 
680 	CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
681 	CreateCtxLength = MBC_LENGTH(&sr->raw_data);
682 	if (CreateCtxLength != 0) {
683 		/*
684 		 * Overwrite CreateCtxOffset, CreateCtxLength, pad
685 		 */
686 		sr->reply.chain_offset -= 8;
687 		rc = smb_mbc_encodef(
688 		    &sr->reply,
689 		    "ll#C",
690 		    CreateCtxOffset,	/* l */
691 		    CreateCtxLength,	/* l */
692 		    CreateCtxLength,	/* # */
693 		    &sr->raw_data);	/* C */
694 		if (rc != 0) {
695 			status = NT_STATUS_UNSUCCESSFUL;
696 			goto errout;
697 		}
698 	} else {
699 		(void) smb_mbc_encodef(&sr->reply, ".");
700 	}
701 
702 	if (status != 0) {
703 	errout:
704 		if (of != NULL)
705 			smb_ofile_close(of, 0);
706 		smb2sr_put_error(sr, status);
707 	}
708 	if (op->sd != NULL) {
709 		smb_sd_term(op->sd);
710 		kmem_free(op->sd, sizeof (*op->sd));
711 	}
712 	if (cctx.cc_out_flags)
713 		smb2_free_create_ctx(&cctx);
714 
715 	return (SDRC_SUCCESS);
716 }
717 
718 /*
719  * Decode an SMB2 Create Context buffer into our internal form.
720  * Avoid policy decisions about what's supported here, just decode.
721  */
722 static uint32_t
723 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
724 {
725 	smb_arg_open_t *op = &sr->arg.open;
726 	smb2_create_ctx_elem_t *cce;
727 	mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
728 	mbuf_chain_t name_mbc;
729 	union {
730 		uint32_t i;
731 		char ch[4];
732 	} cc_name;
733 	uint32_t status;
734 	int32_t next_off;
735 	uint32_t data_len;
736 	uint16_t data_off;
737 	uint16_t name_off;
738 	uint16_t name_len;
739 	int top_offset;
740 	int rc;
741 
742 	/*
743 	 * Any break from the loop below before we've decoded
744 	 * the entire create context means it was malformatted,
745 	 * so we should return INVALID_PARAMETER.
746 	 */
747 	status = NT_STATUS_INVALID_PARAMETER;
748 	for (;;) {
749 		cce = NULL;
750 		top_offset = in_mbc->chain_offset;
751 		rc = smb_mbc_decodef(
752 		    in_mbc,
753 		    "lww..wl",
754 		    &next_off,	/* l */
755 		    &name_off,	/* w */
756 		    &name_len,	/* w */
757 		    /* reserved	  .. */
758 		    &data_off,	/* w */
759 		    &data_len); /* l */
760 		if (rc)
761 			break;
762 
763 		/*
764 		 * The Create Context "name", per [MS-SMB] 2.2.13.2
765 		 * They're defined as network-order integers for our
766 		 * switch below.  We don't have routines to decode
767 		 * native order, so read as char[4] then ntohl.
768 		 * NB: in SMB3, some of these are 8 bytes.
769 		 */
770 		if ((top_offset + name_off) < in_mbc->chain_offset)
771 			break;
772 		rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc,
773 		    top_offset + name_off, name_len);
774 		if (rc)
775 			break;
776 		rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name);
777 		if (rc)
778 			break;
779 		cc_name.i = ntohl(cc_name.i);
780 
781 		switch (cc_name.i) {
782 		case SMB2_CREATE_EA_BUFFER:		/* ("ExtA") */
783 			cc->cc_in_flags |= CCTX_EA_BUFFER;
784 			cce = &cc->cc_in_ext_attr;
785 			break;
786 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
787 			cc->cc_in_flags |= CCTX_SD_BUFFER;
788 			cce = &cc->cc_in_sec_desc;
789 			break;
790 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
791 			cc->cc_in_flags |= CCTX_DH_REQUEST;
792 			cce = &cc->cc_in_dh_request;
793 			break;
794 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
795 			cc->cc_in_flags |= CCTX_DH_RECONNECT;
796 			cce = &cc->cc_in_dh_reconnect;
797 			break;
798 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
799 			cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
800 			cce = &cc->cc_in_alloc_size;
801 			break;
802 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
803 			cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
804 			/* Optional input data for this CC. See below. */
805 			cce = &cc->cc_in_max_access;
806 			break;
807 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
808 			cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
809 			cce = &cc->cc_in_time_warp;
810 			break;
811 		case SMB2_CREATE_QUERY_ON_DISK_ID:	/* ("QFid") */
812 			cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
813 			/* no input data for this */
814 			break;
815 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
816 			cc->cc_in_flags |= CCTX_REQUEST_LEASE;
817 			cce = &cc->cc_in_req_lease;
818 			break;
819 		case SMB2_CREATE_CTX_AAPL:		/* ("AAPL") */
820 			cc->cc_in_flags |= CCTX_AAPL_EXT;
821 			cce = &cc->cc_in_aapl;
822 			break;
823 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
824 			cc->cc_in_flags |= CCTX_DH_REQUEST_V2;
825 			cce = &cc->cc_in_dh_request_v2;
826 			break;
827 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
828 			cc->cc_in_flags |= CCTX_DH_RECONNECT_V2;
829 			cce = &cc->cc_in_dh_reconnect_v2;
830 			break;
831 
832 		/*
833 		 * Known but not implemented context IDs.
834 		 * Here just to silence the debug below.
835 		 *
836 		 * Note: all three of these IDs are actually longer,
837 		 * but we start by decoding just the first 4 bytes.
838 		 * If/when we recognize these, do another match on
839 		 * the full ID after we take this switch case.
840 		 */
841 		case 0x45bca66a: /* SMB2_CREATE_APP_INSTANCE_ID */
842 		case 0xB982D0B7: /* SMB2_CREATE_APP_INSTANCE_VERSION */
843 		case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */
844 			cce = NULL;
845 			break;
846 
847 		default:
848 			/*
849 			 * Unknown create context values are normal, and
850 			 * should be ignored.  However, in debug mode,
851 			 * let's log them so we know which ones we're
852 			 * not handling (and may want to add).
853 			 */
854 #ifdef	DEBUG
855 			cmn_err(CE_NOTE, "unknown create context ID 0x%x",
856 			    cc_name.i);
857 #endif
858 			cce = NULL;
859 			break;
860 		}
861 
862 		if (cce == NULL || data_len == 0)
863 			goto next_cc;
864 
865 		if ((data_off & 7) != 0)
866 			break;
867 		if ((top_offset + data_off) < in_mbc->chain_offset)
868 			break;
869 		rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
870 		    top_offset + data_off, data_len);
871 		if (rc)
872 			break;
873 		cce->cce_len = data_len;
874 
875 		/*
876 		 * Additonal decoding for some create contexts.
877 		 */
878 		switch (cc_name.i) {
879 			uint64_t nttime;
880 
881 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
882 			op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
883 			if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0)
884 				goto errout;
885 			break;
886 
887 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
888 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
889 			if (rc != 0)
890 				goto errout;
891 			break;
892 
893 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
894 			/*
895 			 * The SMB spec says this can be either 0 bytes
896 			 * (handled above) or an 8 byte timestamp value
897 			 * but does not say what its purpose is.
898 			 *
899 			 * Note: The WPTS expects us to validate that it
900 			 * is at least 8 bytes so we read it and discard
901 			 * it.  If it was too short the decode will fail.
902 			 */
903 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &nttime);
904 			if (rc != 0)
905 				goto errout;
906 			break;
907 
908 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
909 			/*
910 			 * Support for opening "Previous Versions".
911 			 * [MS-SMB2] 2.2.13.2.7  Data is an NT time.
912 			 */
913 			rc = smb_mbc_decodef(&cce->cce_mbc,
914 			    "q", &nttime);
915 			if (rc != 0)
916 				goto errout;
917 			smb_time_nt_to_unix(nttime, &op->timewarp);
918 			op->create_timewarp = B_TRUE;
919 			break;
920 
921 		/*
922 		 * Note: This handles both V1 and V2 leases,
923 		 * which differ only by their length.
924 		 */
925 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
926 			if (data_len == 52) {
927 				op->lease_version = 2;
928 			} else if (data_len == 32) {
929 				op->lease_version = 1;
930 			} else {
931 				cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x",
932 				    data_len);
933 			}
934 			rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq",
935 			    UUID_LEN,			/* # */
936 			    op->lease_key,		/* c */
937 			    &op->lease_state,		/* l */
938 			    &op->lease_flags,		/* l */
939 			    &nttime);	/* (ignored)	   q */
940 			if (rc != 0)
941 				goto errout;
942 			if (op->lease_version == 2) {
943 				rc = smb_mbc_decodef(&cce->cce_mbc,
944 				    "#cw..",
945 				    UUID_LEN,
946 				    op->parent_lease_key,
947 				    &op->lease_epoch);
948 				if (rc != 0)
949 					goto errout;
950 			} else {
951 				bzero(op->parent_lease_key, UUID_LEN);
952 			}
953 			break;
954 
955 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
956 			rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl",
957 			    &op->dh_fileid.persistent,	/* q */
958 			    &op->dh_fileid.temporal,	/* q */
959 			    UUID_LEN,			/* # */
960 			    op->create_guid,		/* c */
961 			    &op->dh_v2_flags);		/* l */
962 			if (rc != 0)
963 				goto errout;
964 			break;
965 
966 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
967 			rc = smb_mbc_decodef(&cce->cce_mbc, "qq",
968 			    &op->dh_fileid.persistent, /* q */
969 			    &op->dh_fileid.temporal); /* q */
970 			if (rc != 0)
971 				goto errout;
972 			bzero(op->create_guid, UUID_LEN);
973 			op->dh_v2_flags = 0;
974 			break;
975 
976 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
977 			rc = smb_mbc_decodef(&cce->cce_mbc,
978 			    "ll8.#c",
979 			    &op->dh_timeout,	/* l */
980 			    &op->dh_v2_flags,	/* l */
981 			    /* reserved */	/* 8. */
982 			    UUID_LEN, /* # */
983 			    op->create_guid); /* c */
984 			if (rc != 0)
985 				goto errout;
986 			break;
987 
988 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
989 			rc = smb_mbc_decodef(&cce->cce_mbc,
990 			    "16."); /* reserved */
991 			if (rc != 0)
992 				goto errout;
993 			op->dh_timeout = 0;	/* default */
994 			op->dh_v2_flags = 0;
995 			break;
996 		}
997 
998 	next_cc:
999 		if (next_off == 0) {
1000 			/* Normal loop termination */
1001 			status = 0;
1002 			break;
1003 		}
1004 
1005 		if ((next_off & 7) != 0)
1006 			break;
1007 		if ((top_offset + next_off) < in_mbc->chain_offset)
1008 			break;
1009 		if ((top_offset + next_off) > in_mbc->max_bytes)
1010 			break;
1011 		in_mbc->chain_offset = top_offset + next_off;
1012 	}
1013 
1014 errout:
1015 	return (status);
1016 }
1017 
1018 /*
1019  * Encode an SMB2 Create Context buffer from our internal form.
1020  *
1021  * Build the Create Context to return; first the
1022  * per-element parts, then the aggregated buffer.
1023  *
1024  * No response for these:
1025  *	CCTX_EA_BUFFER
1026  *	CCTX_SD_BUFFER
1027  *	CCTX_ALLOCATION_SIZE
1028  *	CCTX_TIMEWARP_TOKEN
1029  *
1030  * Remember to add code sections to smb2_free_create_ctx()
1031  * for each section here that encodes a context element.
1032  */
1033 static uint32_t
1034 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
1035 {
1036 	smb_arg_open_t *op = &sr->arg.open;
1037 	smb2_create_ctx_elem_t *cce;
1038 	mbuf_chain_t *mbc = &sr->raw_data;
1039 	int last_top = -1;
1040 	int rc;
1041 
1042 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1043 		cce = &cc->cc_out_max_access;
1044 
1045 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1046 		(void) smb_mbc_encodef(&cce->cce_mbc,
1047 		    "ll", 0, op->maximum_access);
1048 
1049 		last_top = mbc->chain_offset;
1050 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1051 		    SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
1052 		if (rc)
1053 			return (NT_STATUS_INTERNAL_ERROR);
1054 		(void) smb_mbc_poke(mbc, last_top, "l",
1055 		    mbc->chain_offset - last_top);
1056 	}
1057 
1058 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1059 		cce = &cc->cc_out_file_id;
1060 
1061 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
1062 		(void) smb_mbc_encodef(
1063 		    &cce->cce_mbc, "qll.15.",
1064 		    op->fileid,			/* q */
1065 		    op->op_fsid.val[0],		/* l */
1066 		    op->op_fsid.val[1]);	/* l */
1067 		    /* reserved (16 bytes)	.15. */
1068 
1069 		last_top = mbc->chain_offset;
1070 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1071 		    SMB2_CREATE_QUERY_ON_DISK_ID);
1072 		if (rc)
1073 			return (NT_STATUS_INTERNAL_ERROR);
1074 		(void) smb_mbc_poke(mbc, last_top, "l",
1075 		    mbc->chain_offset - last_top);
1076 	}
1077 
1078 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1079 		cce = &cc->cc_out_aapl;
1080 		/* cc_out_aapl already encoded */
1081 
1082 		last_top = mbc->chain_offset;
1083 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1084 		    SMB2_CREATE_CTX_AAPL);
1085 		if (rc)
1086 			return (NT_STATUS_INTERNAL_ERROR);
1087 		(void) smb_mbc_poke(mbc, last_top, "l",
1088 		    mbc->chain_offset - last_top);
1089 	}
1090 
1091 	if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
1092 		cce = &cc->cc_out_req_lease;
1093 
1094 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
1095 		(void) smb_mbc_encodef(&cce->cce_mbc, "#cllq",
1096 		    UUID_LEN,			/* # */
1097 		    op->lease_key,		/* c */
1098 		    op->lease_state,		/* l */
1099 		    op->lease_flags,		/* l */
1100 		    0LL);			/* q */
1101 		if (op->lease_version == 2) {
1102 			cce->cce_mbc.max_bytes = cce->cce_len = 52;
1103 			(void) smb_mbc_encodef(&cce->cce_mbc,
1104 			    "#cw..",
1105 			    UUID_LEN,
1106 			    op->parent_lease_key,
1107 			    op->lease_epoch);
1108 		}
1109 
1110 		last_top = mbc->chain_offset;
1111 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1112 		    SMB2_CREATE_REQUEST_LEASE);
1113 		if (rc)
1114 			return (NT_STATUS_INTERNAL_ERROR);
1115 		(void) smb_mbc_poke(mbc, last_top, "l",
1116 		    mbc->chain_offset - last_top);
1117 	}
1118 
1119 	if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1120 		cce = &cc->cc_out_dh_request;
1121 
1122 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1123 		(void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL);
1124 
1125 		last_top = mbc->chain_offset;
1126 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1127 		    SMB2_CREATE_DURABLE_HANDLE_REQUEST);
1128 		if (rc)
1129 			return (NT_STATUS_INTERNAL_ERROR);
1130 		(void) smb_mbc_poke(mbc, last_top, "l",
1131 		    mbc->chain_offset - last_top);
1132 	}
1133 
1134 	if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1135 		cce = &cc->cc_out_dh_request_v2;
1136 
1137 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1138 		(void) smb_mbc_encodef(&cce->cce_mbc, "ll",
1139 		    op->dh_timeout, op->dh_v2_flags);
1140 
1141 		last_top = mbc->chain_offset;
1142 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1143 		    SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);
1144 		if (rc)
1145 			return (NT_STATUS_INTERNAL_ERROR);
1146 		(void) smb_mbc_poke(mbc, last_top, "l",
1147 		    mbc->chain_offset - last_top);
1148 	}
1149 
1150 	if (last_top >= 0)
1151 		(void) smb_mbc_poke(mbc, last_top, "l", 0);
1152 
1153 	return (0);
1154 }
1155 
1156 static int
1157 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
1158     smb2_create_ctx_elem_t *cce, uint32_t id)
1159 {
1160 	union {
1161 		uint32_t i;
1162 		char ch[4];
1163 	} cc_name;
1164 	int rc;
1165 
1166 	/* as above */
1167 	cc_name.i = htonl(id);
1168 
1169 	/*
1170 	 * This is the header, per [MS-SMB2] 2.2.13.2
1171 	 * Sorry about the fixed offsets.  We know we'll
1172 	 * layout the data part as [name, payload] and
1173 	 * name is a fixed length, so this easy.
1174 	 * The final layout looks like this:
1175 	 *	a: this header (16 bytes)
1176 	 *	b: the name (4 bytes, 4 pad)
1177 	 *	c: the payload (variable)
1178 	 *	d: padding (to align 8)
1179 	 *
1180 	 * Note that "Next elem." is filled in later.
1181 	 */
1182 	rc = smb_mbc_encodef(
1183 	    out_mbc, "lwwwwl",
1184 	    0,		/* Next offset	l */
1185 	    16,		/* NameOffset	w */
1186 	    4,		/* NameLength	w */
1187 	    0,		/* Reserved	w */
1188 	    24,		/* DataOffset	w */
1189 	    cce->cce_len); /* DataLen	l */
1190 	if (rc)
1191 		return (rc);
1192 
1193 	/*
1194 	 * Now the "name" and payload.
1195 	 */
1196 	rc = smb_mbc_encodef(
1197 	    out_mbc, "4c4.#C",
1198 	    cc_name.ch,		/* 4c4. */
1199 	    cce->cce_len,	/* # */
1200 	    &cce->cce_mbc);	/* C */
1201 
1202 	(void) smb_mbc_put_align(out_mbc, 8);
1203 
1204 	return (rc);
1205 }
1206 
1207 static void
1208 smb2_free_create_ctx(smb2_create_ctx_t *cc)
1209 {
1210 	smb2_create_ctx_elem_t *cce;
1211 
1212 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1213 		cce = &cc->cc_out_max_access;
1214 		MBC_FLUSH(&cce->cce_mbc);
1215 	}
1216 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1217 		cce = &cc->cc_out_file_id;
1218 		MBC_FLUSH(&cce->cce_mbc);
1219 	}
1220 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1221 		cce = &cc->cc_out_aapl;
1222 		MBC_FLUSH(&cce->cce_mbc);
1223 	}
1224 	if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
1225 		cce = &cc->cc_out_req_lease;
1226 		MBC_FLUSH(&cce->cce_mbc);
1227 	}
1228 	if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1229 		cce = &cc->cc_out_dh_request;
1230 		MBC_FLUSH(&cce->cce_mbc);
1231 	}
1232 	if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1233 		cce = &cc->cc_out_dh_request_v2;
1234 		MBC_FLUSH(&cce->cce_mbc);
1235 	}
1236 }
1237