xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_create.c (revision 17a5fa85fe0c34b1146222e40a80b42f2aae8500)
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 /*
25  * Some flags used locally to keep track of which Create Context
26  * names have been provided and/or requested.
27  */
28 #define	CCTX_EA_BUFFER			1
29 #define	CCTX_SD_BUFFER			2
30 #define	CCTX_DH_REQUEST			4
31 #define	CCTX_DH_RECONNECT		8
32 #define	CCTX_ALLOCATION_SIZE		0x10
33 #define	CCTX_QUERY_MAX_ACCESS		0x20
34 #define	CCTX_TIMEWARP_TOKEN		0x40
35 #define	CCTX_QUERY_ON_DISK_ID		0x80
36 #define	CCTX_REQUEST_LEASE		0x100
37 #define	CCTX_AAPL_EXT			0x200
38 
39 typedef struct smb2_create_ctx_elem {
40 	uint32_t cce_len;
41 	mbuf_chain_t cce_mbc;
42 } smb2_create_ctx_elem_t;
43 
44 typedef struct smb2_create_ctx {
45 	mbuf_chain_t cc_in_mbc;
46 	uint_t	cc_in_flags;	/* CCTX_... */
47 	uint_t	cc_out_flags;	/* CCTX_... */
48 	/* Elements we may see in the request. */
49 	smb2_create_ctx_elem_t cc_in_ext_attr;
50 	smb2_create_ctx_elem_t cc_in_sec_desc;
51 	smb2_create_ctx_elem_t cc_in_dh_request;
52 	smb2_create_ctx_elem_t cc_in_dh_reconnect;
53 	smb2_create_ctx_elem_t cc_in_alloc_size;
54 	smb2_create_ctx_elem_t cc_in_time_warp;
55 	smb2_create_ctx_elem_t cc_in_req_lease;
56 	smb2_create_ctx_elem_t cc_in_aapl;
57 	/* Elements we my place in the response */
58 	smb2_create_ctx_elem_t cc_out_max_access;
59 	smb2_create_ctx_elem_t cc_out_file_id;
60 	smb2_create_ctx_elem_t cc_out_aapl;
61 } smb2_create_ctx_t;
62 
63 static uint32_t smb2_decode_create_ctx(
64 	smb_request_t *, smb2_create_ctx_t *);
65 static uint32_t smb2_encode_create_ctx(
66 	smb_request_t *, smb2_create_ctx_t *);
67 static int smb2_encode_create_ctx_elem(
68 	mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
69 static void smb2_free_create_ctx(smb2_create_ctx_t *);
70 
71 smb_sdrc_t
72 smb2_create(smb_request_t *sr)
73 {
74 	smb_attr_t *attr;
75 	smb2_create_ctx_elem_t *cce;
76 	smb2_create_ctx_t cctx;
77 	smb_arg_open_t *op = &sr->arg.open;
78 	smb_ofile_t *of = NULL;
79 	uint16_t StructSize;
80 	uint8_t SecurityFlags;
81 	uint8_t OplockLevel;
82 	uint32_t ImpersonationLevel;
83 	uint64_t SmbCreateFlags;
84 	uint64_t Reserved4;
85 	uint16_t NameOffset;
86 	uint16_t NameLength;
87 	uint32_t CreateCtxOffset;
88 	uint32_t CreateCtxLength;
89 	smb2fid_t smb2fid;
90 	uint32_t status;
91 	int skip;
92 	int rc = 0;
93 
94 	bzero(&cctx, sizeof (cctx));
95 	op->create_ctx = &cctx;	/* for debugging */
96 
97 	/*
98 	 * Paranoia.  This will set sr->fid_ofile, so
99 	 * if we already have one, release it now.
100 	 */
101 	if (sr->fid_ofile != NULL) {
102 		smb_ofile_request_complete(sr->fid_ofile);
103 		smb_ofile_release(sr->fid_ofile);
104 		sr->fid_ofile = NULL;
105 	}
106 
107 	/*
108 	 * Decode the SMB2 Create request
109 	 *
110 	 * Most decode errors return SDRC_ERROR, but
111 	 * for some we give a more specific error.
112 	 *
113 	 * In the "decode section" (starts here) any
114 	 * errors should either return SDRC_ERROR, or
115 	 * if any cleanup is needed, goto errout.
116 	 */
117 	rc = smb_mbc_decodef(
118 	    &sr->smb_data, "wbblqqlllllwwll",
119 	    &StructSize,		/* w */
120 	    &SecurityFlags,		/* b */
121 	    &op->op_oplock_level,	/* b */
122 	    &ImpersonationLevel,	/* l */
123 	    &SmbCreateFlags,		/* q */
124 	    &Reserved4,			/* q */
125 	    &op->desired_access,	/* l */
126 	    &op->dattr,			/* l */
127 	    &op->share_access,		/* l */
128 	    &op->create_disposition,	/* l */
129 	    &op->create_options,	/* l */
130 	    &NameOffset,		/* w */
131 	    &NameLength,		/* w */
132 	    &CreateCtxOffset,		/* l */
133 	    &CreateCtxLength);		/* l */
134 	if (rc != 0 || StructSize != 57)
135 		return (SDRC_ERROR);
136 
137 	/*
138 	 * We're normally positioned at the path name now,
139 	 * but there could be some padding before it.
140 	 */
141 	skip = (NameOffset + sr->smb2_cmd_hdr) -
142 	    sr->smb_data.chain_offset;
143 	if (skip < 0)
144 		return (SDRC_ERROR);
145 	if (skip > 0)
146 		(void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
147 
148 	/*
149 	 * Get the path name
150 	 *
151 	 * Name too long is not technically a decode error,
152 	 * but it's very rare, so we'll just skip the
153 	 * dtrace probes for this error case.
154 	 */
155 	if (NameLength >= SMB_MAXPATHLEN) {
156 		status = NT_STATUS_OBJECT_PATH_INVALID;
157 		goto errout;
158 	}
159 	if (NameLength == 0) {
160 		op->fqi.fq_path.pn_path = "\\";
161 	} else {
162 		rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
163 		    NameLength, &op->fqi.fq_path.pn_path);
164 		if (rc) {
165 			status = NT_STATUS_OBJECT_PATH_INVALID;
166 			goto errout;
167 		}
168 	}
169 	op->fqi.fq_dnode = sr->tid_tree->t_snode;
170 
171 	/*
172 	 * If there is a "Create Context" payload, decode it.
173 	 * This may carry things like a security descriptor,
174 	 * extended attributes, etc. to be used in create.
175 	 *
176 	 * The create ctx buffer must start after the headers
177 	 * and file name, and must be 8-byte aligned.
178 	 */
179 	if (CreateCtxLength != 0) {
180 		if ((CreateCtxOffset & 7) != 0 ||
181 		    (CreateCtxOffset + sr->smb2_cmd_hdr) <
182 		    sr->smb_data.chain_offset) {
183 			status = NT_STATUS_INVALID_PARAMETER;
184 			goto errout;
185 		}
186 
187 		rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data,
188 		    sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
189 		if (rc) {
190 			status = NT_STATUS_INVALID_PARAMETER;
191 			goto errout;
192 		}
193 		status = smb2_decode_create_ctx(sr, &cctx);
194 		if (status)
195 			goto errout;
196 	}
197 
198 	/*
199 	 * Everything is decoded into some internal form, so
200 	 * in this probe one can look at sr->arg.open etc.
201 	 *
202 	 * This marks the end of the "decode" section and the
203 	 * beginning of the "body" section.  Any errors in
204 	 * this section should use: goto cmd_done (which is
205 	 * just before the dtrace "done" probe).
206 	 */
207 	DTRACE_SMB2_START(op__Create, smb_request_t *, sr); /* arg.open */
208 
209 	/*
210 	 * Process the incoming create contexts (already decoded),
211 	 * that need action before the open, starting with the
212 	 * Durable Handle ones, which may override others.
213 	 */
214 
215 	/*
216 	 * Validate the requested oplock level.
217 	 * Convert the SMB2 oplock level into SMB1 form.
218 	 */
219 	switch (op->op_oplock_level) {
220 	case SMB2_OPLOCK_LEVEL_NONE:
221 		op->op_oplock_level = SMB_OPLOCK_NONE;
222 		break;
223 	case SMB2_OPLOCK_LEVEL_II:
224 		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
225 		break;
226 	case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
227 		op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
228 		break;
229 	case SMB2_OPLOCK_LEVEL_BATCH:
230 		op->op_oplock_level = SMB_OPLOCK_BATCH;
231 		break;
232 	case SMB2_OPLOCK_LEVEL_LEASE:	/* not yet */
233 	default:
234 		/* Unknown SMB2 oplock level. */
235 		status = NT_STATUS_INVALID_PARAMETER;
236 		goto cmd_done;
237 	}
238 	op->op_oplock_levelII = B_TRUE;
239 
240 	/*
241 	 * Only disk trees get oplocks or leases.
242 	 */
243 	if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
244 		op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
245 		cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
246 	}
247 
248 	if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
249 		status = NT_STATUS_EAS_NOT_SUPPORTED;
250 		goto cmd_done;
251 	}
252 
253 	/*
254 	 * ImpersonationLevel (spec. says validate + ignore)
255 	 * SmbCreateFlags (spec. says ignore)
256 	 */
257 
258 	if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
259 	    !(op->desired_access & DELETE)) {
260 		status = NT_STATUS_INVALID_PARAMETER;
261 		goto cmd_done;
262 	}
263 
264 	if (op->dattr & FILE_FLAG_WRITE_THROUGH)
265 		op->create_options |= FILE_WRITE_THROUGH;
266 	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
267 		op->create_options |= FILE_DELETE_ON_CLOSE;
268 	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
269 		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
270 	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
271 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
272 	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
273 		status = NT_STATUS_INVALID_PARAMETER;
274 		goto cmd_done;
275 	}
276 
277 	/*
278 	 * The real open call.   Note: this gets attributes into
279 	 * op->fqi.fq_fattr (SMB_AT_ALL).  We need those below.
280 	 * When of != NULL, goto errout closes it.
281 	 */
282 	status = smb_common_open(sr);
283 	if (status != NT_STATUS_SUCCESS)
284 		goto cmd_done;
285 	of = sr->fid_ofile;
286 
287 	/*
288 	 * NB: after the above smb_common_open() success,
289 	 * we have a handle allocated (sr->fid_ofile).
290 	 * If we don't return success, we must close it.
291 	 *
292 	 * Using sr->smb_fid as the file handle for now,
293 	 * though it could later be something larger,
294 	 * (16 bytes) similar to an NFSv4 open handle.
295 	 */
296 	smb2fid.persistent = 0;
297 	smb2fid.temporal = sr->smb_fid;
298 
299 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
300 	case STYPE_DISKTREE:
301 	case STYPE_PRINTQ:
302 		if (op->create_options & FILE_DELETE_ON_CLOSE)
303 			smb_ofile_set_delete_on_close(of);
304 		break;
305 	}
306 
307 	/*
308 	 * Process any outgoing create contexts that need work
309 	 * after the open succeeds.  Encode happens later.
310 	 */
311 	if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
312 		op->maximum_access = 0;
313 		if (of->f_node != NULL) {
314 			smb_fsop_eaccess(sr, of->f_cr, of->f_node,
315 			    &op->maximum_access);
316 		}
317 		op->maximum_access |= of->f_granted_access;
318 		cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
319 	}
320 
321 	if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
322 	    of->f_node != NULL) {
323 		op->op_fsid = SMB_NODE_FSID(of->f_node);
324 		cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
325 	}
326 
327 	if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) {
328 		cce = &cctx.cc_out_aapl;
329 		/*
330 		 * smb2_aapl_crctx has a variable response depending on
331 		 * what the incoming context looks like, so it does all
332 		 * the work of building cc_out_aapl, including setting
333 		 * cce_len, cce_mbc.max_bytes, and smb_mbc_encode.
334 		 * If we see errors getting this, simply omit it from
335 		 * the collection of returned create contexts.
336 		 */
337 		status = smb2_aapl_crctx(sr,
338 		    &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc);
339 		if (status == 0) {
340 			cce->cce_len = cce->cce_mbc.chain_offset;
341 			cctx.cc_out_flags |= CCTX_AAPL_EXT;
342 		}
343 		status = 0;
344 	}
345 
346 	/*
347 	 * This marks the end of the "body" section and the
348 	 * beginning of the "encode" section.  Any errors
349 	 * encoding the response should use: goto errout
350 	 */
351 cmd_done:
352 	/* Want status visible in the done probe. */
353 	sr->smb2_status = status;
354 	DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr);
355 	if (status != NT_STATUS_SUCCESS)
356 		goto errout;
357 
358 	/*
359 	 * Encode all the create contexts to return.
360 	 */
361 	if (cctx.cc_out_flags) {
362 		sr->raw_data.max_bytes = smb2_max_trans;
363 		status = smb2_encode_create_ctx(sr, &cctx);
364 		if (status)
365 			goto errout;
366 	}
367 
368 	/*
369 	 * Convert the negotiated Oplock level back into
370 	 * SMB2 encoding form.
371 	 */
372 	switch (op->op_oplock_level) {
373 	default:
374 	case SMB_OPLOCK_NONE:
375 		OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
376 		break;
377 	case SMB_OPLOCK_LEVEL_II:
378 		OplockLevel = SMB2_OPLOCK_LEVEL_II;
379 		break;
380 	case SMB_OPLOCK_EXCLUSIVE:
381 		OplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
382 		break;
383 	case SMB_OPLOCK_BATCH:
384 		OplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
385 		break;
386 	}
387 
388 	/*
389 	 * Encode the SMB2 Create reply
390 	 */
391 	attr = &op->fqi.fq_fattr;
392 	rc = smb_mbc_encodef(
393 	    &sr->reply,
394 	    "wb.lTTTTqqllqqll",
395 	    89,	/* StructSize */	/* w */
396 	    OplockLevel,		/* b */
397 	    op->action_taken,		/* l */
398 	    &attr->sa_crtime,		/* T */
399 	    &attr->sa_vattr.va_atime,	/* T */
400 	    &attr->sa_vattr.va_mtime,	/* T */
401 	    &attr->sa_vattr.va_ctime,	/* T */
402 	    attr->sa_allocsz,		/* q */
403 	    attr->sa_vattr.va_size,	/* q */
404 	    attr->sa_dosattr,		/* l */
405 	    0, /* reserved2 */		/* l */
406 	    smb2fid.persistent,		/* q */
407 	    smb2fid.temporal,		/* q */
408 	    0,  /* CreateCtxOffset	   l */
409 	    0); /* CreateCtxLength	   l */
410 	if (rc != 0) {
411 		status = NT_STATUS_UNSUCCESSFUL;
412 		goto errout;
413 	}
414 
415 	CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
416 	CreateCtxLength = MBC_LENGTH(&sr->raw_data);
417 	if (CreateCtxLength != 0) {
418 		/*
419 		 * Overwrite CreateCtxOffset, CreateCtxLength, pad
420 		 */
421 		sr->reply.chain_offset -= 8;
422 		rc = smb_mbc_encodef(
423 		    &sr->reply,
424 		    "ll#C",
425 		    CreateCtxOffset,	/* l */
426 		    CreateCtxLength,	/* l */
427 		    CreateCtxLength,	/* # */
428 		    &sr->raw_data);	/* C */
429 		if (rc != 0) {
430 			status = NT_STATUS_UNSUCCESSFUL;
431 			goto errout;
432 		}
433 	} else {
434 		(void) smb_mbc_encodef(&sr->reply, ".");
435 	}
436 
437 	if (status != 0) {
438 	errout:
439 		if (of != NULL)
440 			smb_ofile_close(of, 0);
441 		smb2sr_put_error(sr, status);
442 	}
443 	if (op->sd != NULL) {
444 		smb_sd_term(op->sd);
445 		kmem_free(op->sd, sizeof (*op->sd));
446 	}
447 	if (cctx.cc_out_flags)
448 		smb2_free_create_ctx(&cctx);
449 
450 	return (SDRC_SUCCESS);
451 }
452 
453 /*
454  * Decode an SMB2 Create Context buffer into our internal form.
455  * Avoid policy decisions about what's supported here, just decode.
456  */
457 static uint32_t
458 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
459 {
460 	smb_arg_open_t *op = &sr->arg.open;
461 	smb2_create_ctx_elem_t *cce;
462 	mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
463 	mbuf_chain_t name_mbc;
464 	union {
465 		uint32_t i;
466 		char ch[4];
467 	} cc_name;
468 	uint32_t status;
469 	int32_t next_off;
470 	uint32_t data_len;
471 	uint16_t data_off;
472 	uint16_t name_off;
473 	uint16_t name_len;
474 	int top_offset;
475 	int rc;
476 
477 	/*
478 	 * Any break from the loop below before we've decoded
479 	 * the entire create context means it was malformatted,
480 	 * so we should return INVALID_PARAMETER.
481 	 */
482 	status = NT_STATUS_INVALID_PARAMETER;
483 	for (;;) {
484 		cce = NULL;
485 		top_offset = in_mbc->chain_offset;
486 		rc = smb_mbc_decodef(
487 		    in_mbc,
488 		    "lww..wl",
489 		    &next_off,	/* l */
490 		    &name_off,	/* w */
491 		    &name_len,	/* w */
492 		    /* reserved	  .. */
493 		    &data_off,	/* w */
494 		    &data_len); /* l */
495 		if (rc)
496 			break;
497 
498 		/*
499 		 * The Create Context "name", per [MS-SMB] 2.2.13.2
500 		 * They're defined as network-order integers for our
501 		 * switch below.  We don't have routines to decode
502 		 * native order, so read as char[4] then ntohl.
503 		 * NB: in SMB3, some of these are 8 bytes.
504 		 */
505 		if ((top_offset + name_off) < in_mbc->chain_offset)
506 			break;
507 		rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc,
508 		    top_offset + name_off, name_len);
509 		if (rc)
510 			break;
511 		rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name);
512 		if (rc)
513 			break;
514 		cc_name.i = ntohl(cc_name.i);
515 
516 		switch (cc_name.i) {
517 		case SMB2_CREATE_EA_BUFFER:		/* ("ExtA") */
518 			cc->cc_in_flags |= CCTX_EA_BUFFER;
519 			cce = &cc->cc_in_ext_attr;
520 			break;
521 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
522 			cc->cc_in_flags |= CCTX_SD_BUFFER;
523 			cce = &cc->cc_in_sec_desc;
524 			break;
525 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
526 			cc->cc_in_flags |= CCTX_DH_REQUEST;
527 			cce = &cc->cc_in_dh_request;
528 			break;
529 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
530 			cc->cc_in_flags |= CCTX_DH_RECONNECT;
531 			cce = &cc->cc_in_dh_reconnect;
532 			break;
533 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
534 			cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
535 			cce = &cc->cc_in_alloc_size;
536 			break;
537 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
538 			cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
539 			/* no input data for this */
540 			break;
541 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
542 			cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
543 			cce = &cc->cc_in_time_warp;
544 			break;
545 		case SMB2_CREATE_QUERY_ON_DISK_ID:	/* ("QFid") */
546 			cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
547 			/* no input data for this */
548 			break;
549 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
550 			cc->cc_in_flags |= CCTX_REQUEST_LEASE;
551 			cce = &cc->cc_in_req_lease;
552 			break;
553 		case SMB2_CREATE_CTX_AAPL:		/* ("AAPL") */
554 			cc->cc_in_flags |= CCTX_AAPL_EXT;
555 			cce = &cc->cc_in_aapl;
556 			break;
557 		default:
558 			/*
559 			 * Unknown create context values are normal, and
560 			 * should be ignored.  However, in debug mode,
561 			 * let's log them so we know which ones we're
562 			 * not handling (and may want to add).
563 			 */
564 #ifdef	DEBUG
565 			cmn_err(CE_NOTE, "unknown create context ID 0x%x",
566 			    cc_name.i);
567 #endif
568 			cce = NULL;
569 			break;
570 		}
571 
572 		if (cce == NULL || data_len == 0)
573 			goto next_cc;
574 
575 		if ((data_off & 7) != 0)
576 			break;
577 		if ((top_offset + data_off) < in_mbc->chain_offset)
578 			break;
579 		rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
580 		    top_offset + data_off, data_len);
581 		if (rc)
582 			break;
583 		cce->cce_len = data_len;
584 
585 		/*
586 		 * Additonal decoding for some create contexts.
587 		 */
588 		switch (cc_name.i) {
589 			uint64_t nttime;
590 
591 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
592 			op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
593 			if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0)
594 				goto errout;
595 			break;
596 
597 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
598 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
599 			if (rc != 0)
600 				goto errout;
601 			break;
602 
603 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
604 			/*
605 			 * Support for opening "Previous Versions".
606 			 * [MS-SMB2] 2.2.13.2.7  Data is an NT time.
607 			 */
608 			rc = smb_mbc_decodef(&cce->cce_mbc,
609 			    "q", &nttime);
610 			if (rc != 0)
611 				goto errout;
612 			smb_time_nt_to_unix(nttime, &op->timewarp);
613 			op->create_timewarp = B_TRUE;
614 			break;
615 
616 		}
617 
618 	next_cc:
619 		if (next_off == 0) {
620 			/* Normal loop termination */
621 			status = 0;
622 			break;
623 		}
624 
625 		if ((next_off & 7) != 0)
626 			break;
627 		if ((top_offset + next_off) < in_mbc->chain_offset)
628 			break;
629 		if ((top_offset + next_off) > in_mbc->max_bytes)
630 			break;
631 		in_mbc->chain_offset = top_offset + next_off;
632 	}
633 
634 errout:
635 	return (status);
636 }
637 
638 /*
639  * Encode an SMB2 Create Context buffer from our internal form.
640  *
641  * Build the Create Context to return; first the
642  * per-element parts, then the aggregated buffer.
643  *
644  * No response for these:
645  *	CCTX_EA_BUFFER
646  *	CCTX_SD_BUFFER
647  *	CCTX_ALLOCATION_SIZE
648  *	CCTX_TIMEWARP_TOKEN
649  *
650  * Remember to add code sections to smb2_free_create_ctx()
651  * for each section here that encodes a context element.
652  */
653 static uint32_t
654 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
655 {
656 	smb_arg_open_t *op = &sr->arg.open;
657 	smb2_create_ctx_elem_t *cce;
658 	mbuf_chain_t *mbc = &sr->raw_data;
659 	int last_top = -1;
660 	int rc;
661 
662 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
663 		cce = &cc->cc_out_max_access;
664 
665 		cce->cce_mbc.max_bytes = cce->cce_len = 8;
666 		(void) smb_mbc_encodef(&cce->cce_mbc,
667 		    "ll", 0, op->maximum_access);
668 
669 		last_top = mbc->chain_offset;
670 		rc = smb2_encode_create_ctx_elem(mbc, cce,
671 		    SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
672 		if (rc)
673 			return (NT_STATUS_INTERNAL_ERROR);
674 		(void) smb_mbc_poke(mbc, last_top, "l",
675 		    mbc->chain_offset - last_top);
676 	}
677 
678 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
679 		cce = &cc->cc_out_file_id;
680 
681 		cce->cce_mbc.max_bytes = cce->cce_len = 32;
682 		(void) smb_mbc_encodef(
683 		    &cce->cce_mbc, "qll.15.",
684 		    op->fileid,			/* q */
685 		    op->op_fsid.val[0],		/* l */
686 		    op->op_fsid.val[1]);	/* l */
687 		    /* reserved (16 bytes)	.15. */
688 
689 		last_top = mbc->chain_offset;
690 		rc = smb2_encode_create_ctx_elem(mbc, cce,
691 		    SMB2_CREATE_QUERY_ON_DISK_ID);
692 		if (rc)
693 			return (NT_STATUS_INTERNAL_ERROR);
694 		(void) smb_mbc_poke(mbc, last_top, "l",
695 		    mbc->chain_offset - last_top);
696 	}
697 
698 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
699 		cce = &cc->cc_out_aapl;
700 		/* cc_out_aapl already encoded */
701 
702 		last_top = mbc->chain_offset;
703 		rc = smb2_encode_create_ctx_elem(mbc, cce,
704 		    SMB2_CREATE_CTX_AAPL);
705 		if (rc)
706 			return (NT_STATUS_INTERNAL_ERROR);
707 		(void) smb_mbc_poke(mbc, last_top, "l",
708 		    mbc->chain_offset - last_top);
709 	}
710 
711 	if (last_top >= 0)
712 		(void) smb_mbc_poke(mbc, last_top, "l", 0);
713 
714 	return (0);
715 }
716 
717 static int
718 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
719     smb2_create_ctx_elem_t *cce, uint32_t id)
720 {
721 	union {
722 		uint32_t i;
723 		char ch[4];
724 	} cc_name;
725 	int rc;
726 
727 	/* as above */
728 	cc_name.i = htonl(id);
729 
730 	/*
731 	 * This is the header, per [MS-SMB2] 2.2.13.2
732 	 * Sorry about the fixed offsets.  We know we'll
733 	 * layout the data part as [name, payload] and
734 	 * name is a fixed length, so this easy.
735 	 * The final layout looks like this:
736 	 *	a: this header (16 bytes)
737 	 *	b: the name (4 bytes, 4 pad)
738 	 *	c: the payload (variable)
739 	 *
740 	 * Note that "Next elem." is filled in later.
741 	 */
742 	rc = smb_mbc_encodef(
743 	    out_mbc, "lwwwwl",
744 	    0,		/* Next offset	l */
745 	    16,		/* NameOffset	w */
746 	    4,		/* NameLength	w */
747 	    0,		/* Reserved	w */
748 	    24,		/* DataOffset	w */
749 	    cce->cce_len); /* DataLen	l */
750 	if (rc)
751 		return (rc);
752 
753 	/*
754 	 * Now the "name" and payload.
755 	 */
756 	rc = smb_mbc_encodef(
757 	    out_mbc, "4c4.#C",
758 	    cc_name.ch,		/* 4c4. */
759 	    cce->cce_len,	/* # */
760 	    &cce->cce_mbc);	/* C */
761 
762 	return (rc);
763 }
764 
765 static void
766 smb2_free_create_ctx(smb2_create_ctx_t *cc)
767 {
768 	smb2_create_ctx_elem_t *cce;
769 
770 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
771 		cce = &cc->cc_out_max_access;
772 		MBC_FLUSH(&cce->cce_mbc);
773 	}
774 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
775 		cce = &cc->cc_out_file_id;
776 		MBC_FLUSH(&cce->cce_mbc);
777 	}
778 	if (cc->cc_out_flags & CCTX_AAPL_EXT) {
779 		cce = &cc->cc_out_aapl;
780 		MBC_FLUSH(&cce->cce_mbc);
781 	}
782 }
783