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