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