xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb2_create.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
1*a90cf9f2SGordon Ross /*
2*a90cf9f2SGordon Ross  * This file and its contents are supplied under the terms of the
3*a90cf9f2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4*a90cf9f2SGordon Ross  * You may only use this file in accordance with the terms of version
5*a90cf9f2SGordon Ross  * 1.0 of the CDDL.
6*a90cf9f2SGordon Ross  *
7*a90cf9f2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8*a90cf9f2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9*a90cf9f2SGordon Ross  * http://www.illumos.org/license/CDDL.
10*a90cf9f2SGordon Ross  */
11*a90cf9f2SGordon Ross 
12*a90cf9f2SGordon Ross /*
13*a90cf9f2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
14*a90cf9f2SGordon Ross  */
15*a90cf9f2SGordon Ross 
16*a90cf9f2SGordon Ross /*
17*a90cf9f2SGordon Ross  * Dispatch function for SMB2_CREATE
18*a90cf9f2SGordon Ross  * [MS-SMB2] 2.2.13
19*a90cf9f2SGordon Ross  */
20*a90cf9f2SGordon Ross 
21*a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h>
22*a90cf9f2SGordon Ross #include <smbsrv/smb_fsops.h>
23*a90cf9f2SGordon Ross 
24*a90cf9f2SGordon Ross /*
25*a90cf9f2SGordon Ross  * Some flags used locally to keep track of which Create Context
26*a90cf9f2SGordon Ross  * names have been provided and/or requested.
27*a90cf9f2SGordon Ross  */
28*a90cf9f2SGordon Ross #define	CCTX_EA_BUFFER			1
29*a90cf9f2SGordon Ross #define	CCTX_SD_BUFFER			2
30*a90cf9f2SGordon Ross #define	CCTX_DH_REQUEST			4
31*a90cf9f2SGordon Ross #define	CCTX_DH_RECONNECT		8
32*a90cf9f2SGordon Ross #define	CCTX_ALLOCATION_SIZE		0x10
33*a90cf9f2SGordon Ross #define	CCTX_QUERY_MAX_ACCESS		0x20
34*a90cf9f2SGordon Ross #define	CCTX_TIMEWARP_TOKEN		0x40
35*a90cf9f2SGordon Ross #define	CCTX_QUERY_ON_DISK_ID		0x80
36*a90cf9f2SGordon Ross #define	CCTX_REQUEST_LEASE		0x100
37*a90cf9f2SGordon Ross 
38*a90cf9f2SGordon Ross 
39*a90cf9f2SGordon Ross typedef struct smb2_create_ctx_elem {
40*a90cf9f2SGordon Ross 	uint32_t cce_len;
41*a90cf9f2SGordon Ross 	mbuf_chain_t cce_mbc;
42*a90cf9f2SGordon Ross } smb2_create_ctx_elem_t;
43*a90cf9f2SGordon Ross 
44*a90cf9f2SGordon Ross typedef struct smb2_create_ctx {
45*a90cf9f2SGordon Ross 	uint_t	cc_in_flags;	/* CCTX_... */
46*a90cf9f2SGordon Ross 	uint_t	cc_out_flags;	/* CCTX_... */
47*a90cf9f2SGordon Ross 	/* Elements we may see in the request. */
48*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_ext_attr;
49*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_sec_desc;
50*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_dh_request;
51*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_dh_reconnect;
52*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_alloc_size;
53*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_time_warp;
54*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_in_req_lease;
55*a90cf9f2SGordon Ross 	/* Elements we my place in the response */
56*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_out_max_access;
57*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t cc_out_file_id;
58*a90cf9f2SGordon Ross } smb2_create_ctx_t;
59*a90cf9f2SGordon Ross 
60*a90cf9f2SGordon Ross static uint32_t smb2_decode_create_ctx(
61*a90cf9f2SGordon Ross 	mbuf_chain_t *,	smb2_create_ctx_t *);
62*a90cf9f2SGordon Ross static uint32_t smb2_encode_create_ctx(
63*a90cf9f2SGordon Ross 	mbuf_chain_t *, smb2_create_ctx_t *);
64*a90cf9f2SGordon Ross static int smb2_encode_create_ctx_elem(
65*a90cf9f2SGordon Ross 	mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
66*a90cf9f2SGordon Ross static void smb2_free_create_ctx(smb2_create_ctx_t *);
67*a90cf9f2SGordon Ross 
68*a90cf9f2SGordon Ross smb_sdrc_t
69*a90cf9f2SGordon Ross smb2_create(smb_request_t *sr)
70*a90cf9f2SGordon Ross {
71*a90cf9f2SGordon Ross 	smb_attr_t *attr;
72*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce;
73*a90cf9f2SGordon Ross 	smb2_create_ctx_t cctx;
74*a90cf9f2SGordon Ross 	mbuf_chain_t cc_mbc;
75*a90cf9f2SGordon Ross 	smb_arg_open_t *op = &sr->arg.open;
76*a90cf9f2SGordon Ross 	smb_ofile_t *of = NULL;
77*a90cf9f2SGordon Ross 	uint16_t StructSize;
78*a90cf9f2SGordon Ross 	uint8_t SecurityFlags;
79*a90cf9f2SGordon Ross 	uint8_t OplockLevel;
80*a90cf9f2SGordon Ross 	uint32_t ImpersonationLevel;
81*a90cf9f2SGordon Ross 	uint64_t SmbCreateFlags;
82*a90cf9f2SGordon Ross 	uint64_t Reserved4;
83*a90cf9f2SGordon Ross 	uint16_t NameOffset;
84*a90cf9f2SGordon Ross 	uint16_t NameLength;
85*a90cf9f2SGordon Ross 	uint32_t CreateCtxOffset;
86*a90cf9f2SGordon Ross 	uint32_t CreateCtxLength;
87*a90cf9f2SGordon Ross 	smb2fid_t smb2fid;
88*a90cf9f2SGordon Ross 	uint32_t status;
89*a90cf9f2SGordon Ross 	int skip;
90*a90cf9f2SGordon Ross 	int rc = 0;
91*a90cf9f2SGordon Ross 
92*a90cf9f2SGordon Ross 	bzero(&cctx, sizeof (cctx));
93*a90cf9f2SGordon Ross 	bzero(&cc_mbc, sizeof (cc_mbc));
94*a90cf9f2SGordon Ross 
95*a90cf9f2SGordon Ross 	/*
96*a90cf9f2SGordon Ross 	 * Paranoia.  This will set sr->fid_ofile, so
97*a90cf9f2SGordon Ross 	 * if we already have one, release it now.
98*a90cf9f2SGordon Ross 	 */
99*a90cf9f2SGordon Ross 	if (sr->fid_ofile != NULL) {
100*a90cf9f2SGordon Ross 		smb_ofile_request_complete(sr->fid_ofile);
101*a90cf9f2SGordon Ross 		smb_ofile_release(sr->fid_ofile);
102*a90cf9f2SGordon Ross 		sr->fid_ofile = NULL;
103*a90cf9f2SGordon Ross 	}
104*a90cf9f2SGordon Ross 
105*a90cf9f2SGordon Ross 	/*
106*a90cf9f2SGordon Ross 	 * SMB2 Create request
107*a90cf9f2SGordon Ross 	 */
108*a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(
109*a90cf9f2SGordon Ross 	    &sr->smb_data, "wbblqqlllllwwll",
110*a90cf9f2SGordon Ross 	    &StructSize,		/* w */
111*a90cf9f2SGordon Ross 	    &SecurityFlags,		/* b */
112*a90cf9f2SGordon Ross 	    &OplockLevel,		/* b */
113*a90cf9f2SGordon Ross 	    &ImpersonationLevel,	/* l */
114*a90cf9f2SGordon Ross 	    &SmbCreateFlags,		/* q */
115*a90cf9f2SGordon Ross 	    &Reserved4,			/* q */
116*a90cf9f2SGordon Ross 	    &op->desired_access,	/* l */
117*a90cf9f2SGordon Ross 	    &op->dattr,			/* l */
118*a90cf9f2SGordon Ross 	    &op->share_access,		/* l */
119*a90cf9f2SGordon Ross 	    &op->create_disposition,	/* l */
120*a90cf9f2SGordon Ross 	    &op->create_options,	/* l */
121*a90cf9f2SGordon Ross 	    &NameOffset,		/* w */
122*a90cf9f2SGordon Ross 	    &NameLength,		/* w */
123*a90cf9f2SGordon Ross 	    &CreateCtxOffset,		/* l */
124*a90cf9f2SGordon Ross 	    &CreateCtxLength);		/* l */
125*a90cf9f2SGordon Ross 	if (rc != 0 || StructSize != 57)
126*a90cf9f2SGordon Ross 		return (SDRC_ERROR);
127*a90cf9f2SGordon Ross 
128*a90cf9f2SGordon Ross 	/*
129*a90cf9f2SGordon Ross 	 * We're normally positioned at the path name now,
130*a90cf9f2SGordon Ross 	 * but there could be some padding before it.
131*a90cf9f2SGordon Ross 	 */
132*a90cf9f2SGordon Ross 	skip = (NameOffset + sr->smb2_cmd_hdr) -
133*a90cf9f2SGordon Ross 	    sr->smb_data.chain_offset;
134*a90cf9f2SGordon Ross 	if (skip < 0) {
135*a90cf9f2SGordon Ross 		status = NT_STATUS_OBJECT_PATH_INVALID;
136*a90cf9f2SGordon Ross 		goto errout;
137*a90cf9f2SGordon Ross 	}
138*a90cf9f2SGordon Ross 	if (skip > 0)
139*a90cf9f2SGordon Ross 		(void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
140*a90cf9f2SGordon Ross 
141*a90cf9f2SGordon Ross 	/*
142*a90cf9f2SGordon Ross 	 * Get the path name
143*a90cf9f2SGordon Ross 	 */
144*a90cf9f2SGordon Ross 	if (NameLength >= SMB_MAXPATHLEN) {
145*a90cf9f2SGordon Ross 		status = NT_STATUS_OBJECT_PATH_INVALID;
146*a90cf9f2SGordon Ross 		goto errout;
147*a90cf9f2SGordon Ross 	}
148*a90cf9f2SGordon Ross 	if (NameLength == 0) {
149*a90cf9f2SGordon Ross 		op->fqi.fq_path.pn_path = "\\";
150*a90cf9f2SGordon Ross 	} else {
151*a90cf9f2SGordon Ross 		rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
152*a90cf9f2SGordon Ross 		    NameLength, &op->fqi.fq_path.pn_path);
153*a90cf9f2SGordon Ross 		if (rc) {
154*a90cf9f2SGordon Ross 			status = NT_STATUS_OBJECT_PATH_INVALID;
155*a90cf9f2SGordon Ross 			goto errout;
156*a90cf9f2SGordon Ross 		}
157*a90cf9f2SGordon Ross 	}
158*a90cf9f2SGordon Ross 	op->fqi.fq_dnode = sr->tid_tree->t_snode;
159*a90cf9f2SGordon Ross 
160*a90cf9f2SGordon Ross 	switch (OplockLevel) {
161*a90cf9f2SGordon Ross 	case SMB2_OPLOCK_LEVEL_NONE:
162*a90cf9f2SGordon Ross 		op->op_oplock_level = SMB_OPLOCK_NONE;
163*a90cf9f2SGordon Ross 		break;
164*a90cf9f2SGordon Ross 	case SMB2_OPLOCK_LEVEL_II:
165*a90cf9f2SGordon Ross 		op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
166*a90cf9f2SGordon Ross 		break;
167*a90cf9f2SGordon Ross 	case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
168*a90cf9f2SGordon Ross 		op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
169*a90cf9f2SGordon Ross 		break;
170*a90cf9f2SGordon Ross 	case SMB2_OPLOCK_LEVEL_BATCH:
171*a90cf9f2SGordon Ross 		op->op_oplock_level = SMB_OPLOCK_BATCH;
172*a90cf9f2SGordon Ross 		break;
173*a90cf9f2SGordon Ross 	case SMB2_OPLOCK_LEVEL_LEASE:
174*a90cf9f2SGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
175*a90cf9f2SGordon Ross 		goto errout;
176*a90cf9f2SGordon Ross 	}
177*a90cf9f2SGordon Ross 	op->op_oplock_levelII = B_TRUE;
178*a90cf9f2SGordon Ross 
179*a90cf9f2SGordon Ross 	/*
180*a90cf9f2SGordon Ross 	 * ImpersonationLevel (spec. says ignore)
181*a90cf9f2SGordon Ross 	 * SmbCreateFlags (spec. says ignore)
182*a90cf9f2SGordon Ross 	 */
183*a90cf9f2SGordon Ross 
184*a90cf9f2SGordon Ross 	if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
185*a90cf9f2SGordon Ross 	    !(op->desired_access & DELETE)) {
186*a90cf9f2SGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
187*a90cf9f2SGordon Ross 		goto errout;
188*a90cf9f2SGordon Ross 	}
189*a90cf9f2SGordon Ross 	if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
190*a90cf9f2SGordon Ross 		status = NT_STATUS_INVALID_PARAMETER;
191*a90cf9f2SGordon Ross 		goto errout;
192*a90cf9f2SGordon Ross 	}
193*a90cf9f2SGordon Ross 
194*a90cf9f2SGordon Ross 	if (op->dattr & FILE_FLAG_WRITE_THROUGH)
195*a90cf9f2SGordon Ross 		op->create_options |= FILE_WRITE_THROUGH;
196*a90cf9f2SGordon Ross 	if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
197*a90cf9f2SGordon Ross 		op->create_options |= FILE_DELETE_ON_CLOSE;
198*a90cf9f2SGordon Ross 	if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
199*a90cf9f2SGordon Ross 		op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
200*a90cf9f2SGordon Ross 	if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
201*a90cf9f2SGordon Ross 		sr->user_cr = smb_user_getprivcred(sr->uid_user);
202*a90cf9f2SGordon Ross 
203*a90cf9f2SGordon Ross 	/*
204*a90cf9f2SGordon Ross 	 * If there is a "Create Context" payload, decode it.
205*a90cf9f2SGordon Ross 	 * This may carry things like a security descriptor,
206*a90cf9f2SGordon Ross 	 * extended attributes, etc. to be used in create.
207*a90cf9f2SGordon Ross 	 *
208*a90cf9f2SGordon Ross 	 * The create ctx buffer must start after the headers
209*a90cf9f2SGordon Ross 	 * and file name, and must be 8-byte aligned.
210*a90cf9f2SGordon Ross 	 */
211*a90cf9f2SGordon Ross 	if (CreateCtxLength != 0) {
212*a90cf9f2SGordon Ross 		if ((CreateCtxOffset & 7) != 0 ||
213*a90cf9f2SGordon Ross 		    (CreateCtxOffset + sr->smb2_cmd_hdr) <
214*a90cf9f2SGordon Ross 		    sr->smb_data.chain_offset) {
215*a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
216*a90cf9f2SGordon Ross 			goto errout;
217*a90cf9f2SGordon Ross 		}
218*a90cf9f2SGordon Ross 
219*a90cf9f2SGordon Ross 		rc = MBC_SHADOW_CHAIN(&cc_mbc, &sr->smb_data,
220*a90cf9f2SGordon Ross 		    sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
221*a90cf9f2SGordon Ross 		if (rc) {
222*a90cf9f2SGordon Ross 			status = NT_STATUS_INVALID_PARAMETER;
223*a90cf9f2SGordon Ross 			goto errout;
224*a90cf9f2SGordon Ross 		}
225*a90cf9f2SGordon Ross 		status = smb2_decode_create_ctx(&cc_mbc, &cctx);
226*a90cf9f2SGordon Ross 		if (status)
227*a90cf9f2SGordon Ross 			goto errout;
228*a90cf9f2SGordon Ross 
229*a90cf9f2SGordon Ross 		if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
230*a90cf9f2SGordon Ross 			status = NT_STATUS_EAS_NOT_SUPPORTED;
231*a90cf9f2SGordon Ross 			goto errout;
232*a90cf9f2SGordon Ross 		}
233*a90cf9f2SGordon Ross 
234*a90cf9f2SGordon Ross 		if (cctx.cc_in_flags & CCTX_SD_BUFFER) {
235*a90cf9f2SGordon Ross 			smb_sd_t sd;
236*a90cf9f2SGordon Ross 			cce = &cctx.cc_in_sec_desc;
237*a90cf9f2SGordon Ross 			status = smb_decode_sd(
238*a90cf9f2SGordon Ross 			    &cce->cce_mbc, &sd);
239*a90cf9f2SGordon Ross 			if (status)
240*a90cf9f2SGordon Ross 				goto errout;
241*a90cf9f2SGordon Ross 			op->sd = kmem_alloc(sizeof (sd), KM_SLEEP);
242*a90cf9f2SGordon Ross 			*op->sd = sd;
243*a90cf9f2SGordon Ross 		}
244*a90cf9f2SGordon Ross 
245*a90cf9f2SGordon Ross 		if (cctx.cc_in_flags & CCTX_ALLOCATION_SIZE) {
246*a90cf9f2SGordon Ross 			cce = &cctx.cc_in_alloc_size;
247*a90cf9f2SGordon Ross 			rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
248*a90cf9f2SGordon Ross 			if (rc) {
249*a90cf9f2SGordon Ross 				status = NT_STATUS_INVALID_PARAMETER;
250*a90cf9f2SGordon Ross 				goto errout;
251*a90cf9f2SGordon Ross 			}
252*a90cf9f2SGordon Ross 		}
253*a90cf9f2SGordon Ross 
254*a90cf9f2SGordon Ross 		/*
255*a90cf9f2SGordon Ross 		 * Support for opening "Previous Versions".
256*a90cf9f2SGordon Ross 		 * [MS-SMB2] 2.2.13.2.7  Data is an NT time.
257*a90cf9f2SGordon Ross 		 */
258*a90cf9f2SGordon Ross 		if (cctx.cc_in_flags & CCTX_TIMEWARP_TOKEN) {
259*a90cf9f2SGordon Ross 			uint64_t timewarp;
260*a90cf9f2SGordon Ross 			cce = &cctx.cc_in_time_warp;
261*a90cf9f2SGordon Ross 			status = smb_mbc_decodef(&cce->cce_mbc,
262*a90cf9f2SGordon Ross 			    "q", &timewarp);
263*a90cf9f2SGordon Ross 			if (status)
264*a90cf9f2SGordon Ross 				goto errout;
265*a90cf9f2SGordon Ross 			smb_time_nt_to_unix(timewarp, &op->timewarp);
266*a90cf9f2SGordon Ross 			op->create_timewarp = B_TRUE;
267*a90cf9f2SGordon Ross 		}
268*a90cf9f2SGordon Ross 	}
269*a90cf9f2SGordon Ross 
270*a90cf9f2SGordon Ross 	/*
271*a90cf9f2SGordon Ross 	 * The real open call.   Note: this gets attributes into
272*a90cf9f2SGordon Ross 	 * op->fqi.fq_fattr (SMB_AT_ALL).  We need those below.
273*a90cf9f2SGordon Ross 	 */
274*a90cf9f2SGordon Ross 	status = smb_common_open(sr);
275*a90cf9f2SGordon Ross 	if (status != NT_STATUS_SUCCESS)
276*a90cf9f2SGordon Ross 		goto errout;
277*a90cf9f2SGordon Ross 	attr = &op->fqi.fq_fattr;
278*a90cf9f2SGordon Ross 
279*a90cf9f2SGordon Ross 	/*
280*a90cf9f2SGordon Ross 	 * Convert the negotiate Oplock level back into
281*a90cf9f2SGordon Ross 	 * SMB2 encoding form.
282*a90cf9f2SGordon Ross 	 */
283*a90cf9f2SGordon Ross 	switch (op->op_oplock_level) {
284*a90cf9f2SGordon Ross 	default:
285*a90cf9f2SGordon Ross 	case SMB_OPLOCK_NONE:
286*a90cf9f2SGordon Ross 		OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
287*a90cf9f2SGordon Ross 		break;
288*a90cf9f2SGordon Ross 	case SMB_OPLOCK_LEVEL_II:
289*a90cf9f2SGordon Ross 		OplockLevel = SMB2_OPLOCK_LEVEL_II;
290*a90cf9f2SGordon Ross 		break;
291*a90cf9f2SGordon Ross 	case SMB_OPLOCK_EXCLUSIVE:
292*a90cf9f2SGordon Ross 		OplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
293*a90cf9f2SGordon Ross 		break;
294*a90cf9f2SGordon Ross 	case SMB_OPLOCK_BATCH:
295*a90cf9f2SGordon Ross 		OplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
296*a90cf9f2SGordon Ross 		break;
297*a90cf9f2SGordon Ross 	}
298*a90cf9f2SGordon Ross 
299*a90cf9f2SGordon Ross 	/*
300*a90cf9f2SGordon Ross 	 * NB: after the above smb_common_open() success,
301*a90cf9f2SGordon Ross 	 * we have a handle allocated (sr->fid_ofile).
302*a90cf9f2SGordon Ross 	 * If we don't return success, we must close it.
303*a90cf9f2SGordon Ross 	 *
304*a90cf9f2SGordon Ross 	 * Using sr->smb_fid as the file handle for now,
305*a90cf9f2SGordon Ross 	 * though it could later be something larger,
306*a90cf9f2SGordon Ross 	 * (16 bytes) similar to an NFSv4 open handle.
307*a90cf9f2SGordon Ross 	 */
308*a90cf9f2SGordon Ross 	of = sr->fid_ofile;
309*a90cf9f2SGordon Ross 	smb2fid.persistent = 0;
310*a90cf9f2SGordon Ross 	smb2fid.temporal = sr->smb_fid;
311*a90cf9f2SGordon Ross 
312*a90cf9f2SGordon Ross 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
313*a90cf9f2SGordon Ross 	case STYPE_DISKTREE:
314*a90cf9f2SGordon Ross 	case STYPE_PRINTQ:
315*a90cf9f2SGordon Ross 		if (op->create_options & FILE_DELETE_ON_CLOSE)
316*a90cf9f2SGordon Ross 			smb_ofile_set_delete_on_close(of);
317*a90cf9f2SGordon Ross 		break;
318*a90cf9f2SGordon Ross 	}
319*a90cf9f2SGordon Ross 
320*a90cf9f2SGordon Ross 	/*
321*a90cf9f2SGordon Ross 	 * Build the Create Context to return; first the
322*a90cf9f2SGordon Ross 	 * per-element parts, then the aggregated buffer.
323*a90cf9f2SGordon Ross 	 *
324*a90cf9f2SGordon Ross 	 * No response for these:
325*a90cf9f2SGordon Ross 	 *	CCTX_EA_BUFFER
326*a90cf9f2SGordon Ross 	 *	CCTX_SD_BUFFER
327*a90cf9f2SGordon Ross 	 *	CCTX_ALLOCATION_SIZE
328*a90cf9f2SGordon Ross 	 *	CCTX_TIMEWARP_TOKEN
329*a90cf9f2SGordon Ross 	 *
330*a90cf9f2SGordon Ross 	 * We don't handle these yet.
331*a90cf9f2SGordon Ross 	 *	CCTX_DH_REQUEST
332*a90cf9f2SGordon Ross 	 *	CCTX_DH_RECONNECT
333*a90cf9f2SGordon Ross 	 *	CCTX_REQUEST_LEASE
334*a90cf9f2SGordon Ross 	 */
335*a90cf9f2SGordon Ross 	if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
336*a90cf9f2SGordon Ross 		cce = &cctx.cc_out_max_access;
337*a90cf9f2SGordon Ross 		uint32_t MaxAccess = 0;
338*a90cf9f2SGordon Ross 		if (of->f_node != NULL) {
339*a90cf9f2SGordon Ross 			smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);
340*a90cf9f2SGordon Ross 		}
341*a90cf9f2SGordon Ross 		MaxAccess |= of->f_granted_access;
342*a90cf9f2SGordon Ross 		cce->cce_len = 8;
343*a90cf9f2SGordon Ross 		cce->cce_mbc.max_bytes = 8;
344*a90cf9f2SGordon Ross 		(void) smb_mbc_encodef(&cce->cce_mbc,
345*a90cf9f2SGordon Ross 		    "ll", 0, MaxAccess);
346*a90cf9f2SGordon Ross 		cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
347*a90cf9f2SGordon Ross 	}
348*a90cf9f2SGordon Ross 	if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
349*a90cf9f2SGordon Ross 	    of->f_node != NULL) {
350*a90cf9f2SGordon Ross 		cce = &cctx.cc_out_file_id;
351*a90cf9f2SGordon Ross 		fsid_t fsid;
352*a90cf9f2SGordon Ross 
353*a90cf9f2SGordon Ross 		fsid = SMB_NODE_FSID(of->f_node);
354*a90cf9f2SGordon Ross 
355*a90cf9f2SGordon Ross 		cce->cce_len = 32;
356*a90cf9f2SGordon Ross 		cce->cce_mbc.max_bytes = 32;
357*a90cf9f2SGordon Ross 		(void) smb_mbc_encodef(
358*a90cf9f2SGordon Ross 		    &cce->cce_mbc, "qll.15.",
359*a90cf9f2SGordon Ross 		    op->fileid,		/* q */
360*a90cf9f2SGordon Ross 		    fsid.val[0],	/* l */
361*a90cf9f2SGordon Ross 		    fsid.val[1]);	/* l */
362*a90cf9f2SGordon Ross 		/* reserved (16 bytes)  .15. */
363*a90cf9f2SGordon Ross 		cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
364*a90cf9f2SGordon Ross 	}
365*a90cf9f2SGordon Ross 	if (cctx.cc_out_flags) {
366*a90cf9f2SGordon Ross 		sr->raw_data.max_bytes = smb2_max_trans;
367*a90cf9f2SGordon Ross 		status = smb2_encode_create_ctx(&sr->raw_data, &cctx);
368*a90cf9f2SGordon Ross 		if (status)
369*a90cf9f2SGordon Ross 			goto errout;
370*a90cf9f2SGordon Ross 	}
371*a90cf9f2SGordon Ross 
372*a90cf9f2SGordon Ross 	/*
373*a90cf9f2SGordon Ross 	 * SMB2 Create reply
374*a90cf9f2SGordon Ross 	 */
375*a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
376*a90cf9f2SGordon Ross 	    &sr->reply,
377*a90cf9f2SGordon Ross 	    "wb.lTTTTqqllqqll",
378*a90cf9f2SGordon Ross 	    89,	/* StructSize */	/* w */
379*a90cf9f2SGordon Ross 	    OplockLevel,		/* b */
380*a90cf9f2SGordon Ross 	    op->action_taken,		/* l */
381*a90cf9f2SGordon Ross 	    &attr->sa_crtime,		/* T */
382*a90cf9f2SGordon Ross 	    &attr->sa_vattr.va_atime,	/* T */
383*a90cf9f2SGordon Ross 	    &attr->sa_vattr.va_mtime,	/* T */
384*a90cf9f2SGordon Ross 	    &attr->sa_vattr.va_ctime,	/* T */
385*a90cf9f2SGordon Ross 	    attr->sa_allocsz,		/* q */
386*a90cf9f2SGordon Ross 	    attr->sa_vattr.va_size,	/* q */
387*a90cf9f2SGordon Ross 	    attr->sa_dosattr,		/* l */
388*a90cf9f2SGordon Ross 	    0, /* reserved2 */		/* l */
389*a90cf9f2SGordon Ross 	    smb2fid.persistent,		/* q */
390*a90cf9f2SGordon Ross 	    smb2fid.temporal,		/* q */
391*a90cf9f2SGordon Ross 	    0,  /* CreateCtxOffset	   l */
392*a90cf9f2SGordon Ross 	    0); /* CreateCtxLength	   l */
393*a90cf9f2SGordon Ross 	if (rc != 0) {
394*a90cf9f2SGordon Ross 		status = NT_STATUS_UNSUCCESSFUL;
395*a90cf9f2SGordon Ross 		goto errout;
396*a90cf9f2SGordon Ross 	}
397*a90cf9f2SGordon Ross 
398*a90cf9f2SGordon Ross 	CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
399*a90cf9f2SGordon Ross 	CreateCtxLength = MBC_LENGTH(&sr->raw_data);
400*a90cf9f2SGordon Ross 	if (CreateCtxLength != 0) {
401*a90cf9f2SGordon Ross 		/*
402*a90cf9f2SGordon Ross 		 * Overwrite CreateCtxOffset, CreateCtxLength, pad
403*a90cf9f2SGordon Ross 		 */
404*a90cf9f2SGordon Ross 		sr->reply.chain_offset -= 8;
405*a90cf9f2SGordon Ross 		rc = smb_mbc_encodef(
406*a90cf9f2SGordon Ross 		    &sr->reply,
407*a90cf9f2SGordon Ross 		    "ll#C",
408*a90cf9f2SGordon Ross 		    CreateCtxOffset,	/* l */
409*a90cf9f2SGordon Ross 		    CreateCtxLength,	/* l */
410*a90cf9f2SGordon Ross 		    CreateCtxLength,	/* # */
411*a90cf9f2SGordon Ross 		    &sr->raw_data);	/* C */
412*a90cf9f2SGordon Ross 		if (rc != 0) {
413*a90cf9f2SGordon Ross 			status = NT_STATUS_UNSUCCESSFUL;
414*a90cf9f2SGordon Ross 			goto errout;
415*a90cf9f2SGordon Ross 		}
416*a90cf9f2SGordon Ross 	} else {
417*a90cf9f2SGordon Ross 		(void) smb_mbc_encodef(&sr->reply, ".");
418*a90cf9f2SGordon Ross 	}
419*a90cf9f2SGordon Ross 	return (SDRC_SUCCESS);
420*a90cf9f2SGordon Ross 
421*a90cf9f2SGordon Ross errout:
422*a90cf9f2SGordon Ross 	if (of != NULL)
423*a90cf9f2SGordon Ross 		smb_ofile_close(of, 0);
424*a90cf9f2SGordon Ross 	if (cctx.cc_out_flags)
425*a90cf9f2SGordon Ross 		smb2_free_create_ctx(&cctx);
426*a90cf9f2SGordon Ross 	smb2sr_put_error(sr, status);
427*a90cf9f2SGordon Ross 	return (SDRC_SUCCESS);
428*a90cf9f2SGordon Ross }
429*a90cf9f2SGordon Ross 
430*a90cf9f2SGordon Ross /*
431*a90cf9f2SGordon Ross  * Decode an SMB2 Create Context buffer into our internal form.
432*a90cf9f2SGordon Ross  * No policy decisions about what's supported here, just decode.
433*a90cf9f2SGordon Ross  */
434*a90cf9f2SGordon Ross static uint32_t
435*a90cf9f2SGordon Ross smb2_decode_create_ctx(mbuf_chain_t *in_mbc, smb2_create_ctx_t *cc)
436*a90cf9f2SGordon Ross {
437*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce;
438*a90cf9f2SGordon Ross 	mbuf_chain_t name_mbc;
439*a90cf9f2SGordon Ross 	union {
440*a90cf9f2SGordon Ross 		uint32_t i;
441*a90cf9f2SGordon Ross 		char ch[4];
442*a90cf9f2SGordon Ross 	} cc_name;
443*a90cf9f2SGordon Ross 	uint32_t status;
444*a90cf9f2SGordon Ross 	int32_t next_off;
445*a90cf9f2SGordon Ross 	uint32_t data_len;
446*a90cf9f2SGordon Ross 	uint16_t data_off;
447*a90cf9f2SGordon Ross 	uint16_t name_off;
448*a90cf9f2SGordon Ross 	uint16_t name_len;
449*a90cf9f2SGordon Ross 	int top_offset;
450*a90cf9f2SGordon Ross 	int rc;
451*a90cf9f2SGordon Ross 
452*a90cf9f2SGordon Ross 	status = NT_STATUS_INVALID_PARAMETER;
453*a90cf9f2SGordon Ross 	for (;;) {
454*a90cf9f2SGordon Ross 		cce = NULL;
455*a90cf9f2SGordon Ross 		top_offset = in_mbc->chain_offset;
456*a90cf9f2SGordon Ross 		rc = smb_mbc_decodef(
457*a90cf9f2SGordon Ross 		    in_mbc,
458*a90cf9f2SGordon Ross 		    "lww..wl",
459*a90cf9f2SGordon Ross 		    &next_off,	/* l */
460*a90cf9f2SGordon Ross 		    &name_off,	/* w */
461*a90cf9f2SGordon Ross 		    &name_len,	/* w */
462*a90cf9f2SGordon Ross 		    /* reserved	  .. */
463*a90cf9f2SGordon Ross 		    &data_off,	/* w */
464*a90cf9f2SGordon Ross 		    &data_len); /* l */
465*a90cf9f2SGordon Ross 		if (rc)
466*a90cf9f2SGordon Ross 			break;
467*a90cf9f2SGordon Ross 
468*a90cf9f2SGordon Ross 		/*
469*a90cf9f2SGordon Ross 		 * The Create Context "name", per [MS-SMB] 2.2.13.2
470*a90cf9f2SGordon Ross 		 * They're defined as network-order integers for our
471*a90cf9f2SGordon Ross 		 * switch below.  We don't have routines to decode
472*a90cf9f2SGordon Ross 		 * native order, so read as char[4] then ntohl.
473*a90cf9f2SGordon Ross 		 * NB: in SMB3, some of these are 8 bytes.
474*a90cf9f2SGordon Ross 		 */
475*a90cf9f2SGordon Ross 		if ((top_offset + name_off) < in_mbc->chain_offset)
476*a90cf9f2SGordon Ross 			break;
477*a90cf9f2SGordon Ross 		rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc,
478*a90cf9f2SGordon Ross 		    top_offset + name_off, name_len);
479*a90cf9f2SGordon Ross 		if (rc)
480*a90cf9f2SGordon Ross 			break;
481*a90cf9f2SGordon Ross 		rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name);
482*a90cf9f2SGordon Ross 		if (rc)
483*a90cf9f2SGordon Ross 			break;
484*a90cf9f2SGordon Ross 		cc_name.i = ntohl(cc_name.i);
485*a90cf9f2SGordon Ross 
486*a90cf9f2SGordon Ross 		switch (cc_name.i) {
487*a90cf9f2SGordon Ross 		case SMB2_CREATE_EA_BUFFER:		/* ("ExtA") */
488*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_EA_BUFFER;
489*a90cf9f2SGordon Ross 			cce = &cc->cc_in_ext_attr;
490*a90cf9f2SGordon Ross 			break;
491*a90cf9f2SGordon Ross 		case SMB2_CREATE_SD_BUFFER:		/* ("SecD") */
492*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_SD_BUFFER;
493*a90cf9f2SGordon Ross 			cce = &cc->cc_in_sec_desc;
494*a90cf9f2SGordon Ross 			break;
495*a90cf9f2SGordon Ross 		case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
496*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_DH_REQUEST;
497*a90cf9f2SGordon Ross 			cce = &cc->cc_in_dh_request;
498*a90cf9f2SGordon Ross 			break;
499*a90cf9f2SGordon Ross 		case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
500*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_DH_RECONNECT;
501*a90cf9f2SGordon Ross 			cce = &cc->cc_in_dh_reconnect;
502*a90cf9f2SGordon Ross 			break;
503*a90cf9f2SGordon Ross 		case SMB2_CREATE_ALLOCATION_SIZE:	/* ("AISi") */
504*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
505*a90cf9f2SGordon Ross 			cce = &cc->cc_in_alloc_size;
506*a90cf9f2SGordon Ross 			break;
507*a90cf9f2SGordon Ross 		case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
508*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
509*a90cf9f2SGordon Ross 			/* no input data for this */
510*a90cf9f2SGordon Ross 			break;
511*a90cf9f2SGordon Ross 		case SMB2_CREATE_TIMEWARP_TOKEN:	/* ("TWrp") */
512*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
513*a90cf9f2SGordon Ross 			cce = &cc->cc_in_time_warp;
514*a90cf9f2SGordon Ross 			break;
515*a90cf9f2SGordon Ross 		case SMB2_CREATE_QUERY_ON_DISK_ID:	/* ("QFid") */
516*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
517*a90cf9f2SGordon Ross 			/* no input data for this */
518*a90cf9f2SGordon Ross 			break;
519*a90cf9f2SGordon Ross 		case SMB2_CREATE_REQUEST_LEASE:		/* ("RqLs") */
520*a90cf9f2SGordon Ross 			cc->cc_in_flags |= CCTX_REQUEST_LEASE;
521*a90cf9f2SGordon Ross 			cce = &cc->cc_in_req_lease;
522*a90cf9f2SGordon Ross 			break;
523*a90cf9f2SGordon Ross 		default:
524*a90cf9f2SGordon Ross 			/*
525*a90cf9f2SGordon Ross 			 * Unknown create context values are normal, and
526*a90cf9f2SGordon Ross 			 * should be ignored.  However, in debug mode,
527*a90cf9f2SGordon Ross 			 * let's log them so we know which ones we're
528*a90cf9f2SGordon Ross 			 * not handling (and may want to add).
529*a90cf9f2SGordon Ross 			 */
530*a90cf9f2SGordon Ross #ifdef	DEBUG
531*a90cf9f2SGordon Ross 			cmn_err(CE_NOTE, "unknown create context ID 0x%x",
532*a90cf9f2SGordon Ross 			    cc_name.i);
533*a90cf9f2SGordon Ross #endif
534*a90cf9f2SGordon Ross 			cce = NULL;
535*a90cf9f2SGordon Ross 			break;
536*a90cf9f2SGordon Ross 		}
537*a90cf9f2SGordon Ross 
538*a90cf9f2SGordon Ross 		if (cce != NULL && data_len != 0) {
539*a90cf9f2SGordon Ross 			if ((data_off & 7) != 0)
540*a90cf9f2SGordon Ross 				break;
541*a90cf9f2SGordon Ross 			if ((top_offset + data_off) < in_mbc->chain_offset)
542*a90cf9f2SGordon Ross 				break;
543*a90cf9f2SGordon Ross 			rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
544*a90cf9f2SGordon Ross 			    top_offset + data_off, data_len);
545*a90cf9f2SGordon Ross 			if (rc)
546*a90cf9f2SGordon Ross 				break;
547*a90cf9f2SGordon Ross 			cce->cce_len = data_len;
548*a90cf9f2SGordon Ross 		}
549*a90cf9f2SGordon Ross 
550*a90cf9f2SGordon Ross 		if (next_off == 0) {
551*a90cf9f2SGordon Ross 			/* Normal loop termination */
552*a90cf9f2SGordon Ross 			status = 0;
553*a90cf9f2SGordon Ross 			break;
554*a90cf9f2SGordon Ross 		}
555*a90cf9f2SGordon Ross 
556*a90cf9f2SGordon Ross 		if ((next_off & 7) != 0)
557*a90cf9f2SGordon Ross 			break;
558*a90cf9f2SGordon Ross 		if ((top_offset + next_off) < in_mbc->chain_offset)
559*a90cf9f2SGordon Ross 			break;
560*a90cf9f2SGordon Ross 		if ((top_offset + next_off) > in_mbc->max_bytes)
561*a90cf9f2SGordon Ross 			break;
562*a90cf9f2SGordon Ross 		in_mbc->chain_offset = top_offset + next_off;
563*a90cf9f2SGordon Ross 	}
564*a90cf9f2SGordon Ross 
565*a90cf9f2SGordon Ross 	return (status);
566*a90cf9f2SGordon Ross }
567*a90cf9f2SGordon Ross 
568*a90cf9f2SGordon Ross /*
569*a90cf9f2SGordon Ross  * Encode an SMB2 Create Context buffer from our internal form.
570*a90cf9f2SGordon Ross  */
571*a90cf9f2SGordon Ross /* ARGSUSED */
572*a90cf9f2SGordon Ross static uint32_t
573*a90cf9f2SGordon Ross smb2_encode_create_ctx(mbuf_chain_t *mbc, smb2_create_ctx_t *cc)
574*a90cf9f2SGordon Ross {
575*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce;
576*a90cf9f2SGordon Ross 	int last_top = -1;
577*a90cf9f2SGordon Ross 	int rc;
578*a90cf9f2SGordon Ross 
579*a90cf9f2SGordon Ross 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
580*a90cf9f2SGordon Ross 		cce = &cc->cc_out_max_access;
581*a90cf9f2SGordon Ross 		last_top = mbc->chain_offset;
582*a90cf9f2SGordon Ross 		rc = smb2_encode_create_ctx_elem(mbc, cce,
583*a90cf9f2SGordon Ross 		    SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
584*a90cf9f2SGordon Ross 		if (rc)
585*a90cf9f2SGordon Ross 			return (NT_STATUS_INTERNAL_ERROR);
586*a90cf9f2SGordon Ross 		(void) smb_mbc_poke(mbc, last_top, "l",
587*a90cf9f2SGordon Ross 		    mbc->chain_offset - last_top);
588*a90cf9f2SGordon Ross 	}
589*a90cf9f2SGordon Ross 
590*a90cf9f2SGordon Ross 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
591*a90cf9f2SGordon Ross 		cce = &cc->cc_out_file_id;
592*a90cf9f2SGordon Ross 		last_top = mbc->chain_offset;
593*a90cf9f2SGordon Ross 		rc = smb2_encode_create_ctx_elem(mbc, cce,
594*a90cf9f2SGordon Ross 		    SMB2_CREATE_QUERY_ON_DISK_ID);
595*a90cf9f2SGordon Ross 		if (rc)
596*a90cf9f2SGordon Ross 			return (NT_STATUS_INTERNAL_ERROR);
597*a90cf9f2SGordon Ross 		(void) smb_mbc_poke(mbc, last_top, "l",
598*a90cf9f2SGordon Ross 		    mbc->chain_offset - last_top);
599*a90cf9f2SGordon Ross 	}
600*a90cf9f2SGordon Ross 
601*a90cf9f2SGordon Ross 	if (last_top >= 0)
602*a90cf9f2SGordon Ross 		(void) smb_mbc_poke(mbc, last_top, "l", 0);
603*a90cf9f2SGordon Ross 
604*a90cf9f2SGordon Ross 	return (0);
605*a90cf9f2SGordon Ross }
606*a90cf9f2SGordon Ross 
607*a90cf9f2SGordon Ross static int
608*a90cf9f2SGordon Ross smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
609*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce, uint32_t id)
610*a90cf9f2SGordon Ross {
611*a90cf9f2SGordon Ross 	union {
612*a90cf9f2SGordon Ross 		uint32_t i;
613*a90cf9f2SGordon Ross 		char ch[4];
614*a90cf9f2SGordon Ross 	} cc_name;
615*a90cf9f2SGordon Ross 	int rc;
616*a90cf9f2SGordon Ross 
617*a90cf9f2SGordon Ross 	/* as above */
618*a90cf9f2SGordon Ross 	cc_name.i = htonl(id);
619*a90cf9f2SGordon Ross 
620*a90cf9f2SGordon Ross 	/*
621*a90cf9f2SGordon Ross 	 * This is the header, per [MS-SMB2] 2.2.13.2
622*a90cf9f2SGordon Ross 	 * Sorry about the fixed offsets.  We know we'll
623*a90cf9f2SGordon Ross 	 * layout the data part as [name, payload] and
624*a90cf9f2SGordon Ross 	 * name is a fixed length, so this easy.
625*a90cf9f2SGordon Ross 	 * The final layout looks like this:
626*a90cf9f2SGordon Ross 	 * 	a: this header (16 bytes)
627*a90cf9f2SGordon Ross 	 *	b: the name (4 bytes, 4 pad)
628*a90cf9f2SGordon Ross 	 *	c: the payload (variable)
629*a90cf9f2SGordon Ross 	 *
630*a90cf9f2SGordon Ross 	 * Note that "Next elem." is filled in later.
631*a90cf9f2SGordon Ross 	 */
632*a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
633*a90cf9f2SGordon Ross 	    out_mbc, "lwwwwl",
634*a90cf9f2SGordon Ross 	    0,		/* Next offset	l */
635*a90cf9f2SGordon Ross 	    16,		/* NameOffset	w */
636*a90cf9f2SGordon Ross 	    4,		/* NameLength	w */
637*a90cf9f2SGordon Ross 	    0,		/* Reserved	w */
638*a90cf9f2SGordon Ross 	    24,		/* DataOffset	w */
639*a90cf9f2SGordon Ross 	    cce->cce_len);	/*	l */
640*a90cf9f2SGordon Ross 	if (rc)
641*a90cf9f2SGordon Ross 		return (rc);
642*a90cf9f2SGordon Ross 
643*a90cf9f2SGordon Ross 	/*
644*a90cf9f2SGordon Ross 	 * Now the "name" and payload.
645*a90cf9f2SGordon Ross 	 */
646*a90cf9f2SGordon Ross 	rc = smb_mbc_encodef(
647*a90cf9f2SGordon Ross 	    out_mbc, "4c4.#C",
648*a90cf9f2SGordon Ross 	    cc_name.ch,		/* 4c4. */
649*a90cf9f2SGordon Ross 	    cce->cce_len,	/* # */
650*a90cf9f2SGordon Ross 	    &cce->cce_mbc);	/* C */
651*a90cf9f2SGordon Ross 
652*a90cf9f2SGordon Ross 	return (rc);
653*a90cf9f2SGordon Ross }
654*a90cf9f2SGordon Ross 
655*a90cf9f2SGordon Ross static void
656*a90cf9f2SGordon Ross smb2_free_create_ctx(smb2_create_ctx_t *cc)
657*a90cf9f2SGordon Ross {
658*a90cf9f2SGordon Ross 	smb2_create_ctx_elem_t *cce;
659*a90cf9f2SGordon Ross 
660*a90cf9f2SGordon Ross 	if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
661*a90cf9f2SGordon Ross 		cce = &cc->cc_out_max_access;
662*a90cf9f2SGordon Ross 		MBC_FLUSH(&cce->cce_mbc);
663*a90cf9f2SGordon Ross 	}
664*a90cf9f2SGordon Ross 	if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
665*a90cf9f2SGordon Ross 		cce = &cc->cc_out_file_id;
666*a90cf9f2SGordon Ross 		MBC_FLUSH(&cce->cce_mbc);
667*a90cf9f2SGordon Ross 	}
668*a90cf9f2SGordon Ross }
669