xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_create.c (revision 19fa1385c0e0ac6b45d333702468f04c026d3f30)
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-2024 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
smb2_create(smb_request_t * sr)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 	 * Ignore lease or oplock requests for anything other than
474 	 * plain files. The share type was checked above, but the
475 	 * node pointer of->f_node is only valid for "disk" files.
476 	 */
477 	if (of->f_ftype != SMB_FTYPE_DISK ||
478 	    !smb_node_is_file(of->f_node)) {
479 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
480 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
481 	}
482 
483 	/*
484 	 * [MS-SMB2] 3.3.5.9.8
485 	 * Handling the SMB2_CREATE_REQUEST_LEASE Create Context
486 	 */
487 	if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0) {
488 		status = smb2_lease_create(sr, sr->session->clnt_uuid);
489 		if (status != NT_STATUS_SUCCESS) {
490 			if (op->action_taken == SMB_OACT_CREATED) {
491 				smb_ofile_set_delete_on_close(sr, of);
492 			}
493 			goto cmd_done;
494 		}
495 	}
496 	if (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
497 		smb2_lease_acquire(sr);
498 	} else if (op->op_oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
499 		smb2_oplock_acquire(sr);
500 	}
501 
502 	/*
503 	 * If requested and allowed, make this a durable open;
504 	 * see comment above smb_dh_create_allowed() for more detail.
505 	 *
506 	 * Otherwise, DH requests are ignored, so we set
507 	 * dh_vers = not durable
508 	 */
509 	if ((cctx.cc_in_flags &
510 	    (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0 &&
511 	    smb_dh_create_allowed(sr, of)) {
512 		/*
513 		 * OK, make this handle "durable"
514 		 */
515 		if (op->dh_vers == SMB2_DURABLE_V2) {
516 			(void) memcpy(of->dh_create_guid,
517 			    op->create_guid, UUID_LEN);
518 
519 			if ((op->dh_v2_flags & DH_PERSISTENT) != 0) {
520 				if (smb2_dh_make_persistent(sr, of) == 0) {
521 					of->dh_persist = B_TRUE;
522 				} else {
523 					op->dh_v2_flags = 0;
524 				}
525 			}
526 		}
527 		if (op->dh_vers != SMB2_NOT_DURABLE) {
528 			uint32_t msto;
529 
530 			of->dh_vers = op->dh_vers;
531 			of->dh_expire_time = 0;
532 
533 			/*
534 			 * Client may provide timeout=0 to request
535 			 * the default timeout (in mSec.)
536 			 */
537 			msto = op->dh_timeout;
538 			if (msto == 0) {
539 				msto = (of->dh_persist) ?
540 				    smb2_persist_timeout :
541 				    smb2_dh_def_timeout;
542 			}
543 			if (msto > smb2_dh_max_timeout)
544 				msto = smb2_dh_max_timeout;
545 			op->dh_timeout = msto;
546 			of->dh_timeout_offset = MSEC2NSEC(msto);
547 		}
548 	} else {
549 		op->dh_vers = SMB2_NOT_DURABLE;
550 		op->dh_v2_flags = 0;
551 	}
552 
553 	/*
554 	 * NB: after the above smb_common_open() success,
555 	 * we have a handle allocated (sr->fid_ofile).
556 	 * If we don't return success, we must close it.
557 	 *
558 	 * Using sr->smb_fid as the file handle for now,
559 	 * though it could later be something larger,
560 	 * (16 bytes) similar to an NFSv4 open handle.
561 	 */
562 reconnect_done:
563 	smb2fid.persistent = of->f_persistid;
564 	smb2fid.temporal = sr->smb_fid;
565 
566 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
567 	case STYPE_DISKTREE:
568 	case STYPE_PRINTQ:
569 		if (op->create_options & FILE_DELETE_ON_CLOSE)
570 			smb_ofile_set_delete_on_close(sr, of);
571 		break;
572 	}
573 
574 	/*
575 	 * Process any outgoing create contexts that need work
576 	 * after the open succeeds.  Encode happens later.
577 	 */
578 	if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
579 		op->maximum_access = 0;
580 		if (of->f_node != NULL) {
581 			smb_fsop_eaccess(sr, of->f_cr, of->f_node,
582 			    &op->maximum_access);
583 		}
584 		op->maximum_access |= of->f_granted_access;
585 		cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
586 	}
587 
588 	if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
589 	    of->f_node != NULL) {
590 		op->op_fsid = SMB_NODE_FSID(of->f_node);
591 		cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
592 	}
593 
594 	if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) {
595 		cce = &cctx.cc_out_aapl;
596 		/*
597 		 * smb2_aapl_crctx has a variable response depending on
598 		 * what the incoming context looks like, so it does all
599 		 * the work of building cc_out_aapl, including setting
600 		 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode.
601 		 * If we see errors getting this, simply omit it from
602 		 * the collection of returned create contexts.
603 		 */
604 		status = smb2_aapl_crctx(sr,
605 		    &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc);
606 		if (status == 0) {
607 			cce->cce_len = cce->cce_mbc.chain_offset;
608 			cctx.cc_out_flags |= CCTX_AAPL_EXT;
609 		}
610 		status = 0;
611 	}
612 
613 	/*
614 	 * If a lease was requested, and we got one...
615 	 */
616 	if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0 &&
617 	    op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE)
618 		cctx.cc_out_flags |= CCTX_REQUEST_LEASE;
619 
620 	/*
621 	 * If a durable handle was requested and we got one...
622 	 */
623 	if ((cctx.cc_in_flags & CCTX_DH_REQUEST) != 0 &&
624 	    of->dh_vers == SMB2_DURABLE_V1) {
625 		cctx.cc_out_flags |= CCTX_DH_REQUEST;
626 	}
627 	if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0 &&
628 	    of->dh_vers == SMB2_DURABLE_V2) {
629 		cctx.cc_out_flags |= CCTX_DH_REQUEST_V2;
630 	}
631 
632 	/*
633 	 * This marks the end of the "body" section and the
634 	 * beginning of the "encode" section.  Any errors
635 	 * encoding the response should use: goto errout
636 	 */
637 cmd_done:
638 	/* Want status visible in the done probe. */
639 	sr->smb2_status = status;
640 	DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr);
641 	if (status != NT_STATUS_SUCCESS)
642 		goto errout;
643 
644 	/*
645 	 * Encode all the create contexts to return.
646 	 */
647 	if (cctx.cc_out_flags) {
648 		sr->raw_data.max_bytes = smb2_max_trans;
649 		status = smb2_encode_create_ctx(sr, &cctx);
650 		if (status)
651 			goto errout;
652 	}
653 
654 	/*
655 	 * Encode the SMB2 Create reply
656 	 */
657 	attr = &op->fqi.fq_fattr;
658 	rc = smb_mbc_encodef(
659 	    &sr->reply,
660 	    "wb.lTTTTqqllqqll",
661 	    89,	/* StructSize */	/* w */
662 	    op->op_oplock_level,	/* b */
663 	    op->action_taken,		/* l */
664 	    &attr->sa_crtime,		/* T */
665 	    &attr->sa_vattr.va_atime,	/* T */
666 	    &attr->sa_vattr.va_mtime,	/* T */
667 	    &attr->sa_vattr.va_ctime,	/* T */
668 	    attr->sa_allocsz,		/* q */
669 	    attr->sa_vattr.va_size,	/* q */
670 	    attr->sa_dosattr,		/* l */
671 	    0, /* reserved2 */		/* l */
672 	    smb2fid.persistent,		/* q */
673 	    smb2fid.temporal,		/* q */
674 	    0,  /* CreateCtxOffset	   l */
675 	    0); /* CreateCtxLength	   l */
676 	if (rc != 0) {
677 		status = NT_STATUS_UNSUCCESSFUL;
678 		goto errout;
679 	}
680 
681 	CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
682 	CreateCtxLength = MBC_LENGTH(&sr->raw_data);
683 	if (CreateCtxLength != 0) {
684 		/*
685 		 * Overwrite CreateCtxOffset, CreateCtxLength, pad
686 		 */
687 		sr->reply.chain_offset -= 8;
688 		rc = smb_mbc_encodef(
689 		    &sr->reply,
690 		    "ll#C",
691 		    CreateCtxOffset,	/* l */
692 		    CreateCtxLength,	/* l */
693 		    CreateCtxLength,	/* # */
694 		    &sr->raw_data);	/* C */
695 		if (rc != 0) {
696 			status = NT_STATUS_UNSUCCESSFUL;
697 			goto errout;
698 		}
699 	} else {
700 		(void) smb_mbc_encodef(&sr->reply, ".");
701 	}
702 
703 	if (status != 0) {
704 	errout:
705 		if (of != NULL)
706 			smb_ofile_close(of, 0);
707 		smb2sr_put_error(sr, status);
708 	}
709 	if (op->sd != NULL) {
710 		smb_sd_term(op->sd);
711 		kmem_free(op->sd, sizeof (*op->sd));
712 	}
713 	if (cctx.cc_out_flags)
714 		smb2_free_create_ctx(&cctx);
715 
716 	return (SDRC_SUCCESS);
717 }
718 
719 /*
720  * Decode an SMB2 Create Context buffer into our internal form.
721  * Avoid policy decisions about what's supported here, just decode.
722  */
723 static uint32_t
smb2_decode_create_ctx(smb_request_t * sr,smb2_create_ctx_t * cc)724 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
725 {
726 	smb_arg_open_t *op = &sr->arg.open;
727 	smb2_create_ctx_elem_t *cce;
728 	mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
729 	mbuf_chain_t name_mbc;
730 	union {
731 		uint32_t i;
732 		char ch[4];
733 	} cc_name;
734 	uint32_t status;
735 	int32_t next_off;
736 	uint32_t data_len;
737 	uint16_t data_off;
738 	uint16_t name_off;
739 	uint16_t name_len;
740 	int top_offset;
741 	int rc;
742 
743 	/*
744 	 * Any break from the loop below before we've decoded
745 	 * the entire create context means it was malformatted,
746 	 * so we should return INVALID_PARAMETER.
747 	 */
748 	status = NT_STATUS_INVALID_PARAMETER;
749 	for (;;) {
750 		cce = NULL;
751 		top_offset = in_mbc->chain_offset;
752 		rc = smb_mbc_decodef(
753 		    in_mbc,
754 		    "lww..wl",
755 		    &next_off,	/* l */
756 		    &name_off,	/* w */
757 		    &name_len,	/* w */
758 		    /* reserved	  .. */
759 		    &data_off,	/* w */
760 		    &data_len); /* l */
761 		if (rc)
762 			break;
763 
764 		/*
765 		 * The Create Context "name", per [MS-SMB] 2.2.13.2
766 		 * They're defined as network-order integers for our
767 		 * switch below.  We don't have routines to decode
768 		 * native order, so read as char[4] then ntohl.
769 		 * NB: in SMB3, some of these are 8 bytes.
770 		 */
771 		if ((top_offset + name_off) < in_mbc->chain_offset)
772 			break;
773 		rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc,
774 		    top_offset + name_off, name_len);
775 		if (rc)
776 			break;
777 		rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name);
778 		if (rc)
779 			break;
780 		cc_name.i = ntohl(cc_name.i);
781 
782 		switch (cc_name.i) {
783 		case SMB2_CREATE_EA_BUFFER:		/* ("ExtA") */
784 			cc->cc_in_flags |= CCTX_EA_BUFFER;
785 			cce = &cc->cc_in_ext_attr;
786 			break;
787 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
788 			cc->cc_in_flags |= CCTX_SD_BUFFER;
789 			cce = &cc->cc_in_sec_desc;
790 			break;
791 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
792 			cc->cc_in_flags |= CCTX_DH_REQUEST;
793 			cce = &cc->cc_in_dh_request;
794 			break;
795 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
796 			cc->cc_in_flags |= CCTX_DH_RECONNECT;
797 			cce = &cc->cc_in_dh_reconnect;
798 			break;
799 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
800 			cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
801 			cce = &cc->cc_in_alloc_size;
802 			break;
803 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
804 			cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
805 			/* Optional input data for this CC. See below. */
806 			cce = &cc->cc_in_max_access;
807 			break;
808 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
809 			cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
810 			cce = &cc->cc_in_time_warp;
811 			break;
812 		case SMB2_CREATE_QUERY_ON_DISK_ID:	/* ("QFid") */
813 			cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
814 			/* no input data for this */
815 			break;
816 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
817 			cc->cc_in_flags |= CCTX_REQUEST_LEASE;
818 			cce = &cc->cc_in_req_lease;
819 			break;
820 		case SMB2_CREATE_CTX_AAPL:		/* ("AAPL") */
821 			cc->cc_in_flags |= CCTX_AAPL_EXT;
822 			cce = &cc->cc_in_aapl;
823 			break;
824 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
825 			cc->cc_in_flags |= CCTX_DH_REQUEST_V2;
826 			cce = &cc->cc_in_dh_request_v2;
827 			break;
828 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
829 			cc->cc_in_flags |= CCTX_DH_RECONNECT_V2;
830 			cce = &cc->cc_in_dh_reconnect_v2;
831 			break;
832 
833 		/*
834 		 * Known but not implemented context IDs.
835 		 * Here just to silence the debug below.
836 		 *
837 		 * Note: all three of these IDs are actually longer,
838 		 * but we start by decoding just the first 4 bytes.
839 		 * If/when we recognize these, do another match on
840 		 * the full ID after we take this switch case.
841 		 */
842 		case 0x45bca66a: /* SMB2_CREATE_APP_INSTANCE_ID */
843 		case 0xB982D0B7: /* SMB2_CREATE_APP_INSTANCE_VERSION */
844 		case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */
845 			cce = NULL;
846 			break;
847 
848 		default:
849 			/*
850 			 * Unknown create context values are normal, and
851 			 * should be ignored.  However, in debug mode,
852 			 * let's log them so we know which ones we're
853 			 * not handling (and may want to add).
854 			 */
855 #ifdef	DEBUG
856 			cmn_err(CE_NOTE, "unknown create context ID 0x%x",
857 			    cc_name.i);
858 #endif
859 			cce = NULL;
860 			break;
861 		}
862 
863 		if (cce == NULL || data_len == 0)
864 			goto next_cc;
865 
866 		if ((data_off & 7) != 0)
867 			break;
868 		if ((top_offset + data_off) < in_mbc->chain_offset)
869 			break;
870 		rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
871 		    top_offset + data_off, data_len);
872 		if (rc)
873 			break;
874 		cce->cce_len = data_len;
875 
876 		/*
877 		 * Additonal decoding for some create contexts.
878 		 */
879 		switch (cc_name.i) {
880 			uint64_t nttime;
881 
882 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
883 			op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
884 			if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0)
885 				goto errout;
886 			break;
887 
888 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
889 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
890 			if (rc != 0)
891 				goto errout;
892 			break;
893 
894 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
895 			/*
896 			 * The SMB spec says this can be either 0 bytes
897 			 * (handled above) or an 8 byte timestamp value
898 			 * but does not say what its purpose is.
899 			 *
900 			 * Note: The WPTS expects us to validate that it
901 			 * is at least 8 bytes so we read it and discard
902 			 * it.  If it was too short the decode will fail.
903 			 */
904 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &nttime);
905 			if (rc != 0)
906 				goto errout;
907 			break;
908 
909 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
910 			/*
911 			 * Support for opening "Previous Versions".
912 			 * [MS-SMB2] 2.2.13.2.7  Data is an NT time.
913 			 */
914 			rc = smb_mbc_decodef(&cce->cce_mbc,
915 			    "q", &nttime);
916 			if (rc != 0)
917 				goto errout;
918 			smb_time_nt_to_unix(nttime, &op->timewarp);
919 			op->create_timewarp = B_TRUE;
920 			break;
921 
922 		/*
923 		 * Note: This handles both V1 and V2 leases,
924 		 * which differ only by their length.
925 		 */
926 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
927 			if (data_len == 52) {
928 				op->lease_version = 2;
929 			} else if (data_len == 32) {
930 				op->lease_version = 1;
931 			} else {
932 				cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x",
933 				    data_len);
934 			}
935 			rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq",
936 			    UUID_LEN,			/* # */
937 			    op->lease_key,		/* c */
938 			    &op->lease_state,		/* l */
939 			    &op->lease_flags,		/* l */
940 			    &nttime);	/* (ignored)	   q */
941 			if (rc != 0)
942 				goto errout;
943 			if (op->lease_version == 2) {
944 				rc = smb_mbc_decodef(&cce->cce_mbc,
945 				    "#cw..",
946 				    UUID_LEN,
947 				    op->parent_lease_key,
948 				    &op->lease_epoch);
949 				if (rc != 0)
950 					goto errout;
951 			} else {
952 				bzero(op->parent_lease_key, UUID_LEN);
953 			}
954 			break;
955 
956 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
957 			rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl",
958 			    &op->dh_fileid.persistent,	/* q */
959 			    &op->dh_fileid.temporal,	/* q */
960 			    UUID_LEN,			/* # */
961 			    op->create_guid,		/* c */
962 			    &op->dh_v2_flags);		/* l */
963 			if (rc != 0)
964 				goto errout;
965 			break;
966 
967 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
968 			rc = smb_mbc_decodef(&cce->cce_mbc, "qq",
969 			    &op->dh_fileid.persistent, /* q */
970 			    &op->dh_fileid.temporal); /* q */
971 			if (rc != 0)
972 				goto errout;
973 			bzero(op->create_guid, UUID_LEN);
974 			op->dh_v2_flags = 0;
975 			break;
976 
977 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
978 			rc = smb_mbc_decodef(&cce->cce_mbc,
979 			    "ll8.#c",
980 			    &op->dh_timeout,	/* l */
981 			    &op->dh_v2_flags,	/* l */
982 			    /* reserved */	/* 8. */
983 			    UUID_LEN, /* # */
984 			    op->create_guid); /* c */
985 			if (rc != 0)
986 				goto errout;
987 			break;
988 
989 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
990 			rc = smb_mbc_decodef(&cce->cce_mbc,
991 			    "16."); /* reserved */
992 			if (rc != 0)
993 				goto errout;
994 			op->dh_timeout = 0;	/* default */
995 			op->dh_v2_flags = 0;
996 			break;
997 		}
998 
999 	next_cc:
1000 		if (next_off == 0) {
1001 			/* Normal loop termination */
1002 			status = 0;
1003 			break;
1004 		}
1005 
1006 		if ((next_off & 7) != 0)
1007 			break;
1008 		if ((top_offset + next_off) < in_mbc->chain_offset)
1009 			break;
1010 		if ((top_offset + next_off) > in_mbc->max_bytes)
1011 			break;
1012 		in_mbc->chain_offset = top_offset + next_off;
1013 	}
1014 
1015 errout:
1016 	return (status);
1017 }
1018 
1019 /*
1020  * Encode an SMB2 Create Context buffer from our internal form.
1021  *
1022  * Build the Create Context to return; first the
1023  * per-element parts, then the aggregated buffer.
1024  *
1025  * No response for these:
1026  *	CCTX_EA_BUFFER
1027  *	CCTX_SD_BUFFER
1028  *	CCTX_ALLOCATION_SIZE
1029  *	CCTX_TIMEWARP_TOKEN
1030  *
1031  * Remember to add code sections to smb2_free_create_ctx()
1032  * for each section here that encodes a context element.
1033  */
1034 static uint32_t
smb2_encode_create_ctx(smb_request_t * sr,smb2_create_ctx_t * cc)1035 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
1036 {
1037 	smb_arg_open_t *op = &sr->arg.open;
1038 	smb2_create_ctx_elem_t *cce;
1039 	mbuf_chain_t *mbc = &sr->raw_data;
1040 	int last_top = -1;
1041 	int rc;
1042 
1043 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1044 		cce = &cc->cc_out_max_access;
1045 
1046 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1047 		(void) smb_mbc_encodef(&cce->cce_mbc,
1048 		    "ll", 0, op->maximum_access);
1049 
1050 		last_top = mbc->chain_offset;
1051 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1052 		    SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
1053 		if (rc)
1054 			return (NT_STATUS_INTERNAL_ERROR);
1055 		(void) smb_mbc_poke(mbc, last_top, "l",
1056 		    mbc->chain_offset - last_top);
1057 	}
1058 
1059 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1060 		cce = &cc->cc_out_file_id;
1061 
1062 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
1063 		(void) smb_mbc_encodef(
1064 		    &cce->cce_mbc, "qll.15.",
1065 		    op->fileid,			/* q */
1066 		    op->op_fsid.val[0],		/* l */
1067 		    op->op_fsid.val[1]);	/* l */
1068 		    /* reserved (16 bytes)	.15. */
1069 
1070 		last_top = mbc->chain_offset;
1071 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1072 		    SMB2_CREATE_QUERY_ON_DISK_ID);
1073 		if (rc)
1074 			return (NT_STATUS_INTERNAL_ERROR);
1075 		(void) smb_mbc_poke(mbc, last_top, "l",
1076 		    mbc->chain_offset - last_top);
1077 	}
1078 
1079 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1080 		cce = &cc->cc_out_aapl;
1081 		/* cc_out_aapl already encoded */
1082 
1083 		last_top = mbc->chain_offset;
1084 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1085 		    SMB2_CREATE_CTX_AAPL);
1086 		if (rc)
1087 			return (NT_STATUS_INTERNAL_ERROR);
1088 		(void) smb_mbc_poke(mbc, last_top, "l",
1089 		    mbc->chain_offset - last_top);
1090 	}
1091 
1092 	if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
1093 		cce = &cc->cc_out_req_lease;
1094 
1095 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
1096 		(void) smb_mbc_encodef(&cce->cce_mbc, "#cllq",
1097 		    UUID_LEN,			/* # */
1098 		    op->lease_key,		/* c */
1099 		    op->lease_state,		/* l */
1100 		    op->lease_flags,		/* l */
1101 		    0LL);			/* q */
1102 		if (op->lease_version == 2) {
1103 			cce->cce_mbc.max_bytes = cce->cce_len = 52;
1104 			(void) smb_mbc_encodef(&cce->cce_mbc,
1105 			    "#cw..",
1106 			    UUID_LEN,
1107 			    op->parent_lease_key,
1108 			    op->lease_epoch);
1109 		}
1110 
1111 		last_top = mbc->chain_offset;
1112 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1113 		    SMB2_CREATE_REQUEST_LEASE);
1114 		if (rc)
1115 			return (NT_STATUS_INTERNAL_ERROR);
1116 		(void) smb_mbc_poke(mbc, last_top, "l",
1117 		    mbc->chain_offset - last_top);
1118 	}
1119 
1120 	if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1121 		cce = &cc->cc_out_dh_request;
1122 
1123 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1124 		(void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL);
1125 
1126 		last_top = mbc->chain_offset;
1127 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1128 		    SMB2_CREATE_DURABLE_HANDLE_REQUEST);
1129 		if (rc)
1130 			return (NT_STATUS_INTERNAL_ERROR);
1131 		(void) smb_mbc_poke(mbc, last_top, "l",
1132 		    mbc->chain_offset - last_top);
1133 	}
1134 
1135 	if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1136 		cce = &cc->cc_out_dh_request_v2;
1137 
1138 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
1139 		(void) smb_mbc_encodef(&cce->cce_mbc, "ll",
1140 		    op->dh_timeout, op->dh_v2_flags);
1141 
1142 		last_top = mbc->chain_offset;
1143 		rc = smb2_encode_create_ctx_elem(mbc, cce,
1144 		    SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);
1145 		if (rc)
1146 			return (NT_STATUS_INTERNAL_ERROR);
1147 		(void) smb_mbc_poke(mbc, last_top, "l",
1148 		    mbc->chain_offset - last_top);
1149 	}
1150 
1151 	if (last_top >= 0)
1152 		(void) smb_mbc_poke(mbc, last_top, "l", 0);
1153 
1154 	return (0);
1155 }
1156 
1157 static int
smb2_encode_create_ctx_elem(mbuf_chain_t * out_mbc,smb2_create_ctx_elem_t * cce,uint32_t id)1158 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
1159     smb2_create_ctx_elem_t *cce, uint32_t id)
1160 {
1161 	union {
1162 		uint32_t i;
1163 		char ch[4];
1164 	} cc_name;
1165 	int rc;
1166 
1167 	/* as above */
1168 	cc_name.i = htonl(id);
1169 
1170 	/*
1171 	 * This is the header, per [MS-SMB2] 2.2.13.2
1172 	 * Sorry about the fixed offsets.  We know we'll
1173 	 * layout the data part as [name, payload] and
1174 	 * name is a fixed length, so this easy.
1175 	 * The final layout looks like this:
1176 	 *	a: this header (16 bytes)
1177 	 *	b: the name (4 bytes, 4 pad)
1178 	 *	c: the payload (variable)
1179 	 *	d: padding (to align 8)
1180 	 *
1181 	 * Note that "Next elem." is filled in later.
1182 	 */
1183 	rc = smb_mbc_encodef(
1184 	    out_mbc, "lwwwwl",
1185 	    0,		/* Next offset	l */
1186 	    16,		/* NameOffset	w */
1187 	    4,		/* NameLength	w */
1188 	    0,		/* Reserved	w */
1189 	    24,		/* DataOffset	w */
1190 	    cce->cce_len); /* DataLen	l */
1191 	if (rc)
1192 		return (rc);
1193 
1194 	/*
1195 	 * Now the "name" and payload.
1196 	 */
1197 	rc = smb_mbc_encodef(
1198 	    out_mbc, "4c4.#C",
1199 	    cc_name.ch,		/* 4c4. */
1200 	    cce->cce_len,	/* # */
1201 	    &cce->cce_mbc);	/* C */
1202 
1203 	(void) smb_mbc_put_align(out_mbc, 8);
1204 
1205 	return (rc);
1206 }
1207 
1208 static void
smb2_free_create_ctx(smb2_create_ctx_t * cc)1209 smb2_free_create_ctx(smb2_create_ctx_t *cc)
1210 {
1211 	smb2_create_ctx_elem_t *cce;
1212 
1213 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1214 		cce = &cc->cc_out_max_access;
1215 		MBC_FLUSH(&cce->cce_mbc);
1216 	}
1217 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1218 		cce = &cc->cc_out_file_id;
1219 		MBC_FLUSH(&cce->cce_mbc);
1220 	}
1221 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1222 		cce = &cc->cc_out_aapl;
1223 		MBC_FLUSH(&cce->cce_mbc);
1224 	}
1225 	if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
1226 		cce = &cc->cc_out_req_lease;
1227 		MBC_FLUSH(&cce->cce_mbc);
1228 	}
1229 	if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1230 		cce = &cc->cc_out_dh_request;
1231 		MBC_FLUSH(&cce->cce_mbc);
1232 	}
1233 	if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1234 		cce = &cc->cc_out_dh_request_v2;
1235 		MBC_FLUSH(&cce->cce_mbc);
1236 	}
1237 }
1238