Print this page
NEX-19375 SMB2 durable handle create response missing timeout
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-9808 SMB3 persistent handles
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-5672 SMB2_create dtrace probe
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-3553 SMB2/3 durable handles
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-5586 SMB2 ofiles need real Persistent IDs
NEX-5313 SMB2 oplock break notification should use TID=0
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-4836 WBC: export and destroy may hang due to faulty wrc migration termination
Reviewed by: Alex Aizman <alex.aizman@nexenta.com>
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
NEX-3733 Want SMB2 Apple extensions (allow disable)
NEX-3733 Want SMB2 Apple extensions
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-4239 smbtorture create failures re. allocation size
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-1635 Codenomicon: SMB2 TC: 157974 Panic in smb2_create/smb_decode_sd
SMB-115 Support SMB path names with length > 1024
SMB-100 Internal error if filename is too long
Approved by: Gordon Ross <gwr@nexenta.com>
SMB-136 Snapshots not visible in Windows previous versions
SMB-138 memory leak in smb2_create
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
SMB-96 Codenomicon: SMB2 TC: 141500 - Panic in smb2_decode_create_ctx
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/fs/smbsrv/smb2_create.c
+++ new/usr/src/uts/common/fs/smbsrv/smb2_create.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
|
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 - * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
13 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
14 14 */
15 15
16 16 /*
17 17 * Dispatch function for SMB2_CREATE
18 18 * [MS-SMB2] 2.2.13
19 19 */
20 20
21 21 #include <smbsrv/smb2_kproto.h>
22 22 #include <smbsrv/smb_fsops.h>
23 23
24 +#define DH_PERSISTENT SMB2_DHANDLE_FLAG_PERSISTENT
25 +
24 26 /*
27 + * Compile-time check that the SMB2_LEASE_... definitions
28 + * match the (internal) equivalents from ntifs.h
29 + */
30 +#if SMB2_LEASE_NONE != OPLOCK_LEVEL_NONE
31 +#error "SMB2_LEASE_NONE"
32 +#endif
33 +#if SMB2_LEASE_READ_CACHING != OPLOCK_LEVEL_CACHE_READ
34 +#error "SMB2_LEASE_READ_CACHING"
35 +#endif
36 +#if SMB2_LEASE_HANDLE_CACHING != OPLOCK_LEVEL_CACHE_HANDLE
37 +#error "SMB2_LEASE_HANDLE_CACHING"
38 +#endif
39 +#if SMB2_LEASE_WRITE_CACHING != OPLOCK_LEVEL_CACHE_WRITE
40 +#error "SMB2_LEASE_WRITE_CACHING"
41 +#endif
42 +
43 +/*
25 44 * Some flags used locally to keep track of which Create Context
26 45 * names have been provided and/or requested.
27 46 */
28 47 #define CCTX_EA_BUFFER 1
29 48 #define CCTX_SD_BUFFER 2
30 49 #define CCTX_DH_REQUEST 4
31 50 #define CCTX_DH_RECONNECT 8
32 51 #define CCTX_ALLOCATION_SIZE 0x10
33 52 #define CCTX_QUERY_MAX_ACCESS 0x20
34 53 #define CCTX_TIMEWARP_TOKEN 0x40
35 54 #define CCTX_QUERY_ON_DISK_ID 0x80
36 55 #define CCTX_REQUEST_LEASE 0x100
56 +#define CCTX_AAPL_EXT 0x200
57 +#define CCTX_DH_REQUEST_V2 0x400
58 +#define CCTX_DH_RECONNECT_V2 0x800
37 59
38 -
39 60 typedef struct smb2_create_ctx_elem {
40 61 uint32_t cce_len;
41 62 mbuf_chain_t cce_mbc;
42 63 } smb2_create_ctx_elem_t;
43 64
44 65 typedef struct smb2_create_ctx {
66 + mbuf_chain_t cc_in_mbc;
45 67 uint_t cc_in_flags; /* CCTX_... */
46 68 uint_t cc_out_flags; /* CCTX_... */
47 69 /* Elements we may see in the request. */
48 70 smb2_create_ctx_elem_t cc_in_ext_attr;
49 71 smb2_create_ctx_elem_t cc_in_sec_desc;
50 72 smb2_create_ctx_elem_t cc_in_dh_request;
51 73 smb2_create_ctx_elem_t cc_in_dh_reconnect;
52 74 smb2_create_ctx_elem_t cc_in_alloc_size;
53 75 smb2_create_ctx_elem_t cc_in_time_warp;
54 76 smb2_create_ctx_elem_t cc_in_req_lease;
77 + smb2_create_ctx_elem_t cc_in_aapl;
78 + smb2_create_ctx_elem_t cc_in_dh_request_v2;
79 + smb2_create_ctx_elem_t cc_in_dh_reconnect_v2;
55 80 /* Elements we my place in the response */
56 81 smb2_create_ctx_elem_t cc_out_max_access;
57 82 smb2_create_ctx_elem_t cc_out_file_id;
83 + smb2_create_ctx_elem_t cc_out_aapl;
84 + smb2_create_ctx_elem_t cc_out_req_lease;
85 + smb2_create_ctx_elem_t cc_out_dh_request;
86 + smb2_create_ctx_elem_t cc_out_dh_request_v2;
58 87 } smb2_create_ctx_t;
59 88
60 89 static uint32_t smb2_decode_create_ctx(
61 - mbuf_chain_t *, smb2_create_ctx_t *);
90 + smb_request_t *, smb2_create_ctx_t *);
62 91 static uint32_t smb2_encode_create_ctx(
63 - mbuf_chain_t *, smb2_create_ctx_t *);
92 + smb_request_t *, smb2_create_ctx_t *);
64 93 static int smb2_encode_create_ctx_elem(
65 94 mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
66 95 static void smb2_free_create_ctx(smb2_create_ctx_t *);
67 96
97 +int smb2_enable_dh = 1;
98 +
68 99 smb_sdrc_t
69 100 smb2_create(smb_request_t *sr)
70 101 {
71 102 smb_attr_t *attr;
72 103 smb2_create_ctx_elem_t *cce;
73 104 smb2_create_ctx_t cctx;
74 - mbuf_chain_t cc_mbc;
75 105 smb_arg_open_t *op = &sr->arg.open;
76 106 smb_ofile_t *of = NULL;
77 107 uint16_t StructSize;
78 108 uint8_t SecurityFlags;
79 - uint8_t OplockLevel;
80 109 uint32_t ImpersonationLevel;
81 110 uint64_t SmbCreateFlags;
82 111 uint64_t Reserved4;
83 112 uint16_t NameOffset;
84 113 uint16_t NameLength;
85 114 uint32_t CreateCtxOffset;
86 115 uint32_t CreateCtxLength;
87 - smb2fid_t smb2fid;
116 + smb2fid_t smb2fid = { 0, 0 };
88 117 uint32_t status;
118 + int dh_flags;
89 119 int skip;
90 120 int rc = 0;
91 121
92 122 bzero(&cctx, sizeof (cctx));
93 - bzero(&cc_mbc, sizeof (cc_mbc));
123 + op->create_ctx = &cctx; /* for debugging */
94 124
95 125 /*
96 126 * Paranoia. This will set sr->fid_ofile, so
97 127 * if we already have one, release it now.
98 128 */
99 129 if (sr->fid_ofile != NULL) {
100 - smb_ofile_request_complete(sr->fid_ofile);
101 130 smb_ofile_release(sr->fid_ofile);
102 131 sr->fid_ofile = NULL;
103 132 }
104 133
105 134 /*
106 - * SMB2 Create request
135 + * Decode the SMB2 Create request
136 + *
137 + * Most decode errors return SDRC_ERROR, but
138 + * for some we give a more specific error.
139 + *
140 + * In the "decode section" (starts here) any
141 + * errors should either return SDRC_ERROR, or
142 + * if any cleanup is needed, goto errout.
107 143 */
108 144 rc = smb_mbc_decodef(
109 145 &sr->smb_data, "wbblqqlllllwwll",
110 146 &StructSize, /* w */
111 147 &SecurityFlags, /* b */
112 - &OplockLevel, /* b */
148 + &op->op_oplock_level, /* b */
113 149 &ImpersonationLevel, /* l */
114 150 &SmbCreateFlags, /* q */
115 151 &Reserved4, /* q */
116 152 &op->desired_access, /* l */
117 153 &op->dattr, /* l */
118 154 &op->share_access, /* l */
119 155 &op->create_disposition, /* l */
120 156 &op->create_options, /* l */
121 157 &NameOffset, /* w */
122 158 &NameLength, /* w */
123 159 &CreateCtxOffset, /* l */
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
124 160 &CreateCtxLength); /* l */
125 161 if (rc != 0 || StructSize != 57)
126 162 return (SDRC_ERROR);
127 163
128 164 /*
129 165 * We're normally positioned at the path name now,
130 166 * but there could be some padding before it.
131 167 */
132 168 skip = (NameOffset + sr->smb2_cmd_hdr) -
133 169 sr->smb_data.chain_offset;
134 - if (skip < 0) {
135 - status = NT_STATUS_OBJECT_PATH_INVALID;
136 - goto errout;
137 - }
170 + if (skip < 0)
171 + return (SDRC_ERROR);
138 172 if (skip > 0)
139 173 (void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
140 174
141 175 /*
142 176 * Get the path name
177 + *
178 + * Name too long is not technically a decode error,
179 + * but it's very rare, so we'll just skip the
180 + * dtrace probes for this error case.
143 181 */
144 182 if (NameLength >= SMB_MAXPATHLEN) {
145 183 status = NT_STATUS_OBJECT_PATH_INVALID;
146 184 goto errout;
147 185 }
148 186 if (NameLength == 0) {
149 187 op->fqi.fq_path.pn_path = "\\";
150 188 } else {
151 189 rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
152 190 NameLength, &op->fqi.fq_path.pn_path);
153 191 if (rc) {
154 192 status = NT_STATUS_OBJECT_PATH_INVALID;
155 193 goto errout;
156 194 }
157 195 }
158 196 op->fqi.fq_dnode = sr->tid_tree->t_snode;
159 197
160 - switch (OplockLevel) {
161 - case SMB2_OPLOCK_LEVEL_NONE:
162 - op->op_oplock_level = SMB_OPLOCK_NONE;
163 - break;
164 - case SMB2_OPLOCK_LEVEL_II:
165 - op->op_oplock_level = SMB_OPLOCK_LEVEL_II;
166 - break;
167 - case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
168 - op->op_oplock_level = SMB_OPLOCK_EXCLUSIVE;
169 - break;
170 - case SMB2_OPLOCK_LEVEL_BATCH:
171 - op->op_oplock_level = SMB_OPLOCK_BATCH;
172 - break;
173 - case SMB2_OPLOCK_LEVEL_LEASE:
174 - status = NT_STATUS_INVALID_PARAMETER;
175 - goto errout;
176 - }
177 - op->op_oplock_levelII = B_TRUE;
178 -
179 198 /*
180 - * ImpersonationLevel (spec. says ignore)
181 - * SmbCreateFlags (spec. says ignore)
182 - */
183 -
184 - if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
185 - !(op->desired_access & DELETE)) {
186 - status = NT_STATUS_INVALID_PARAMETER;
187 - goto errout;
188 - }
189 - if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
190 - status = NT_STATUS_INVALID_PARAMETER;
191 - goto errout;
192 - }
193 -
194 - if (op->dattr & FILE_FLAG_WRITE_THROUGH)
195 - op->create_options |= FILE_WRITE_THROUGH;
196 - if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
197 - op->create_options |= FILE_DELETE_ON_CLOSE;
198 - if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
199 - op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
200 - if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
201 - sr->user_cr = smb_user_getprivcred(sr->uid_user);
202 -
203 - /*
204 199 * If there is a "Create Context" payload, decode it.
205 200 * This may carry things like a security descriptor,
206 201 * extended attributes, etc. to be used in create.
207 202 *
208 203 * The create ctx buffer must start after the headers
209 204 * and file name, and must be 8-byte aligned.
210 205 */
211 206 if (CreateCtxLength != 0) {
212 207 if ((CreateCtxOffset & 7) != 0 ||
213 208 (CreateCtxOffset + sr->smb2_cmd_hdr) <
214 209 sr->smb_data.chain_offset) {
215 210 status = NT_STATUS_INVALID_PARAMETER;
216 211 goto errout;
217 212 }
218 213
219 - rc = MBC_SHADOW_CHAIN(&cc_mbc, &sr->smb_data,
214 + rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data,
220 215 sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
221 216 if (rc) {
222 217 status = NT_STATUS_INVALID_PARAMETER;
223 218 goto errout;
224 219 }
225 - status = smb2_decode_create_ctx(&cc_mbc, &cctx);
220 + status = smb2_decode_create_ctx(sr, &cctx);
226 221 if (status)
227 222 goto errout;
223 + }
228 224
229 - if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
230 - status = NT_STATUS_EAS_NOT_SUPPORTED;
231 - goto errout;
232 - }
225 + /*
226 + * Everything is decoded into some internal form, so
227 + * in this probe one can look at sr->arg.open etc.
228 + *
229 + * This marks the end of the "decode" section and the
230 + * beginning of the "body" section. Any errors in
231 + * this section should use: goto cmd_done (which is
232 + * just before the dtrace "done" probe).
233 + */
234 + DTRACE_SMB2_START(op__Create, smb_request_t *, sr); /* arg.open */
233 235
234 - if (cctx.cc_in_flags & CCTX_SD_BUFFER) {
235 - smb_sd_t sd;
236 - cce = &cctx.cc_in_sec_desc;
237 - status = smb_decode_sd(
238 - &cce->cce_mbc, &sd);
239 - if (status)
240 - goto errout;
241 - op->sd = kmem_alloc(sizeof (sd), KM_SLEEP);
242 - *op->sd = sd;
243 - }
236 + /*
237 + * Process the incoming create contexts (already decoded),
238 + * that need action before the open, starting with the
239 + * Durable Handle ones, which may override others.
240 + */
244 241
245 - if (cctx.cc_in_flags & CCTX_ALLOCATION_SIZE) {
246 - cce = &cctx.cc_in_alloc_size;
247 - rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
248 - if (rc) {
249 - status = NT_STATUS_INVALID_PARAMETER;
250 - goto errout;
242 + /*
243 + * Only disk trees get durable handles.
244 + */
245 + if (smb2_enable_dh == 0 ||
246 + (sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
247 + cctx.cc_in_flags &=
248 + ~(CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
249 + CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
250 + }
251 +
252 + /*
253 + * DH v2 is only valid in SMB3.0 and later.
254 + * If seen in earlier dialects, ignore.
255 + */
256 + if (sr->session->dialect < SMB_VERS_3_0) {
257 + cctx.cc_in_flags &=
258 + ~(CCTX_DH_REQUEST_V2|CCTX_DH_RECONNECT_V2);
259 + }
260 +
261 + /*
262 + * It is an error to specify more than one Durable Handle
263 + * operation in a single create, except when only the v1
264 + * REQUEST and RECONNECT operations are specified. In that
265 + * case, the v1 REQUEST is ignored.
266 + */
267 + dh_flags = cctx.cc_in_flags &
268 + (CCTX_DH_REQUEST | CCTX_DH_REQUEST_V2 |
269 + CCTX_DH_RECONNECT | CCTX_DH_RECONNECT_V2);
270 + if ((dh_flags & (dh_flags - 1)) != 0 &&
271 + dh_flags != (CCTX_DH_REQUEST|CCTX_DH_RECONNECT)) {
272 + status = NT_STATUS_INVALID_PARAMETER;
273 + goto cmd_done;
274 + }
275 +
276 + /*
277 + * Reconnect is special in MANY ways, including the
278 + * somewhat surprising (specified) behavior that
279 + * most other creat parameters are ignored, and
280 + * many create context types are ignored too.
281 + */
282 + op->dh_vers = SMB2_NOT_DURABLE;
283 + if ((cctx.cc_in_flags &
284 + (CCTX_DH_RECONNECT|CCTX_DH_RECONNECT_V2)) != 0) {
285 +
286 + if ((cctx.cc_in_flags & CCTX_DH_RECONNECT_V2) != 0)
287 + op->dh_vers = SMB2_DURABLE_V2;
288 + else
289 + op->dh_vers = SMB2_DURABLE_V1;
290 +
291 + /* Ignore these create contexts. */
292 + cctx.cc_in_flags &=
293 + ~(CCTX_DH_REQUEST |
294 + CCTX_DH_REQUEST_V2 |
295 + CCTX_EA_BUFFER |
296 + CCTX_SD_BUFFER |
297 + CCTX_ALLOCATION_SIZE |
298 + CCTX_TIMEWARP_TOKEN |
299 + CCTX_QUERY_ON_DISK_ID);
300 +
301 + /*
302 + * Reconnect check needs to know if a lease was requested.
303 + * The requested oplock level is ignored in reconnect, so
304 + * using op_oplock_level to convey this info.
305 + */
306 + if (cctx.cc_in_flags & CCTX_REQUEST_LEASE)
307 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
308 + else
309 + op->op_oplock_level = 0;
310 +
311 + status = smb2_dh_reconnect(sr);
312 + if (status != NT_STATUS_SUCCESS)
313 + goto cmd_done;
314 +
315 + /*
316 + * Skip most open execution during reconnect,
317 + * but need (reclaimed) oplock state in *op.
318 + */
319 + of = sr->fid_ofile;
320 +
321 + op->op_oplock_state = of->f_oplock.og_state;
322 + if (of->f_lease != NULL) {
323 + smb_lease_t *ls = of->f_lease;
324 +
325 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_LEASE;
326 + op->lease_state = ls->ls_state &
327 + OPLOCK_LEVEL_CACHE_MASK;
328 + op->lease_flags = (ls->ls_breaking != 0) ?
329 + SMB2_LEASE_FLAG_BREAK_IN_PROGRESS : 0;
330 + op->lease_epoch = ls->ls_epoch;
331 + op->lease_version = ls->ls_version;
332 + } else {
333 + switch (op->op_oplock_state & OPLOCK_LEVEL_TYPE_MASK) {
334 + default:
335 + case OPLOCK_LEVEL_NONE:
336 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
337 + break;
338 + case OPLOCK_LEVEL_TWO:
339 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_II;
340 + break;
341 + case OPLOCK_LEVEL_ONE:
342 + op->op_oplock_level =
343 + SMB2_OPLOCK_LEVEL_EXCLUSIVE;
344 + break;
345 + case OPLOCK_LEVEL_BATCH:
346 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
347 + break;
251 348 }
252 349 }
253 350
351 + goto reconnect_done;
352 + }
353 +
354 + /*
355 + * Real create (of a new handle, not reconnect)
356 + */
357 +
358 + /*
359 + * Validate the requested oplock level.
360 + * Conversion to internal form is in smb2_oplock_acquire()
361 + */
362 + switch (op->op_oplock_level) {
363 + case SMB2_OPLOCK_LEVEL_NONE: /* OPLOCK_LEVEL_NONE */
364 + case SMB2_OPLOCK_LEVEL_II: /* OPLOCK_LEVEL_TWO */
365 + case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* OPLOCK_LEVEL_ONE */
366 + case SMB2_OPLOCK_LEVEL_BATCH: /* OPLOCK_LEVEL_BATCH */
254 367 /*
255 - * Support for opening "Previous Versions".
256 - * [MS-SMB2] 2.2.13.2.7 Data is an NT time.
368 + * Ignore lease create context (if any)
257 369 */
258 - if (cctx.cc_in_flags & CCTX_TIMEWARP_TOKEN) {
259 - uint64_t timewarp;
260 - cce = &cctx.cc_in_time_warp;
261 - status = smb_mbc_decodef(&cce->cce_mbc,
262 - "q", &timewarp);
263 - if (status)
264 - goto errout;
265 - smb_time_nt_to_unix(timewarp, &op->timewarp);
266 - op->create_timewarp = B_TRUE;
370 + cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
371 + break;
372 +
373 + case SMB2_OPLOCK_LEVEL_LEASE: /* OPLOCK_LEVEL_GRANULAR */
374 + /*
375 + * Require a lease create context.
376 + */
377 + if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) == 0) {
378 + cmn_err(CE_NOTE, "smb2:create, oplock=ff and no lease");
379 + status = NT_STATUS_INVALID_PARAMETER;
380 + goto cmd_done;
267 381 }
382 +
383 + /*
384 + * Validate lease request state
385 + * Only a few valid combinations.
386 + */
387 + switch (op->lease_state) {
388 + case SMB2_LEASE_NONE:
389 + case SMB2_LEASE_READ_CACHING:
390 + case SMB2_LEASE_READ_CACHING | SMB2_LEASE_HANDLE_CACHING:
391 + case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING:
392 + case SMB2_LEASE_READ_CACHING | SMB2_LEASE_WRITE_CACHING |
393 + SMB2_LEASE_HANDLE_CACHING:
394 + break;
395 +
396 + default:
397 + /*
398 + * Invalid lease state flags
399 + * Just force to "none".
400 + */
401 + op->lease_state = SMB2_LEASE_NONE;
402 + break;
403 + }
404 + break;
405 +
406 + default:
407 + /* Unknown SMB2 oplock level. */
408 + status = NT_STATUS_INVALID_PARAMETER;
409 + goto cmd_done;
268 410 }
269 411
270 412 /*
413 + * Only disk trees get oplocks or leases.
414 + */
415 + if ((sr->tid_tree->t_res_type & STYPE_MASK) != STYPE_DISKTREE) {
416 + op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
417 + cctx.cc_in_flags &= ~CCTX_REQUEST_LEASE;
418 + }
419 +
420 + if ((sr->tid_tree->t_flags & SMB_TREE_CA) == 0)
421 + op->dh_v2_flags &= ~DH_PERSISTENT;
422 +
423 + if ((cctx.cc_in_flags &
424 + (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0) {
425 + if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0)
426 + op->dh_vers = SMB2_DURABLE_V2;
427 + else
428 + op->dh_vers = SMB2_DURABLE_V1;
429 + }
430 +
431 + if (cctx.cc_in_flags & CCTX_EA_BUFFER) {
432 + status = NT_STATUS_EAS_NOT_SUPPORTED;
433 + goto cmd_done;
434 + }
435 +
436 + /*
437 + * ImpersonationLevel (spec. says validate + ignore)
438 + * SmbCreateFlags (spec. says ignore)
439 + */
440 +
441 + if ((op->create_options & FILE_DELETE_ON_CLOSE) &&
442 + !(op->desired_access & DELETE)) {
443 + status = NT_STATUS_INVALID_PARAMETER;
444 + goto cmd_done;
445 + }
446 +
447 + if (op->dattr & FILE_FLAG_WRITE_THROUGH)
448 + op->create_options |= FILE_WRITE_THROUGH;
449 + if (op->dattr & FILE_FLAG_DELETE_ON_CLOSE)
450 + op->create_options |= FILE_DELETE_ON_CLOSE;
451 + if (op->dattr & FILE_FLAG_BACKUP_SEMANTICS)
452 + op->create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
453 + if (op->create_options & FILE_OPEN_FOR_BACKUP_INTENT)
454 + sr->user_cr = smb_user_getprivcred(sr->uid_user);
455 + if (op->create_disposition > FILE_MAXIMUM_DISPOSITION) {
456 + status = NT_STATUS_INVALID_PARAMETER;
457 + goto cmd_done;
458 + }
459 +
460 + /*
271 461 * The real open call. Note: this gets attributes into
272 462 * op->fqi.fq_fattr (SMB_AT_ALL). We need those below.
463 + * When of != NULL, goto errout closes it.
273 464 */
274 465 status = smb_common_open(sr);
275 466 if (status != NT_STATUS_SUCCESS)
276 - goto errout;
277 - attr = &op->fqi.fq_fattr;
467 + goto cmd_done;
468 + of = sr->fid_ofile;
278 469
279 470 /*
280 - * Convert the negotiate Oplock level back into
281 - * SMB2 encoding form.
471 + * Set the "persistent" part of the file ID
472 + * (only for DISK shares). Need this even for
473 + * non-durable handles in case we get the ioctl
474 + * to set "resiliency" on this handle.
282 475 */
283 - switch (op->op_oplock_level) {
284 - default:
285 - case SMB_OPLOCK_NONE:
286 - OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
287 - break;
288 - case SMB_OPLOCK_LEVEL_II:
289 - OplockLevel = SMB2_OPLOCK_LEVEL_II;
290 - break;
291 - case SMB_OPLOCK_EXCLUSIVE:
292 - OplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
293 - break;
294 - case SMB_OPLOCK_BATCH:
295 - OplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
296 - break;
476 + if (of->f_ftype == SMB_FTYPE_DISK) {
477 + if ((op->dh_v2_flags & DH_PERSISTENT) != 0)
478 + smb_ofile_set_persistid_ph(of);
479 + else
480 + smb_ofile_set_persistid_dh(of);
297 481 }
298 482
299 483 /*
484 + * [MS-SMB2] 3.3.5.9.8
485 + * Handling the SMB2_CREATE_REQUEST_LEASE Create Context
486 + */
487 + if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0) {
488 + status = smb2_lease_create(sr, sr->session->clnt_uuid);
489 + if (status != NT_STATUS_SUCCESS) {
490 + if (op->action_taken == SMB_OACT_CREATED) {
491 + smb_ofile_set_delete_on_close(sr, of);
492 + }
493 + goto cmd_done;
494 + }
495 + }
496 + if (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
497 + smb2_lease_acquire(sr);
498 + } else if (op->op_oplock_level != SMB2_OPLOCK_LEVEL_NONE) {
499 + smb2_oplock_acquire(sr);
500 + }
501 +
502 + /*
503 + * Make this a durable open, but only if:
504 + * (durable handle requested and...)
505 + *
506 + * 1. op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH
507 + * 2. A lease is requested with handle caching
508 + * - for v1, the lease must not be on a directory
509 + * 3. For v2, flags has "persistent" && tree->is_CA
510 + * (when tree not CA, turned off persist above)
511 + *
512 + * Otherwise, DH requests are ignored, so we set
513 + * dh_vers = not durable
514 + */
515 + if ((cctx.cc_in_flags &
516 + (CCTX_DH_REQUEST|CCTX_DH_REQUEST_V2)) != 0 &&
517 + smb_node_is_file(of->f_node) &&
518 + ((op->dh_v2_flags & DH_PERSISTENT) != 0 ||
519 + (op->op_oplock_level == SMB2_OPLOCK_LEVEL_BATCH) ||
520 + (op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE &&
521 + (op->lease_state & OPLOCK_LEVEL_CACHE_HANDLE) != 0))) {
522 + /*
523 + * OK, make this handle "durable"
524 + */
525 + if (op->dh_vers == SMB2_DURABLE_V2) {
526 + (void) memcpy(of->dh_create_guid,
527 + op->create_guid, UUID_LEN);
528 +
529 + if ((op->dh_v2_flags & DH_PERSISTENT) != 0) {
530 + if (smb2_dh_make_persistent(sr, of) == 0) {
531 + of->dh_persist = B_TRUE;
532 + } else {
533 + op->dh_v2_flags = 0;
534 + }
535 + }
536 + }
537 + if (op->dh_vers != SMB2_NOT_DURABLE) {
538 + uint32_t msto;
539 +
540 + of->dh_vers = op->dh_vers;
541 + of->dh_expire_time = 0;
542 +
543 + /*
544 + * Client may provide timeout=0 to request
545 + * the default timeout (in mSec.)
546 + */
547 + msto = op->dh_timeout;
548 + if (msto == 0) {
549 + msto = (of->dh_persist) ?
550 + smb2_persist_timeout :
551 + smb2_dh_def_timeout;
552 + }
553 + if (msto > smb2_dh_max_timeout)
554 + msto = smb2_dh_max_timeout;
555 + op->dh_timeout = msto;
556 + of->dh_timeout_offset = MSEC2NSEC(msto);
557 + }
558 + } else {
559 + op->dh_vers = SMB2_NOT_DURABLE;
560 + op->dh_v2_flags = 0;
561 + }
562 +
563 + /*
300 564 * NB: after the above smb_common_open() success,
301 565 * we have a handle allocated (sr->fid_ofile).
302 566 * If we don't return success, we must close it.
303 567 *
304 568 * Using sr->smb_fid as the file handle for now,
305 569 * though it could later be something larger,
306 570 * (16 bytes) similar to an NFSv4 open handle.
307 571 */
308 - of = sr->fid_ofile;
309 - smb2fid.persistent = 0;
572 +reconnect_done:
573 + smb2fid.persistent = of->f_persistid;
310 574 smb2fid.temporal = sr->smb_fid;
311 575
312 576 switch (sr->tid_tree->t_res_type & STYPE_MASK) {
313 577 case STYPE_DISKTREE:
314 578 case STYPE_PRINTQ:
315 579 if (op->create_options & FILE_DELETE_ON_CLOSE)
316 - smb_ofile_set_delete_on_close(of);
580 + smb_ofile_set_delete_on_close(sr, of);
317 581 break;
318 582 }
319 583
320 584 /*
321 - * Build the Create Context to return; first the
322 - * per-element parts, then the aggregated buffer.
323 - *
324 - * No response for these:
325 - * CCTX_EA_BUFFER
326 - * CCTX_SD_BUFFER
327 - * CCTX_ALLOCATION_SIZE
328 - * CCTX_TIMEWARP_TOKEN
329 - *
330 - * We don't handle these yet.
331 - * CCTX_DH_REQUEST
332 - * CCTX_DH_RECONNECT
333 - * CCTX_REQUEST_LEASE
585 + * Process any outgoing create contexts that need work
586 + * after the open succeeds. Encode happens later.
334 587 */
335 588 if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
336 - cce = &cctx.cc_out_max_access;
337 - uint32_t MaxAccess = 0;
589 + op->maximum_access = 0;
338 590 if (of->f_node != NULL) {
339 - smb_fsop_eaccess(sr, of->f_cr, of->f_node, &MaxAccess);
591 + smb_fsop_eaccess(sr, of->f_cr, of->f_node,
592 + &op->maximum_access);
340 593 }
341 - MaxAccess |= of->f_granted_access;
342 - cce->cce_len = 8;
343 - cce->cce_mbc.max_bytes = 8;
344 - (void) smb_mbc_encodef(&cce->cce_mbc,
345 - "ll", 0, MaxAccess);
594 + op->maximum_access |= of->f_granted_access;
346 595 cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
347 596 }
597 +
348 598 if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
349 599 of->f_node != NULL) {
350 - cce = &cctx.cc_out_file_id;
351 - fsid_t fsid;
600 + op->op_fsid = SMB_NODE_FSID(of->f_node);
601 + cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
602 + }
352 603
353 - fsid = SMB_NODE_FSID(of->f_node);
604 + if ((cctx.cc_in_flags & CCTX_AAPL_EXT) != 0) {
605 + cce = &cctx.cc_out_aapl;
606 + /*
607 + * smb2_aapl_crctx has a variable response depending on
608 + * what the incoming context looks like, so it does all
609 + * the work of building cc_out_aapl, including setting
610 + * cce_len, cce_mbc.max_bytes, and smb_mbc_encode.
611 + * If we see errors getting this, simply omit it from
612 + * the collection of returned create contexts.
613 + */
614 + status = smb2_aapl_crctx(sr,
615 + &cctx.cc_in_aapl.cce_mbc, &cce->cce_mbc);
616 + if (status == 0) {
617 + cce->cce_len = cce->cce_mbc.chain_offset;
618 + cctx.cc_out_flags |= CCTX_AAPL_EXT;
619 + }
620 + status = 0;
621 + }
354 622
355 - cce->cce_len = 32;
356 - cce->cce_mbc.max_bytes = 32;
357 - (void) smb_mbc_encodef(
358 - &cce->cce_mbc, "qll.15.",
359 - op->fileid, /* q */
360 - fsid.val[0], /* l */
361 - fsid.val[1]); /* l */
362 - /* reserved (16 bytes) .15. */
363 - cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
623 + /*
624 + * If a lease was requested, and we got one...
625 + */
626 + if ((cctx.cc_in_flags & CCTX_REQUEST_LEASE) != 0 &&
627 + op->op_oplock_level == SMB2_OPLOCK_LEVEL_LEASE)
628 + cctx.cc_out_flags |= CCTX_REQUEST_LEASE;
629 +
630 + /*
631 + * If a durable handle was requested and we got one...
632 + */
633 + if ((cctx.cc_in_flags & CCTX_DH_REQUEST) != 0 &&
634 + of->dh_vers == SMB2_DURABLE_V1) {
635 + cctx.cc_out_flags |= CCTX_DH_REQUEST;
364 636 }
637 + if ((cctx.cc_in_flags & CCTX_DH_REQUEST_V2) != 0 &&
638 + of->dh_vers == SMB2_DURABLE_V2) {
639 + cctx.cc_out_flags |= CCTX_DH_REQUEST_V2;
640 + }
641 +
642 + /*
643 + * This marks the end of the "body" section and the
644 + * beginning of the "encode" section. Any errors
645 + * encoding the response should use: goto errout
646 + */
647 +cmd_done:
648 + /* Want status visible in the done probe. */
649 + sr->smb2_status = status;
650 + DTRACE_SMB2_DONE(op__Create, smb_request_t *, sr);
651 + if (status != NT_STATUS_SUCCESS)
652 + goto errout;
653 +
654 + /*
655 + * Encode all the create contexts to return.
656 + */
365 657 if (cctx.cc_out_flags) {
366 658 sr->raw_data.max_bytes = smb2_max_trans;
367 - status = smb2_encode_create_ctx(&sr->raw_data, &cctx);
659 + status = smb2_encode_create_ctx(sr, &cctx);
368 660 if (status)
369 661 goto errout;
370 662 }
371 663
372 664 /*
373 - * SMB2 Create reply
665 + * Encode the SMB2 Create reply
374 666 */
667 + attr = &op->fqi.fq_fattr;
375 668 rc = smb_mbc_encodef(
376 669 &sr->reply,
377 670 "wb.lTTTTqqllqqll",
378 671 89, /* StructSize */ /* w */
379 - OplockLevel, /* b */
672 + op->op_oplock_level, /* b */
380 673 op->action_taken, /* l */
381 674 &attr->sa_crtime, /* T */
382 675 &attr->sa_vattr.va_atime, /* T */
383 676 &attr->sa_vattr.va_mtime, /* T */
384 677 &attr->sa_vattr.va_ctime, /* T */
385 678 attr->sa_allocsz, /* q */
386 679 attr->sa_vattr.va_size, /* q */
387 680 attr->sa_dosattr, /* l */
388 681 0, /* reserved2 */ /* l */
389 682 smb2fid.persistent, /* q */
390 683 smb2fid.temporal, /* q */
391 684 0, /* CreateCtxOffset l */
392 685 0); /* CreateCtxLength l */
393 686 if (rc != 0) {
394 687 status = NT_STATUS_UNSUCCESSFUL;
395 688 goto errout;
396 689 }
397 690
398 691 CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
399 692 CreateCtxLength = MBC_LENGTH(&sr->raw_data);
400 693 if (CreateCtxLength != 0) {
401 694 /*
402 695 * Overwrite CreateCtxOffset, CreateCtxLength, pad
403 696 */
404 697 sr->reply.chain_offset -= 8;
405 698 rc = smb_mbc_encodef(
406 699 &sr->reply,
407 700 "ll#C",
408 701 CreateCtxOffset, /* l */
|
↓ open down ↓ |
19 lines elided |
↑ open up ↑ |
409 702 CreateCtxLength, /* l */
410 703 CreateCtxLength, /* # */
411 704 &sr->raw_data); /* C */
412 705 if (rc != 0) {
413 706 status = NT_STATUS_UNSUCCESSFUL;
414 707 goto errout;
415 708 }
416 709 } else {
417 710 (void) smb_mbc_encodef(&sr->reply, ".");
418 711 }
419 - return (SDRC_SUCCESS);
420 712
421 -errout:
422 - if (of != NULL)
423 - smb_ofile_close(of, 0);
713 + if (status != 0) {
714 + errout:
715 + if (of != NULL)
716 + smb_ofile_close(of, 0);
717 + smb2sr_put_error(sr, status);
718 + }
719 + if (op->sd != NULL) {
720 + smb_sd_term(op->sd);
721 + kmem_free(op->sd, sizeof (*op->sd));
722 + }
424 723 if (cctx.cc_out_flags)
425 724 smb2_free_create_ctx(&cctx);
426 - smb2sr_put_error(sr, status);
725 +
427 726 return (SDRC_SUCCESS);
428 727 }
429 728
430 729 /*
431 730 * Decode an SMB2 Create Context buffer into our internal form.
432 - * No policy decisions about what's supported here, just decode.
731 + * Avoid policy decisions about what's supported here, just decode.
433 732 */
434 733 static uint32_t
435 -smb2_decode_create_ctx(mbuf_chain_t *in_mbc, smb2_create_ctx_t *cc)
734 +smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
436 735 {
736 + smb_arg_open_t *op = &sr->arg.open;
437 737 smb2_create_ctx_elem_t *cce;
738 + mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
438 739 mbuf_chain_t name_mbc;
439 740 union {
440 741 uint32_t i;
441 742 char ch[4];
442 743 } cc_name;
443 744 uint32_t status;
444 745 int32_t next_off;
445 746 uint32_t data_len;
446 747 uint16_t data_off;
447 748 uint16_t name_off;
448 749 uint16_t name_len;
449 750 int top_offset;
450 751 int rc;
451 752
753 + /*
754 + * Any break from the loop below before we've decoded
755 + * the entire create context means it was malformatted,
756 + * so we should return INVALID_PARAMETER.
757 + */
452 758 status = NT_STATUS_INVALID_PARAMETER;
453 759 for (;;) {
454 760 cce = NULL;
455 761 top_offset = in_mbc->chain_offset;
456 762 rc = smb_mbc_decodef(
457 763 in_mbc,
458 764 "lww..wl",
459 765 &next_off, /* l */
460 766 &name_off, /* w */
461 767 &name_len, /* w */
462 768 /* reserved .. */
463 769 &data_off, /* w */
464 770 &data_len); /* l */
465 771 if (rc)
466 772 break;
467 773
468 774 /*
469 775 * The Create Context "name", per [MS-SMB] 2.2.13.2
470 776 * They're defined as network-order integers for our
471 777 * switch below. We don't have routines to decode
472 778 * native order, so read as char[4] then ntohl.
473 779 * NB: in SMB3, some of these are 8 bytes.
474 780 */
475 781 if ((top_offset + name_off) < in_mbc->chain_offset)
476 782 break;
477 783 rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc,
478 784 top_offset + name_off, name_len);
479 785 if (rc)
480 786 break;
481 787 rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name);
482 788 if (rc)
483 789 break;
484 790 cc_name.i = ntohl(cc_name.i);
485 791
486 792 switch (cc_name.i) {
487 793 case SMB2_CREATE_EA_BUFFER: /* ("ExtA") */
488 794 cc->cc_in_flags |= CCTX_EA_BUFFER;
489 795 cce = &cc->cc_in_ext_attr;
490 796 break;
491 797 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */
492 798 cc->cc_in_flags |= CCTX_SD_BUFFER;
493 799 cce = &cc->cc_in_sec_desc;
494 800 break;
495 801 case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
496 802 cc->cc_in_flags |= CCTX_DH_REQUEST;
497 803 cce = &cc->cc_in_dh_request;
498 804 break;
499 805 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
500 806 cc->cc_in_flags |= CCTX_DH_RECONNECT;
501 807 cce = &cc->cc_in_dh_reconnect;
502 808 break;
503 809 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */
504 810 cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
505 811 cce = &cc->cc_in_alloc_size;
506 812 break;
507 813 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
508 814 cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
509 815 /* no input data for this */
510 816 break;
511 817 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */
512 818 cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
|
↓ open down ↓ |
51 lines elided |
↑ open up ↑ |
513 819 cce = &cc->cc_in_time_warp;
514 820 break;
515 821 case SMB2_CREATE_QUERY_ON_DISK_ID: /* ("QFid") */
516 822 cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
517 823 /* no input data for this */
518 824 break;
519 825 case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */
520 826 cc->cc_in_flags |= CCTX_REQUEST_LEASE;
521 827 cce = &cc->cc_in_req_lease;
522 828 break;
829 + case SMB2_CREATE_CTX_AAPL: /* ("AAPL") */
830 + cc->cc_in_flags |= CCTX_AAPL_EXT;
831 + cce = &cc->cc_in_aapl;
832 + break;
833 + case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
834 + cc->cc_in_flags |= CCTX_DH_REQUEST_V2;
835 + cce = &cc->cc_in_dh_request_v2;
836 + break;
837 + case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
838 + cc->cc_in_flags |= CCTX_DH_RECONNECT_V2;
839 + cce = &cc->cc_in_dh_reconnect_v2;
840 + break;
841 + case 0x9ccbcf9e: /* SVHDX_OPEN_DEVICE_CONTEXT */
842 + /* 9ccbcf9e 04c1e643 980e158d a1f6ec83 */
843 + /* silently ignore */
844 + break;
523 845 default:
524 846 /*
525 847 * Unknown create context values are normal, and
526 848 * should be ignored. However, in debug mode,
527 849 * let's log them so we know which ones we're
528 850 * not handling (and may want to add).
529 851 */
530 852 #ifdef DEBUG
531 853 cmn_err(CE_NOTE, "unknown create context ID 0x%x",
532 854 cc_name.i);
533 855 #endif
534 856 cce = NULL;
535 857 break;
536 858 }
537 859
538 - if (cce != NULL && data_len != 0) {
539 - if ((data_off & 7) != 0)
540 - break;
541 - if ((top_offset + data_off) < in_mbc->chain_offset)
542 - break;
543 - rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
544 - top_offset + data_off, data_len);
545 - if (rc)
546 - break;
547 - cce->cce_len = data_len;
860 + if (cce == NULL || data_len == 0)
861 + goto next_cc;
862 +
863 + if ((data_off & 7) != 0)
864 + break;
865 + if ((top_offset + data_off) < in_mbc->chain_offset)
866 + break;
867 + rc = MBC_SHADOW_CHAIN(&cce->cce_mbc, in_mbc,
868 + top_offset + data_off, data_len);
869 + if (rc)
870 + break;
871 + cce->cce_len = data_len;
872 +
873 + /*
874 + * Additonal decoding for some create contexts.
875 + */
876 + switch (cc_name.i) {
877 + uint64_t nttime;
878 +
879 + case SMB2_CREATE_SD_BUFFER: /* ("SecD") */
880 + op->sd = kmem_alloc(sizeof (smb_sd_t), KM_SLEEP);
881 + if (smb_decode_sd(&cce->cce_mbc, op->sd) != 0)
882 + goto errout;
883 + break;
884 +
885 + case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */
886 + rc = smb_mbc_decodef(&cce->cce_mbc, "q", &op->dsize);
887 + if (rc != 0)
888 + goto errout;
889 + break;
890 +
891 + case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */
892 + /*
893 + * Support for opening "Previous Versions".
894 + * [MS-SMB2] 2.2.13.2.7 Data is an NT time.
895 + */
896 + rc = smb_mbc_decodef(&cce->cce_mbc,
897 + "q", &nttime);
898 + if (rc != 0)
899 + goto errout;
900 + smb_time_nt_to_unix(nttime, &op->timewarp);
901 + op->create_timewarp = B_TRUE;
902 + break;
903 +
904 + /*
905 + * Note: This handles both V1 and V2 leases,
906 + * which differ only by their length.
907 + */
908 + case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */
909 + if (data_len == 52) {
910 + op->lease_version = 2;
911 + } else if (data_len == 32) {
912 + op->lease_version = 1;
913 + } else {
914 + cmn_err(CE_NOTE, "Cctx RqLs bad len=0x%x",
915 + data_len);
916 + }
917 + rc = smb_mbc_decodef(&cce->cce_mbc, "#cllq",
918 + UUID_LEN, /* # */
919 + op->lease_key, /* c */
920 + &op->lease_state, /* l */
921 + &op->lease_flags, /* l */
922 + &nttime); /* (ignored) q */
923 + if (rc != 0)
924 + goto errout;
925 + if (op->lease_version == 2) {
926 + rc = smb_mbc_decodef(&cce->cce_mbc,
927 + "#cw..",
928 + UUID_LEN,
929 + op->parent_lease_key,
930 + &op->lease_epoch);
931 + if (rc != 0)
932 + goto errout;
933 + } else {
934 + bzero(op->parent_lease_key, UUID_LEN);
935 + }
936 + break;
937 +
938 + case SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2: /* ("DH2C") */
939 + rc = smb_mbc_decodef(&cce->cce_mbc, "qq#cl",
940 + &op->dh_fileid.persistent, /* q */
941 + &op->dh_fileid.temporal, /* q */
942 + UUID_LEN, /* # */
943 + op->create_guid, /* c */
944 + &op->dh_v2_flags); /* l */
945 + if (rc != 0)
946 + goto errout;
947 + break;
948 +
949 + case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
950 + rc = smb_mbc_decodef(&cce->cce_mbc, "qq",
951 + &op->dh_fileid.persistent, /* q */
952 + &op->dh_fileid.temporal); /* q */
953 + if (rc != 0)
954 + goto errout;
955 + bzero(op->create_guid, UUID_LEN);
956 + op->dh_v2_flags = 0;
957 + break;
958 +
959 + case SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2: /* ("DH2Q") */
960 + rc = smb_mbc_decodef(&cce->cce_mbc,
961 + "ll8.#c",
962 + &op->dh_timeout, /* l */
963 + &op->dh_v2_flags, /* l */
964 + /* reserved */ /* 8. */
965 + UUID_LEN, /* # */
966 + op->create_guid); /* c */
967 + if (rc != 0)
968 + goto errout;
969 + break;
970 +
971 + case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
972 + rc = smb_mbc_decodef(&cce->cce_mbc,
973 + "16."); /* reserved */
974 + if (rc != 0)
975 + goto errout;
976 + op->dh_timeout = 0; /* default */
977 + op->dh_v2_flags = 0;
978 + break;
548 979 }
549 980
981 + next_cc:
550 982 if (next_off == 0) {
551 983 /* Normal loop termination */
552 984 status = 0;
553 985 break;
554 986 }
555 987
556 988 if ((next_off & 7) != 0)
557 989 break;
558 990 if ((top_offset + next_off) < in_mbc->chain_offset)
559 991 break;
560 992 if ((top_offset + next_off) > in_mbc->max_bytes)
561 993 break;
562 994 in_mbc->chain_offset = top_offset + next_off;
563 995 }
564 996
997 +errout:
565 998 return (status);
566 999 }
567 1000
568 1001 /*
569 1002 * Encode an SMB2 Create Context buffer from our internal form.
1003 + *
1004 + * Build the Create Context to return; first the
1005 + * per-element parts, then the aggregated buffer.
1006 + *
1007 + * No response for these:
1008 + * CCTX_EA_BUFFER
1009 + * CCTX_SD_BUFFER
1010 + * CCTX_ALLOCATION_SIZE
1011 + * CCTX_TIMEWARP_TOKEN
1012 + *
1013 + * Remember to add code sections to smb2_free_create_ctx()
1014 + * for each section here that encodes a context element.
570 1015 */
571 -/* ARGSUSED */
572 1016 static uint32_t
573 -smb2_encode_create_ctx(mbuf_chain_t *mbc, smb2_create_ctx_t *cc)
1017 +smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
574 1018 {
1019 + smb_arg_open_t *op = &sr->arg.open;
575 1020 smb2_create_ctx_elem_t *cce;
1021 + mbuf_chain_t *mbc = &sr->raw_data;
576 1022 int last_top = -1;
577 1023 int rc;
578 1024
579 1025 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
580 1026 cce = &cc->cc_out_max_access;
1027 +
1028 + cce->cce_mbc.max_bytes = cce->cce_len = 8;
1029 + (void) smb_mbc_encodef(&cce->cce_mbc,
1030 + "ll", 0, op->maximum_access);
1031 +
581 1032 last_top = mbc->chain_offset;
582 1033 rc = smb2_encode_create_ctx_elem(mbc, cce,
583 1034 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
584 1035 if (rc)
585 1036 return (NT_STATUS_INTERNAL_ERROR);
586 1037 (void) smb_mbc_poke(mbc, last_top, "l",
587 1038 mbc->chain_offset - last_top);
588 1039 }
589 1040
590 1041 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
591 1042 cce = &cc->cc_out_file_id;
1043 +
1044 + cce->cce_mbc.max_bytes = cce->cce_len = 32;
1045 + (void) smb_mbc_encodef(
1046 + &cce->cce_mbc, "qll.15.",
1047 + op->fileid, /* q */
1048 + op->op_fsid.val[0], /* l */
1049 + op->op_fsid.val[1]); /* l */
1050 + /* reserved (16 bytes) .15. */
1051 +
592 1052 last_top = mbc->chain_offset;
593 1053 rc = smb2_encode_create_ctx_elem(mbc, cce,
594 1054 SMB2_CREATE_QUERY_ON_DISK_ID);
595 1055 if (rc)
596 1056 return (NT_STATUS_INTERNAL_ERROR);
597 1057 (void) smb_mbc_poke(mbc, last_top, "l",
598 1058 mbc->chain_offset - last_top);
599 1059 }
600 1060
1061 + if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1062 + cce = &cc->cc_out_aapl;
1063 + /* cc_out_aapl already encoded */
1064 +
1065 + last_top = mbc->chain_offset;
1066 + rc = smb2_encode_create_ctx_elem(mbc, cce,
1067 + SMB2_CREATE_CTX_AAPL);
1068 + if (rc)
1069 + return (NT_STATUS_INTERNAL_ERROR);
1070 + (void) smb_mbc_poke(mbc, last_top, "l",
1071 + mbc->chain_offset - last_top);
1072 + }
1073 +
1074 + if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
1075 + cce = &cc->cc_out_req_lease;
1076 +
1077 + cce->cce_mbc.max_bytes = cce->cce_len = 32;
1078 + (void) smb_mbc_encodef(&cce->cce_mbc, "#cllq",
1079 + UUID_LEN, /* # */
1080 + op->lease_key, /* c */
1081 + op->lease_state, /* l */
1082 + op->lease_flags, /* l */
1083 + 0LL); /* q */
1084 + if (op->lease_version == 2) {
1085 + cce->cce_mbc.max_bytes = cce->cce_len = 52;
1086 + (void) smb_mbc_encodef(&cce->cce_mbc,
1087 + "#cw..",
1088 + UUID_LEN,
1089 + op->parent_lease_key,
1090 + op->lease_epoch);
1091 + }
1092 +
1093 + last_top = mbc->chain_offset;
1094 + rc = smb2_encode_create_ctx_elem(mbc, cce,
1095 + SMB2_CREATE_REQUEST_LEASE);
1096 + if (rc)
1097 + return (NT_STATUS_INTERNAL_ERROR);
1098 + (void) smb_mbc_poke(mbc, last_top, "l",
1099 + mbc->chain_offset - last_top);
1100 + }
1101 +
1102 + if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1103 + cce = &cc->cc_out_dh_request;
1104 +
1105 + cce->cce_mbc.max_bytes = cce->cce_len = 8;
1106 + (void) smb_mbc_encodef(&cce->cce_mbc, "q", 0LL);
1107 +
1108 + last_top = mbc->chain_offset;
1109 + rc = smb2_encode_create_ctx_elem(mbc, cce,
1110 + SMB2_CREATE_DURABLE_HANDLE_REQUEST);
1111 + if (rc)
1112 + return (NT_STATUS_INTERNAL_ERROR);
1113 + (void) smb_mbc_poke(mbc, last_top, "l",
1114 + mbc->chain_offset - last_top);
1115 + }
1116 +
1117 + if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1118 + cce = &cc->cc_out_dh_request_v2;
1119 +
1120 + cce->cce_mbc.max_bytes = cce->cce_len = 8;
1121 + (void) smb_mbc_encodef(&cce->cce_mbc, "ll",
1122 + op->dh_timeout, op->dh_v2_flags);
1123 +
1124 + last_top = mbc->chain_offset;
1125 + rc = smb2_encode_create_ctx_elem(mbc, cce,
1126 + SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2);
1127 + if (rc)
1128 + return (NT_STATUS_INTERNAL_ERROR);
1129 + (void) smb_mbc_poke(mbc, last_top, "l",
1130 + mbc->chain_offset - last_top);
1131 + }
1132 +
601 1133 if (last_top >= 0)
602 1134 (void) smb_mbc_poke(mbc, last_top, "l", 0);
603 1135
604 1136 return (0);
605 1137 }
606 1138
607 1139 static int
608 1140 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
609 - smb2_create_ctx_elem_t *cce, uint32_t id)
1141 + smb2_create_ctx_elem_t *cce, uint32_t id)
610 1142 {
611 1143 union {
612 1144 uint32_t i;
613 1145 char ch[4];
614 1146 } cc_name;
615 1147 int rc;
616 1148
617 1149 /* as above */
618 1150 cc_name.i = htonl(id);
619 1151
620 1152 /*
621 1153 * This is the header, per [MS-SMB2] 2.2.13.2
622 1154 * Sorry about the fixed offsets. We know we'll
623 1155 * layout the data part as [name, payload] and
624 1156 * name is a fixed length, so this easy.
625 1157 * The final layout looks like this:
626 - * a: this header (16 bytes)
1158 + * a: this header (16 bytes)
627 1159 * b: the name (4 bytes, 4 pad)
628 1160 * c: the payload (variable)
1161 + * d: padding (to align 8)
629 1162 *
630 1163 * Note that "Next elem." is filled in later.
631 1164 */
632 1165 rc = smb_mbc_encodef(
633 1166 out_mbc, "lwwwwl",
634 1167 0, /* Next offset l */
635 1168 16, /* NameOffset w */
636 1169 4, /* NameLength w */
637 1170 0, /* Reserved w */
638 1171 24, /* DataOffset w */
639 - cce->cce_len); /* l */
1172 + cce->cce_len); /* DataLen l */
640 1173 if (rc)
641 1174 return (rc);
642 1175
643 1176 /*
644 1177 * Now the "name" and payload.
645 1178 */
646 1179 rc = smb_mbc_encodef(
647 1180 out_mbc, "4c4.#C",
648 1181 cc_name.ch, /* 4c4. */
649 1182 cce->cce_len, /* # */
650 1183 &cce->cce_mbc); /* C */
651 1184
1185 + (void) smb_mbc_put_align(out_mbc, 8);
1186 +
652 1187 return (rc);
653 1188 }
654 1189
655 1190 static void
656 1191 smb2_free_create_ctx(smb2_create_ctx_t *cc)
657 1192 {
658 1193 smb2_create_ctx_elem_t *cce;
659 1194
660 1195 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
661 1196 cce = &cc->cc_out_max_access;
662 1197 MBC_FLUSH(&cce->cce_mbc);
663 1198 }
664 1199 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
665 1200 cce = &cc->cc_out_file_id;
666 1201 MBC_FLUSH(&cce->cce_mbc);
667 1202 }
1203 + if (cc->cc_out_flags & CCTX_AAPL_EXT) {
1204 + cce = &cc->cc_out_aapl;
1205 + MBC_FLUSH(&cce->cce_mbc);
1206 + }
1207 + if (cc->cc_out_flags & CCTX_REQUEST_LEASE) {
1208 + cce = &cc->cc_out_req_lease;
1209 + MBC_FLUSH(&cce->cce_mbc);
1210 + }
1211 + if (cc->cc_out_flags & CCTX_DH_REQUEST) {
1212 + cce = &cc->cc_out_dh_request;
1213 + MBC_FLUSH(&cce->cce_mbc);
1214 + }
1215 + if (cc->cc_out_flags & CCTX_DH_REQUEST_V2) {
1216 + cce = &cc->cc_out_dh_request_v2;
1217 + MBC_FLUSH(&cce->cce_mbc);
1218 + }
668 1219 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX