1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
14 */
15
16 /*
17 * Dispatch function for SMB2_CREATE
18 * [MS-SMB2] 2.2.13
19 */
20
21 #include <smbsrv/smb2_kproto.h>
22 #include <smbsrv/smb_fsops.h>
23
24 #define DH_PERSISTENT SMB2_DHANDLE_FLAG_PERSISTENT
25
26 /*
27 * 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 /*
44 * Some flags used locally to keep track of which Create Context
45 * names have been provided and/or requested.
46 */
47 #define CCTX_EA_BUFFER 1
48 #define CCTX_SD_BUFFER 2
49 #define CCTX_DH_REQUEST 4
50 #define CCTX_DH_RECONNECT 8
51 #define CCTX_ALLOCATION_SIZE 0x10
52 #define CCTX_QUERY_MAX_ACCESS 0x20
53 #define CCTX_TIMEWARP_TOKEN 0x40
54 #define CCTX_QUERY_ON_DISK_ID 0x80
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
59
60 typedef struct smb2_create_ctx_elem {
61 uint32_t cce_len;
62 mbuf_chain_t cce_mbc;
63 } smb2_create_ctx_elem_t;
64
65 typedef struct smb2_create_ctx {
66 mbuf_chain_t cc_in_mbc;
67 uint_t cc_in_flags; /* CCTX_... */
68 uint_t cc_out_flags; /* CCTX_... */
69 /* Elements we may see in the request. */
70 smb2_create_ctx_elem_t cc_in_ext_attr;
71 smb2_create_ctx_elem_t cc_in_sec_desc;
72 smb2_create_ctx_elem_t cc_in_dh_request;
73 smb2_create_ctx_elem_t cc_in_dh_reconnect;
74 smb2_create_ctx_elem_t cc_in_alloc_size;
75 smb2_create_ctx_elem_t cc_in_time_warp;
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;
80 /* Elements we my place in the response */
81 smb2_create_ctx_elem_t cc_out_max_access;
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;
87 } smb2_create_ctx_t;
88
89 static uint32_t smb2_decode_create_ctx(
90 smb_request_t *, smb2_create_ctx_t *);
91 static uint32_t smb2_encode_create_ctx(
92 smb_request_t *, smb2_create_ctx_t *);
93 static int smb2_encode_create_ctx_elem(
94 mbuf_chain_t *, smb2_create_ctx_elem_t *, uint32_t);
95 static void smb2_free_create_ctx(smb2_create_ctx_t *);
96
97 int smb2_enable_dh = 1;
98
99 smb_sdrc_t
100 smb2_create(smb_request_t *sr)
101 {
102 smb_attr_t *attr;
103 smb2_create_ctx_elem_t *cce;
104 smb2_create_ctx_t cctx;
105 smb_arg_open_t *op = &sr->arg.open;
106 smb_ofile_t *of = NULL;
107 uint16_t StructSize;
108 uint8_t SecurityFlags;
109 uint32_t ImpersonationLevel;
110 uint64_t SmbCreateFlags;
111 uint64_t Reserved4;
112 uint16_t NameOffset;
113 uint16_t NameLength;
114 uint32_t CreateCtxOffset;
115 uint32_t CreateCtxLength;
116 smb2fid_t smb2fid = { 0, 0 };
117 uint32_t status;
118 int dh_flags;
119 int skip;
120 int rc = 0;
121
122 bzero(&cctx, sizeof (cctx));
123 op->create_ctx = &cctx; /* for debugging */
124
125 /*
126 * Paranoia. This will set sr->fid_ofile, so
127 * if we already have one, release it now.
128 */
129 if (sr->fid_ofile != NULL) {
130 smb_ofile_release(sr->fid_ofile);
131 sr->fid_ofile = NULL;
132 }
133
134 /*
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.
143 */
144 rc = smb_mbc_decodef(
145 &sr->smb_data, "wbblqqlllllwwll",
146 &StructSize, /* w */
147 &SecurityFlags, /* b */
148 &op->op_oplock_level, /* b */
149 &ImpersonationLevel, /* l */
150 &SmbCreateFlags, /* q */
151 &Reserved4, /* q */
152 &op->desired_access, /* l */
153 &op->dattr, /* l */
154 &op->share_access, /* l */
155 &op->create_disposition, /* l */
156 &op->create_options, /* l */
157 &NameOffset, /* w */
158 &NameLength, /* w */
159 &CreateCtxOffset, /* l */
160 &CreateCtxLength); /* l */
161 if (rc != 0 || StructSize != 57)
162 return (SDRC_ERROR);
163
164 /*
165 * We're normally positioned at the path name now,
166 * but there could be some padding before it.
167 */
168 skip = (NameOffset + sr->smb2_cmd_hdr) -
169 sr->smb_data.chain_offset;
170 if (skip < 0)
171 return (SDRC_ERROR);
172 if (skip > 0)
173 (void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
174
175 /*
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.
181 */
182 if (NameLength >= SMB_MAXPATHLEN) {
183 status = NT_STATUS_OBJECT_PATH_INVALID;
184 goto errout;
185 }
186 if (NameLength == 0) {
187 op->fqi.fq_path.pn_path = "\\";
188 } else {
189 rc = smb_mbc_decodef(&sr->smb_data, "%#U", sr,
190 NameLength, &op->fqi.fq_path.pn_path);
191 if (rc) {
192 status = NT_STATUS_OBJECT_PATH_INVALID;
193 goto errout;
194 }
195 }
196 op->fqi.fq_dnode = sr->tid_tree->t_snode;
197
198 /*
199 * If there is a "Create Context" payload, decode it.
200 * This may carry things like a security descriptor,
201 * extended attributes, etc. to be used in create.
202 *
203 * The create ctx buffer must start after the headers
204 * and file name, and must be 8-byte aligned.
205 */
206 if (CreateCtxLength != 0) {
207 if ((CreateCtxOffset & 7) != 0 ||
208 (CreateCtxOffset + sr->smb2_cmd_hdr) <
209 sr->smb_data.chain_offset) {
210 status = NT_STATUS_INVALID_PARAMETER;
211 goto errout;
212 }
213
214 rc = MBC_SHADOW_CHAIN(&cctx.cc_in_mbc, &sr->smb_data,
215 sr->smb2_cmd_hdr + CreateCtxOffset, CreateCtxLength);
216 if (rc) {
217 status = NT_STATUS_INVALID_PARAMETER;
218 goto errout;
219 }
220 status = smb2_decode_create_ctx(sr, &cctx);
221 if (status)
222 goto errout;
223 }
224
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 */
235
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 */
241
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;
348 }
349 }
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 */
367 /*
368 * Ignore lease create context (if any)
369 */
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;
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;
410 }
411
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 /*
461 * The real open call. Note: this gets attributes into
462 * op->fqi.fq_fattr (SMB_AT_ALL). We need those below.
463 * When of != NULL, goto errout closes it.
464 */
465 status = smb_common_open(sr);
466 if (status != NT_STATUS_SUCCESS)
467 goto cmd_done;
468 of = sr->fid_ofile;
469
470 /*
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.
475 */
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);
481 }
482
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 /*
564 * NB: after the above smb_common_open() success,
565 * we have a handle allocated (sr->fid_ofile).
566 * If we don't return success, we must close it.
567 *
568 * Using sr->smb_fid as the file handle for now,
569 * though it could later be something larger,
570 * (16 bytes) similar to an NFSv4 open handle.
571 */
572 reconnect_done:
573 smb2fid.persistent = of->f_persistid;
574 smb2fid.temporal = sr->smb_fid;
575
576 switch (sr->tid_tree->t_res_type & STYPE_MASK) {
577 case STYPE_DISKTREE:
578 case STYPE_PRINTQ:
579 if (op->create_options & FILE_DELETE_ON_CLOSE)
580 smb_ofile_set_delete_on_close(sr, of);
581 break;
582 }
583
584 /*
585 * Process any outgoing create contexts that need work
586 * after the open succeeds. Encode happens later.
587 */
588 if (cctx.cc_in_flags & CCTX_QUERY_MAX_ACCESS) {
589 op->maximum_access = 0;
590 if (of->f_node != NULL) {
591 smb_fsop_eaccess(sr, of->f_cr, of->f_node,
592 &op->maximum_access);
593 }
594 op->maximum_access |= of->f_granted_access;
595 cctx.cc_out_flags |= CCTX_QUERY_MAX_ACCESS;
596 }
597
598 if ((cctx.cc_in_flags & CCTX_QUERY_ON_DISK_ID) != 0 &&
599 of->f_node != NULL) {
600 op->op_fsid = SMB_NODE_FSID(of->f_node);
601 cctx.cc_out_flags |= CCTX_QUERY_ON_DISK_ID;
602 }
603
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 }
622
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;
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 */
657 if (cctx.cc_out_flags) {
658 sr->raw_data.max_bytes = smb2_max_trans;
659 status = smb2_encode_create_ctx(sr, &cctx);
660 if (status)
661 goto errout;
662 }
663
664 /*
665 * Encode the SMB2 Create reply
666 */
667 attr = &op->fqi.fq_fattr;
668 rc = smb_mbc_encodef(
669 &sr->reply,
670 "wb.lTTTTqqllqqll",
671 89, /* StructSize */ /* w */
672 op->op_oplock_level, /* b */
673 op->action_taken, /* l */
674 &attr->sa_crtime, /* T */
675 &attr->sa_vattr.va_atime, /* T */
676 &attr->sa_vattr.va_mtime, /* T */
677 &attr->sa_vattr.va_ctime, /* T */
678 attr->sa_allocsz, /* q */
679 attr->sa_vattr.va_size, /* q */
680 attr->sa_dosattr, /* l */
681 0, /* reserved2 */ /* l */
682 smb2fid.persistent, /* q */
683 smb2fid.temporal, /* q */
684 0, /* CreateCtxOffset l */
685 0); /* CreateCtxLength l */
686 if (rc != 0) {
687 status = NT_STATUS_UNSUCCESSFUL;
688 goto errout;
689 }
690
691 CreateCtxOffset = sr->reply.chain_offset - sr->smb2_reply_hdr;
692 CreateCtxLength = MBC_LENGTH(&sr->raw_data);
693 if (CreateCtxLength != 0) {
694 /*
695 * Overwrite CreateCtxOffset, CreateCtxLength, pad
696 */
697 sr->reply.chain_offset -= 8;
698 rc = smb_mbc_encodef(
699 &sr->reply,
700 "ll#C",
701 CreateCtxOffset, /* l */
702 CreateCtxLength, /* l */
703 CreateCtxLength, /* # */
704 &sr->raw_data); /* C */
705 if (rc != 0) {
706 status = NT_STATUS_UNSUCCESSFUL;
707 goto errout;
708 }
709 } else {
710 (void) smb_mbc_encodef(&sr->reply, ".");
711 }
712
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 }
723 if (cctx.cc_out_flags)
724 smb2_free_create_ctx(&cctx);
725
726 return (SDRC_SUCCESS);
727 }
728
729 /*
730 * Decode an SMB2 Create Context buffer into our internal form.
731 * Avoid policy decisions about what's supported here, just decode.
732 */
733 static uint32_t
734 smb2_decode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
735 {
736 smb_arg_open_t *op = &sr->arg.open;
737 smb2_create_ctx_elem_t *cce;
738 mbuf_chain_t *in_mbc = &cc->cc_in_mbc;
739 mbuf_chain_t name_mbc;
740 union {
741 uint32_t i;
742 char ch[4];
743 } cc_name;
744 uint32_t status;
745 int32_t next_off;
746 uint32_t data_len;
747 uint16_t data_off;
748 uint16_t name_off;
749 uint16_t name_len;
750 int top_offset;
751 int rc;
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 */
758 status = NT_STATUS_INVALID_PARAMETER;
759 for (;;) {
760 cce = NULL;
761 top_offset = in_mbc->chain_offset;
762 rc = smb_mbc_decodef(
763 in_mbc,
764 "lww..wl",
765 &next_off, /* l */
766 &name_off, /* w */
767 &name_len, /* w */
768 /* reserved .. */
769 &data_off, /* w */
770 &data_len); /* l */
771 if (rc)
772 break;
773
774 /*
775 * The Create Context "name", per [MS-SMB] 2.2.13.2
776 * They're defined as network-order integers for our
777 * switch below. We don't have routines to decode
778 * native order, so read as char[4] then ntohl.
779 * NB: in SMB3, some of these are 8 bytes.
780 */
781 if ((top_offset + name_off) < in_mbc->chain_offset)
782 break;
783 rc = MBC_SHADOW_CHAIN(&name_mbc, in_mbc,
784 top_offset + name_off, name_len);
785 if (rc)
786 break;
787 rc = smb_mbc_decodef(&name_mbc, "4c", &cc_name);
788 if (rc)
789 break;
790 cc_name.i = ntohl(cc_name.i);
791
792 switch (cc_name.i) {
793 case SMB2_CREATE_EA_BUFFER: /* ("ExtA") */
794 cc->cc_in_flags |= CCTX_EA_BUFFER;
795 cce = &cc->cc_in_ext_attr;
796 break;
797 case SMB2_CREATE_SD_BUFFER: /* ("SecD") */
798 cc->cc_in_flags |= CCTX_SD_BUFFER;
799 cce = &cc->cc_in_sec_desc;
800 break;
801 case SMB2_CREATE_DURABLE_HANDLE_REQUEST: /* ("DHnQ") */
802 cc->cc_in_flags |= CCTX_DH_REQUEST;
803 cce = &cc->cc_in_dh_request;
804 break;
805 case SMB2_CREATE_DURABLE_HANDLE_RECONNECT: /* ("DHnC") */
806 cc->cc_in_flags |= CCTX_DH_RECONNECT;
807 cce = &cc->cc_in_dh_reconnect;
808 break;
809 case SMB2_CREATE_ALLOCATION_SIZE: /* ("AISi") */
810 cc->cc_in_flags |= CCTX_ALLOCATION_SIZE;
811 cce = &cc->cc_in_alloc_size;
812 break;
813 case SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ: /* ("MxAc") */
814 cc->cc_in_flags |= CCTX_QUERY_MAX_ACCESS;
815 /* no input data for this */
816 break;
817 case SMB2_CREATE_TIMEWARP_TOKEN: /* ("TWrp") */
818 cc->cc_in_flags |= CCTX_TIMEWARP_TOKEN;
819 cce = &cc->cc_in_time_warp;
820 break;
821 case SMB2_CREATE_QUERY_ON_DISK_ID: /* ("QFid") */
822 cc->cc_in_flags |= CCTX_QUERY_ON_DISK_ID;
823 /* no input data for this */
824 break;
825 case SMB2_CREATE_REQUEST_LEASE: /* ("RqLs") */
826 cc->cc_in_flags |= CCTX_REQUEST_LEASE;
827 cce = &cc->cc_in_req_lease;
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;
845 default:
846 /*
847 * Unknown create context values are normal, and
848 * should be ignored. However, in debug mode,
849 * let's log them so we know which ones we're
850 * not handling (and may want to add).
851 */
852 #ifdef DEBUG
853 cmn_err(CE_NOTE, "unknown create context ID 0x%x",
854 cc_name.i);
855 #endif
856 cce = NULL;
857 break;
858 }
859
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;
979 }
980
981 next_cc:
982 if (next_off == 0) {
983 /* Normal loop termination */
984 status = 0;
985 break;
986 }
987
988 if ((next_off & 7) != 0)
989 break;
990 if ((top_offset + next_off) < in_mbc->chain_offset)
991 break;
992 if ((top_offset + next_off) > in_mbc->max_bytes)
993 break;
994 in_mbc->chain_offset = top_offset + next_off;
995 }
996
997 errout:
998 return (status);
999 }
1000
1001 /*
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.
1015 */
1016 static uint32_t
1017 smb2_encode_create_ctx(smb_request_t *sr, smb2_create_ctx_t *cc)
1018 {
1019 smb_arg_open_t *op = &sr->arg.open;
1020 smb2_create_ctx_elem_t *cce;
1021 mbuf_chain_t *mbc = &sr->raw_data;
1022 int last_top = -1;
1023 int rc;
1024
1025 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
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
1032 last_top = mbc->chain_offset;
1033 rc = smb2_encode_create_ctx_elem(mbc, cce,
1034 SMB2_CREATE_QUERY_MAXIMAL_ACCESS_REQ);
1035 if (rc)
1036 return (NT_STATUS_INTERNAL_ERROR);
1037 (void) smb_mbc_poke(mbc, last_top, "l",
1038 mbc->chain_offset - last_top);
1039 }
1040
1041 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
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
1052 last_top = mbc->chain_offset;
1053 rc = smb2_encode_create_ctx_elem(mbc, cce,
1054 SMB2_CREATE_QUERY_ON_DISK_ID);
1055 if (rc)
1056 return (NT_STATUS_INTERNAL_ERROR);
1057 (void) smb_mbc_poke(mbc, last_top, "l",
1058 mbc->chain_offset - last_top);
1059 }
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
1133 if (last_top >= 0)
1134 (void) smb_mbc_poke(mbc, last_top, "l", 0);
1135
1136 return (0);
1137 }
1138
1139 static int
1140 smb2_encode_create_ctx_elem(mbuf_chain_t *out_mbc,
1141 smb2_create_ctx_elem_t *cce, uint32_t id)
1142 {
1143 union {
1144 uint32_t i;
1145 char ch[4];
1146 } cc_name;
1147 int rc;
1148
1149 /* as above */
1150 cc_name.i = htonl(id);
1151
1152 /*
1153 * This is the header, per [MS-SMB2] 2.2.13.2
1154 * Sorry about the fixed offsets. We know we'll
1155 * layout the data part as [name, payload] and
1156 * name is a fixed length, so this easy.
1157 * The final layout looks like this:
1158 * a: this header (16 bytes)
1159 * b: the name (4 bytes, 4 pad)
1160 * c: the payload (variable)
1161 * d: padding (to align 8)
1162 *
1163 * Note that "Next elem." is filled in later.
1164 */
1165 rc = smb_mbc_encodef(
1166 out_mbc, "lwwwwl",
1167 0, /* Next offset l */
1168 16, /* NameOffset w */
1169 4, /* NameLength w */
1170 0, /* Reserved w */
1171 24, /* DataOffset w */
1172 cce->cce_len); /* DataLen l */
1173 if (rc)
1174 return (rc);
1175
1176 /*
1177 * Now the "name" and payload.
1178 */
1179 rc = smb_mbc_encodef(
1180 out_mbc, "4c4.#C",
1181 cc_name.ch, /* 4c4. */
1182 cce->cce_len, /* # */
1183 &cce->cce_mbc); /* C */
1184
1185 (void) smb_mbc_put_align(out_mbc, 8);
1186
1187 return (rc);
1188 }
1189
1190 static void
1191 smb2_free_create_ctx(smb2_create_ctx_t *cc)
1192 {
1193 smb2_create_ctx_elem_t *cce;
1194
1195 if (cc->cc_out_flags & CCTX_QUERY_MAX_ACCESS) {
1196 cce = &cc->cc_out_max_access;
1197 MBC_FLUSH(&cce->cce_mbc);
1198 }
1199 if (cc->cc_out_flags & CCTX_QUERY_ON_DISK_ID) {
1200 cce = &cc->cc_out_file_id;
1201 MBC_FLUSH(&cce->cce_mbc);
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 }
1219 }