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
smb2_create(smb_request_t * sr)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
smb2_decode_create_ctx(mbuf_chain_t * in_mbc,smb2_create_ctx_t * cc)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
smb2_encode_create_ctx(mbuf_chain_t * mbc,smb2_create_ctx_t * cc)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
smb2_encode_create_ctx_elem(mbuf_chain_t * out_mbc,smb2_create_ctx_elem_t * cce,uint32_t id)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
smb2_free_create_ctx(smb2_create_ctx_t * cc)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