1 /*
2 * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
26 * Copyright 2024 RackTop Systems, Inc.
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kmem.h>
32 #include <sys/proc.h>
33 #include <sys/lock.h>
34 #include <sys/socket.h>
35 #include <sys/uio.h>
36 #include <sys/random.h>
37 #include <sys/note.h>
38 #include <sys/errno.h>
39 #include <sys/cmn_err.h>
40
41 #include <smb/ntaccess.h>
42 #include <smb/winioctl.h>
43
44 #include <netsmb/smb_osdep.h>
45
46 #include <netsmb/smb.h>
47 #include <netsmb/smb2.h>
48 #include <netsmb/smb_conn.h>
49 #include <netsmb/smb_subr.h>
50 #include <netsmb/smb_tran.h>
51 #include <netsmb/smb_rq.h>
52 #include <netsmb/smb2_rq.h>
53
54 /*
55 * Supported dialects. Keep sorted by number because of how the
56 * vc_maxver check below may truncate this list.
57 */
58 #define NDIALECTS 3
59 static const uint16_t smb2_dialects[NDIALECTS] = {
60 SMB2_DIALECT_0210,
61 SMB2_DIALECT_0300,
62 SMB2_DIALECT_0302,
63 };
64
65 /* Optional capabilities we advertise (none yet). */
66 uint32_t smb2_clnt_caps =
67 SMB2_CAP_LARGE_MTU |
68 SMB2_CAP_ENCRYPTION;
69
70 /* How many credits to ask for during ssn. setup. */
71 uint16_t smb2_ss_req_credits = 64;
72
73 /*
74 * Default timeout values, all in seconds.
75 * Make these tunable (only via mdb for now).
76 */
77 int smb2_timo_notice = 15;
78 int smb2_timo_default = 30;
79 int smb2_timo_logon = 45;
80 int smb2_timo_open = 45;
81 int smb2_timo_read = 45;
82 int smb2_timo_write = 60;
83 int smb2_timo_append = 90;
84
85 /*
86 * This is a special handler for the odd SMB1-to-SMB2 negotiate
87 * response, where an SMB1 request gets an SMB2 response.
88 *
89 * Unlike most parse functions here, this needs to parse both
90 * the SMB2 header and the nego. response body. Note that
91 * the only "SMB2" dialect our SMB1 negotiate offered was
92 * { SMB_DIALECT_SMB2_FF, "SMB 2.???"} so the only valid
93 * SMB2 dialect we should get is: SMB2_DIALECT_02ff
94 */
95 int
smb2_parse_smb1nego_resp(struct smb_rq * rqp)96 smb2_parse_smb1nego_resp(struct smb_rq *rqp)
97 {
98 struct smb_vc *vcp = rqp->sr_vc;
99 struct smb_sopt *sp = &vcp->vc_sopt;
100 struct mdchain *mdp;
101 uint16_t length = 0;
102 int error;
103
104 /* Get pointer to response data */
105 smb_rq_getreply(rqp, &mdp);
106
107 error = smb2_rq_parsehdr(rqp);
108 if (error != 0)
109 return (error);
110
111 /*
112 * Parse SMB 2/3 Negotiate Response
113 * We are already pointing to begining of Response data
114 */
115
116 /* Check structure size is 65 */
117 md_get_uint16le(mdp, &length);
118 if (length != 65)
119 return (EBADRPC);
120
121 /* Get Security Mode */
122 md_get_uint16le(mdp, &sp->sv2_security_mode);
123
124 /* Get Dialect. */
125 error = md_get_uint16le(mdp, &sp->sv_proto);
126 if (error != 0)
127 return (error);
128
129 /* What dialect did we get? */
130 if (sp->sv_proto != SMB2_DIALECT_02ff) {
131 SMBERROR("Unknown dialect 0x%x\n", sp->sv_proto);
132 return (EINVAL);
133 }
134 /* Set our (internal) SMB1 dialect also. */
135 sp->sv_proto = SMB_DIALECT_SMB2_FF;
136
137 /*
138 * This request did not go through smb2_iod_addrq and
139 * smb2_iod_process() so the SMB2 message ID state is
140 * behind what we need it to be. Fix that.
141 */
142 vcp->vc2_next_message_id = 1;
143 vcp->vc2_limit_message_id = 2;
144
145 /*
146 * Skip parsing the rest. We'll get a normal
147 * SMB2 negotiate next and do negotiate then.
148 */
149 return (0);
150 }
151
152 int
smb2_smb_negotiate(struct smb_vc * vcp,struct smb_cred * scred)153 smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
154 {
155 smb_sopt_t *sp = &vcp->vc_sopt;
156 smbioc_ssn_work_t *wk = &vcp->vc_work;
157 struct smb_rq *rqp = NULL;
158 struct mbchain *mbp = NULL;
159 struct mdchain *mdp = NULL;
160 uint16_t *ndialects_p;
161 uint16_t ndialects = NDIALECTS;
162 boolean_t will_sign = B_FALSE;
163 uint16_t length = 0;
164 uint16_t security_mode;
165 uint16_t sec_buf_off;
166 uint16_t sec_buf_len;
167 int err, i;
168
169 /*
170 * Compute security mode
171 */
172 if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
173 security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
174 } else {
175 security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
176 }
177
178 err = smb_rq_alloc(VCTOCP(vcp), SMB2_NEGOTIATE, scred, &rqp);
179 if (err)
180 return (err);
181
182 /*
183 * Build the SMB2 negotiate request.
184 */
185 smb_rq_getrequest(rqp, &mbp);
186 mb_put_uint16le(mbp, 36); /* Struct Size */
187 ndialects_p = mb_reserve(mbp, 2); /* Dialect Count */
188 mb_put_uint16le(mbp, security_mode);
189 mb_put_uint16le(mbp, 0); /* Reserved */
190 mb_put_uint32le(mbp, smb2_clnt_caps);
191 mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM);
192 mb_put_uint64le(mbp, 0); /* Start Time */
193 for (i = 0; i < ndialects; i++) { /* Dialects */
194 if (smb2_dialects[i] > vcp->vc_maxver)
195 break;
196 mb_put_uint16le(mbp, smb2_dialects[i]);
197 }
198 *ndialects_p = htoles(i);
199
200 /*
201 * Do the OTW call.
202 */
203 err = smb2_rq_internal(rqp, smb2_timo_default);
204 if (err) {
205 goto errout;
206 }
207 /* Should only get status success. */
208 if (rqp->sr_error != NT_STATUS_SUCCESS) {
209 err = ENOTSUP;
210 goto errout;
211 }
212
213 /*
214 * Decode the negotiate response
215 */
216 smb_rq_getreply(rqp, &mdp);
217
218 md_get_uint16le(mdp, &length); /* Struct size */
219 if (length != 65) {
220 err = EBADRPC;
221 goto errout;
222 }
223
224 md_get_uint16le(mdp, &sp->sv2_security_mode);
225 md_get_uint16le(mdp, &sp->sv_proto); /* dialect */
226 md_get_uint16le(mdp, NULL); /* reserved */
227 md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM);
228 md_get_uint32le(mdp, &sp->sv2_capabilities);
229 md_get_uint32le(mdp, &sp->sv2_maxtransact);
230 md_get_uint32le(mdp, &sp->sv2_maxread);
231 md_get_uint32le(mdp, &sp->sv2_maxwrite);
232 md_get_uint64le(mdp, NULL); /* curr_time */
233 md_get_uint64le(mdp, NULL); /* boot_time */
234
235 /* Get Security Blob offset and length */
236 md_get_uint16le(mdp, &sec_buf_off);
237 err = md_get_uint16le(mdp, &sec_buf_len);
238 if (err != 0)
239 goto errout;
240 md_get_uint32le(mdp, NULL); /* reserved */
241
242 /*
243 * Security buffer offset is from the beginning of SMB 2 Header
244 * Calculate how much further we have to go to get to it.
245 * Current offset is: SMB2_HDRLEN + 64
246 */
247 if (sec_buf_len != 0) {
248 int skip = (int)sec_buf_off - (SMB2_HDRLEN + 64);
249 if (skip < 0) {
250 err = EBADRPC;
251 goto errout;
252 }
253 if (skip > 0) {
254 md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
255 }
256
257 /*
258 * Copy the security blob out to user space.
259 * Buffer addr,size in vc_auth_rbuf,rlen
260 */
261 if (wk->wk_u_auth_rlen < sec_buf_len) {
262 SMBSDEBUG("vc_auth_rbuf too small");
263 /* Give caller required size. */
264 wk->wk_u_auth_rlen = sec_buf_len;
265 err = EMSGSIZE;
266 goto errout;
267 }
268 wk->wk_u_auth_rlen = sec_buf_len;
269 err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
270 sec_buf_len, MB_MUSER);
271 if (err) {
272 goto errout;
273 }
274 }
275
276 /*
277 * Decoded everything. Now decisions.
278 */
279
280 /*
281 * Turn on signing if either Server or client requires it,
282 * except: anonymous sessions can't sign.
283 */
284 if ((sp->sv2_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
285 (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED))
286 will_sign = B_TRUE;
287 if (vcp->vc_vopt & SMBVOPT_ANONYMOUS)
288 will_sign = B_FALSE;
289 SMBSDEBUG("Security signatures: %d", (int)will_sign);
290 if (will_sign)
291 vcp->vc_flags |= SMBV_SIGNING;
292
293 /*
294 * ToDo - too many places are looking at sv_caps, so for now
295 * set the SMB1 capabilities too. Later we should use the
296 * sv2_capabilities for SMB 2+.
297 */
298 sp->sv_caps = (SMB_CAP_UNICODE |
299 SMB_CAP_LARGE_FILES |
300 SMB_CAP_STATUS32 |
301 SMB_CAP_LARGE_READX |
302 SMB_CAP_LARGE_WRITEX |
303 SMB_CAP_EXT_SECURITY);
304 if (sp->sv2_capabilities & SMB2_CAP_DFS)
305 sp->sv_caps |= SMB_CAP_DFS;
306
307 if (sp->sv_proto >= SMB2_DIALECT_0300 &&
308 (sp->sv2_capabilities & SMB2_CAP_ENCRYPTION) != 0) {
309 nsmb_crypt_init_mech(vcp);
310 }
311
312 /*
313 * A few sanity checks on what we received,
314 * becuse we will send these in ssnsetup.
315 *
316 * Maximum outstanding requests (we care),
317 * and Max. VCs (we only use one). Also,
318 * MaxBufferSize lower limit per spec.
319 */
320 if (sp->sv2_maxread < 0x8000) {
321 SMBSDEBUG("maxread too small\n");
322 err = ENOTSUP;
323 goto errout;
324 }
325 if (sp->sv2_maxwrite < 0x8000) {
326 SMBSDEBUG("maxwrite too small\n");
327 err = ENOTSUP;
328 goto errout;
329 }
330 if (sp->sv2_maxtransact < 0x4000) {
331 SMBSDEBUG("maxtransact too small\n");
332 err = ENOTSUP;
333 goto errout;
334 }
335
336 /* Here too, fill SMB1 fields */
337 vcp->vc_rxmax = sp->sv2_maxread;
338 vcp->vc_wxmax = sp->sv2_maxwrite;
339 vcp->vc_txmax = sp->sv2_maxtransact;
340
341 smb_rq_done(rqp);
342 return (0);
343
344 errout:
345 smb_rq_done(rqp);
346 if (err == 0)
347 err = EBADRPC;
348 return (err);
349 }
350
351 int
smb2_smb_ssnsetup(struct smb_vc * vcp,struct smb_cred * scred)352 smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
353 {
354 smbioc_ssn_work_t *wk = &vcp->vc_work;
355 struct smb_rq *rqp = NULL;
356 struct mbchain *mbp = NULL;
357 struct mdchain *mdp = NULL;
358 char *sb;
359 int err, ret;
360 uint16_t sblen;
361 uint16_t length = 0;
362 uint16_t session_flags;
363 uint16_t sec_buf_off;
364 uint16_t sec_buf_len;
365 uint8_t security_mode;
366
367 /*
368 * Compute security mode
369 */
370 if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
371 security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
372 } else {
373 security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
374 }
375
376 sb = wk->wk_u_auth_wbuf.lp_ptr;
377 sblen = (uint16_t)wk->wk_u_auth_wlen;
378
379 err = smb_rq_alloc(VCTOCP(vcp), SMB2_SESSION_SETUP, scred, &rqp);
380 if (err != 0) {
381 ret = err;
382 goto out;
383 }
384
385 /*
386 * Always ask for some credits. The server usually will
387 * only grant these credits once we've authenticated.
388 */
389 rqp->sr2_creditsrequested = smb2_ss_req_credits;
390
391 /*
392 * Build the SMB Session Setup request.
393 */
394 smb_rq_getrequest(rqp, &mbp);
395
396 mb_put_uint16le(mbp, 25); /* Struct size */
397 mb_put_uint8(mbp, 0); /* VcNumber */
398 mb_put_uint8(mbp, security_mode);
399 mb_put_uint32le(mbp, smb2_clnt_caps); /* Capabilities */
400 mb_put_uint32le(mbp, 0); /* Channel - always 0 */
401
402 /*
403 * Security buffer offset and length. Normally would use
404 * ptr = mb_reserve() and fill in later, but since only a
405 * small amount of fixed-size stuff follows (12 bytes)
406 * we can just compute the offset now.
407 */
408 mb_put_uint16le(mbp, mbp->mb_count + 12);
409 mb_put_uint16le(mbp, sblen);
410 mb_put_uint64le(mbp, vcp->vc2_prev_session_id);
411 err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
412 if (err != 0) {
413 ret = err;
414 goto out;
415 }
416
417 /*
418 * Run the request. The return value here should be the
419 * return from this function, unless we fail decoding.
420 * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
421 * the caller expects EINPROGRESS for that case.
422 */
423 ret = smb2_rq_internal(rqp, smb2_timo_logon);
424 if (ret != 0)
425 goto out;
426 switch (rqp->sr_error) {
427 case NT_STATUS_SUCCESS:
428 break;
429 case NT_STATUS_MORE_PROCESSING_REQUIRED:
430 /* Keep going, but return... */
431 ret = EINPROGRESS;
432 break;
433 default:
434 ret = EAUTH;
435 goto out;
436 }
437
438 /*
439 * After the first Session Setup Response,
440 * save the session ID.
441 */
442 if (vcp->vc2_session_id == 0)
443 vcp->vc2_session_id = rqp->sr2_rspsessionid;
444
445 /*
446 * Decode the session setup response
447 */
448 smb_rq_getreply(rqp, &mdp);
449
450 md_get_uint16le(mdp, &length); /* Struct size */
451 if (length != 9) {
452 ret = EBADRPC;
453 goto out;
454 }
455
456 md_get_uint16le(mdp, &session_flags);
457 md_get_uint16le(mdp, &sec_buf_off);
458 err = md_get_uint16le(mdp, &sec_buf_len);
459 if (err != 0) {
460 ret = err;
461 goto out;
462 }
463
464 /*
465 * Security buffer offset is from the beginning of SMB 2 Header
466 * Calculate how much further we have to go to get to it.
467 * Current offset is: SMB2_HDRLEN + 8
468 */
469 if (sec_buf_len != 0) {
470 int skip = (int)sec_buf_off - (SMB2_HDRLEN + 8);
471 if (skip < 0) {
472 ret = EBADRPC;
473 goto out;
474 }
475 if (skip > 0) {
476 md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
477 }
478
479 /*
480 * Copy the security blob out to user space.
481 * Buffer addr,size in vc_auth_rbuf,rlen
482 */
483 if (wk->wk_u_auth_rlen < sec_buf_len) {
484 SMBSDEBUG("vc_auth_rbuf too small");
485 /* Give caller required size. */
486 wk->wk_u_auth_rlen = sec_buf_len;
487 ret = EMSGSIZE;
488 goto out;
489 }
490 wk->wk_u_auth_rlen = sec_buf_len;
491 err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
492 sec_buf_len, MB_MUSER);
493 if (err != 0) {
494 ret = err;
495 goto out;
496 }
497 }
498
499 if (ret == 0) {
500 /*
501 * Final session setup response
502 */
503 vcp->vc_sopt.sv2_sessflags = session_flags;
504 if ((vcp->vc_sopt.sv2_sessflags &
505 SMB2_SESSION_FLAG_ENCRYPT_DATA) != 0 &&
506 vcp->vc3_crypt_mech == NULL) {
507 cmn_err(CE_NOTE, "SMB server requires encryption"
508 " but no crypto mechanism found");
509 ret = ENOTSUP;
510 goto out;
511 }
512 }
513
514 out:
515 if (err != 0 && err != EINPROGRESS) {
516 /* Session ID no longer valid. */
517 vcp->vc2_session_id = 0;
518 }
519 if (rqp)
520 smb_rq_done(rqp);
521
522 return (ret);
523 }
524
525 int
smb2_smb_logoff(struct smb_vc * vcp,struct smb_cred * scred)526 smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
527 {
528 struct smb_rq *rqp;
529 struct mbchain *mbp;
530 int error;
531
532 if (vcp->vc2_session_id == 0)
533 return (0);
534
535 error = smb_rq_alloc(VCTOCP(vcp), SMB2_LOGOFF, scred, &rqp);
536 if (error)
537 return (error);
538
539 /*
540 * Fill in Logoff part
541 */
542 smb_rq_getrequest(rqp, &mbp);
543 mb_put_uint16le(mbp, 4); /* Struct size */
544 mb_put_uint16le(mbp, 0); /* Reserved */
545
546 /*
547 * Run this with a relatively short timeout. (5 sec.)
548 * We don't really care about the result here.
549 * Also, don't reconnect for this, of course!
550 */
551 rqp->sr_flags |= SMBR_NORECONNECT;
552 error = smb2_rq_internal(rqp, 5);
553 smb_rq_done(rqp);
554 return (error);
555 }
556
557 int
smb2_smb_treeconnect(struct smb_share * ssp,struct smb_cred * scred)558 smb2_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
559 {
560 struct smb_vc *vcp;
561 struct smb_rq *rqp = NULL;
562 struct mbchain *mbp;
563 struct mdchain *mdp;
564 char *unc_name = NULL;
565 int error, unc_len;
566 uint16_t plen, *plenp;
567 uint16_t options = 0;
568 uint_t cnt0;
569 uint32_t net_stype;
570 uint16_t structure_size = 0;
571 uint8_t smb2stype;
572
573 vcp = SSTOVC(ssp);
574
575 /*
576 * Make this a "VC-level" request, so it will have
577 * rqp->sr_share == NULL, and smb_iod_sendrq()
578 * will send it with TID = SMB_TID_UNKNOWN
579 *
580 * This also serves to bypass the wait for
581 * share state changes, which this call is
582 * trying to carry out.
583 */
584 error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_CONNECT, scred, &rqp);
585 if (error)
586 return (error);
587
588 /*
589 * Build the UNC name, i.e. "//server/share"
590 * but with backslashes of course.
591 * size math: three slashes, one null.
592 */
593 unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
594 unc_name = kmem_alloc(unc_len, KM_SLEEP);
595 (void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
596 vcp->vc_srvname, ssp->ss_name);
597 SMBSDEBUG("unc_name: \"%s\"", unc_name);
598
599 /*
600 * Build the request.
601 */
602 mbp = &rqp->sr_rq;
603
604 mb_put_uint16le(mbp, 9); /* Struct size */
605 mb_put_uint16le(mbp, 0); /* Reserved */
606 mb_put_uint16le(mbp, 72); /* Path Offset */
607
608 /*
609 * Fill in path length after we put the string, so we know
610 * the length after conversion from UTF-8 to UCS-2.
611 */
612 plenp = mb_reserve(mbp, 2);
613 cnt0 = mbp->mb_count;
614
615 /* UNC resource name (without the null) */
616 error = smb_put_dmem(mbp, vcp, unc_name, unc_len - 1,
617 SMB_CS_NONE, NULL);
618 if (error)
619 goto out;
620
621 /* Now go back and fill in the path length. */
622 plen = (uint16_t)(mbp->mb_count - cnt0);
623 *plenp = htoles(plen);
624
625 /*
626 * Run the request.
627 *
628 * Using NOINTR_RECV because we don't want to risk
629 * missing a successful tree connect response,
630 * which would "leak" Tree IDs.
631 */
632 rqp->sr_flags |= SMBR_NOINTR_RECV;
633 error = smb2_rq_simple(rqp);
634 SMBSDEBUG("%d\n", error);
635 if (error) {
636 /*
637 * If we get the server name wrong, i.e. due to
638 * mis-configured name services, this will be
639 * NT_STATUS_DUPLICATE_NAME. Log this error.
640 */
641 SMBERROR("(%s) failed, status=0x%x",
642 unc_name, rqp->sr_error);
643 goto out;
644 }
645
646 /*
647 * Parse the tree connect response
648 */
649 smb_rq_getreply(rqp, &mdp);
650
651 /* Check structure size is 16 */
652 md_get_uint16le(mdp, &structure_size);
653 if (structure_size != 16) {
654 error = EBADRPC;
655 goto out;
656 }
657
658 md_get_uint8(mdp, &smb2stype);
659 md_get_uint8(mdp, NULL); /* reserved */
660 md_get_uint32le(mdp, &ssp->ss2_share_flags);
661 md_get_uint32le(mdp, &ssp->ss2_share_caps);
662 error = md_get_uint32le(mdp, NULL); /* maxAccessRights */
663 if (error)
664 goto out;
665
666 /*
667 * If the share requires encryption, make sure we can.
668 */
669 if ((ssp->ss2_share_flags & SMB2_SHAREFLAG_ENCRYPT_DATA) != 0 &&
670 vcp->vc3_crypt_mech == NULL) {
671 cmn_err(CE_NOTE, "SMB share requires encryption"
672 " but no crypto mechanism found");
673 error = ENOTSUP;
674 goto out;
675 }
676
677 /*
678 * Convert SMB2 share type to NetShareEnum share type
679 */
680 switch (smb2stype) {
681 case SMB2_SHARE_TYPE_DISK:
682 net_stype = STYPE_DISKTREE;
683 break;
684 case SMB2_SHARE_TYPE_PIPE:
685 net_stype = STYPE_IPC;
686 break;
687 case SMB2_SHARE_TYPE_PRINT:
688 net_stype = STYPE_PRINTQ;
689 break;
690 default:
691 net_stype = STYPE_UNKNOWN;
692 break;
693 }
694 ssp->ss_type = net_stype;
695
696 /*
697 * Map SMB 2/3 capabilities to SMB 1 options,
698 * for common code that looks there.
699 */
700 if (ssp->ss2_share_caps & SMB2_SHARE_CAP_DFS)
701 options |= SMB_SHARE_IS_IN_DFS;
702
703 /* Update share state */
704 SMB_SS_LOCK(ssp);
705 ssp->ss2_tree_id = rqp->sr2_rsptreeid;
706 ssp->ss_vcgenid = vcp->vc_genid;
707 ssp->ss_options = options;
708 ssp->ss_flags |= SMBS_CONNECTED;
709 SMB_SS_UNLOCK(ssp);
710
711 out:
712 if (unc_name)
713 kmem_free(unc_name, unc_len);
714 smb_rq_done(rqp);
715 return (error);
716 }
717
718 int
smb2_smb_treedisconnect(struct smb_share * ssp,struct smb_cred * scred)719 smb2_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
720 {
721 struct smb_vc *vcp;
722 struct smb_rq *rqp;
723 struct mbchain *mbp;
724 int error;
725
726 if (ssp->ss2_tree_id == SMB2_TID_UNKNOWN)
727 return (0);
728
729 /*
730 * Build this as a "VC-level" request, so it will
731 * avoid testing the _GONE flag on the share,
732 * which has already been set at this point.
733 * Add the share pointer "by hand" below, so
734 * smb_iod_sendrq will plug in the TID.
735 */
736 vcp = SSTOVC(ssp);
737 error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_DISCONNECT, scred, &rqp);
738 if (error)
739 return (error);
740 rqp->sr_share = ssp; /* See "by hand" above. */
741
742 /*
743 * Fill in SMB2 Tree Disconnect part
744 */
745 smb_rq_getrequest(rqp, &mbp);
746 mb_put_uint16le(mbp, 4); /* Struct size */
747 mb_put_uint16le(mbp, 0); /* Reserved */
748
749 /*
750 * Run this with a relatively short timeout. (5 sec.)
751 * We don't really care about the result here, but we
752 * do need to make sure we send this out, or we could
753 * "leak" active tree IDs on interrupt or timeout.
754 * The NOINTR_SEND flag makes this request immune to
755 * interrupt or timeout until the send is done.
756 * Also, don't reconnect for this, of course!
757 */
758 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
759 error = smb2_rq_simple_timed(rqp, 5);
760
761 smb_rq_done(rqp);
762
763 /* Whether we get an error or not... */
764 ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
765
766 return (error);
767 }
768
769 /*
770 * Put the name, first skipping a leading slash.
771 */
772 static int
put_name_skip_slash(struct mbchain * mbp,struct mbchain * name_mbp)773 put_name_skip_slash(struct mbchain *mbp, struct mbchain *name_mbp)
774 {
775 mblk_t *m;
776
777 if (name_mbp == NULL)
778 return (0);
779 m = name_mbp->mb_top;
780 if (m == NULL)
781 return (0);
782
783 /* Use a dup of the message to leave the passed one untouched. */
784 m = dupmsg(m);
785 if (m == NULL)
786 return (ENOSR);
787
788 if (MBLKL(m) >= 2 &&
789 m->b_rptr[0] == '\\' &&
790 m->b_rptr[1] == '\0')
791 m->b_rptr += 2;
792
793 return (mb_put_mbuf(mbp, m));
794 }
795
796 /*
797 * Modern create/open of file or directory.
798 *
799 * The passed name is a full path relative to the share root.
800 * Callers prepare paths with a leading slash (backslash)
801 * because that's what SMB1 expected. SMB2 does not allow the
802 * leading slash here. To make life simpler for callers skip a
803 * leading slash here. That allows callers use use common logic
804 * for building paths without needing to know if the connection
805 * is using SMB1 or SMB2 (just build paths with a leading slash).
806 */
807 int
smb2_smb_ntcreate(struct smb_share * ssp,struct mbchain * name_mb,struct mbchain * cctx_in,struct mdchain * cctx_out,uint32_t cr_flags,uint32_t req_acc,uint32_t efa,uint32_t share_acc,uint32_t open_disp,uint32_t createopt,uint32_t impersonate,struct smb_cred * scrp,smb2fid_t * fidp,uint32_t * cr_act_p,struct smbfattr * fap)808 smb2_smb_ntcreate(
809 struct smb_share *ssp,
810 struct mbchain *name_mb,
811 struct mbchain *cctx_in,
812 struct mdchain *cctx_out,
813 uint32_t cr_flags, /* create flags */
814 uint32_t req_acc, /* requested access */
815 uint32_t efa, /* ext. file attrs (DOS attr +) */
816 uint32_t share_acc,
817 uint32_t open_disp, /* open disposition */
818 uint32_t createopt, /* NTCREATEX_OPTIONS_ */
819 uint32_t impersonate, /* NTCREATEX_IMPERSONATION_... */
820 struct smb_cred *scrp,
821 smb2fid_t *fidp, /* returned FID */
822 uint32_t *cr_act_p, /* optional create action */
823 struct smbfattr *fap) /* optional attributes */
824 {
825 struct smbfattr fa;
826 struct smb_rq *rqp;
827 struct mbchain *mbp;
828 struct mdchain *mdp;
829 uint16_t *name_offp;
830 uint16_t *name_lenp;
831 uint32_t *cctx_offp;
832 uint32_t *cctx_lenp;
833 uint32_t rcc_off, rcc_len;
834 smb2fid_t smb2_fid;
835 uint64_t llongint;
836 uint32_t longint, createact;
837 uint_t off, len;
838 int error;
839 uint16_t StructSize = 57; // [MS-SMB2]
840
841 bzero(&fa, sizeof (fa));
842
843 error = smb_rq_alloc(SSTOCP(ssp), SMB2_CREATE, scrp, &rqp);
844 if (error)
845 return (error);
846
847 /*
848 * Todo: Assemble creat contexts (if needed)
849 * into an mbchain.
850 */
851
852 /*
853 * Build the SMB 2/3 Create Request
854 */
855 smb_rq_getrequest(rqp, &mbp);
856 mb_put_uint16le(mbp, StructSize);
857 mb_put_uint8(mbp, 0); /* Security flags */
858 mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE); /* Oplock level */
859 mb_put_uint32le(mbp, impersonate); /* Impersonation Level */
860 mb_put_uint64le(mbp, cr_flags);
861 mb_put_uint64le(mbp, 0); /* Reserved */
862 mb_put_uint32le(mbp, req_acc);
863 mb_put_uint32le(mbp, efa); /* File attributes */
864 mb_put_uint32le(mbp, share_acc); /* Share access */
865 mb_put_uint32le(mbp, open_disp); /* Create disposition */
866 mb_put_uint32le(mbp, createopt); /* Create options */
867
868 name_offp = mb_reserve(mbp, 2); /* Name offset */
869 name_lenp = mb_reserve(mbp, 2); /* Name len */
870
871 cctx_offp = mb_reserve(mbp, 4); /* Context offset */
872 cctx_lenp = mb_reserve(mbp, 4); /* Context len */
873
874 /*
875 * Put the file name, which is provided in an mbchain.
876 * If there's a leading slash, skip it (see above).
877 */
878 off = mbp->mb_count;
879 *name_offp = htoles((uint16_t)off);
880 error = put_name_skip_slash(mbp, name_mb);
881 if (error)
882 goto out;
883 len = mbp->mb_count - off;
884 *name_lenp = htoles((uint16_t)len);
885
886 /*
887 * Now the create contexts (if provided)
888 */
889 if (cctx_in != NULL) {
890 off = mbp->mb_count;
891 *cctx_offp = htolel((uint32_t)off);
892 mb_put_mbchain(mbp, cctx_in);
893 len = mbp->mb_count - off;
894 *cctx_lenp = htolel((uint32_t)len);
895 } else {
896 *cctx_offp = 0;
897 *cctx_lenp = 0;
898 }
899
900 /*
901 * If we didn't put any variable-sized data, we'll have
902 * put exactly 56 bytes of data, and we need to pad out
903 * this request to the 57 bytes StructSize indicated.
904 */
905 if (mbp->mb_count < (StructSize + SMB2_HDRLEN))
906 mb_put_uint8(mbp, 0);
907
908 /*
909 * Don't want to risk missing a successful
910 * open response, or we could "leak" FIDs.
911 */
912 rqp->sr_flags |= SMBR_NOINTR_RECV;
913 error = smb2_rq_simple_timed(rqp, smb2_timo_open);
914 if (error)
915 goto out;
916
917 /*
918 * Parse SMB 2/3 Create Response
919 */
920 smb_rq_getreply(rqp, &mdp);
921
922 /* Check structure size is 89 */
923 error = md_get_uint16le(mdp, &StructSize);
924 if (StructSize != 89) {
925 error = EBADRPC;
926 goto out;
927 }
928
929 md_get_uint8(mdp, NULL); /* oplock lvl granted */
930 md_get_uint8(mdp, NULL); /* mbz */
931 md_get_uint32le(mdp, &createact); /* create_action */
932 md_get_uint64le(mdp, &llongint); /* creation time */
933 smb_time_NT2local(llongint, &fa.fa_createtime);
934 md_get_uint64le(mdp, &llongint); /* access time */
935 smb_time_NT2local(llongint, &fa.fa_atime);
936 md_get_uint64le(mdp, &llongint); /* write time */
937 smb_time_NT2local(llongint, &fa.fa_mtime);
938 md_get_uint64le(mdp, &llongint); /* change time */
939 smb_time_NT2local(llongint, &fa.fa_ctime);
940 md_get_uint64le(mdp, &llongint); /* allocation size */
941 fa.fa_allocsz = llongint;
942 md_get_uint64le(mdp, &llongint); /* EOF position */
943 fa.fa_size = llongint;
944 md_get_uint32le(mdp, &longint); /* attributes */
945 fa.fa_attr = longint;
946 md_get_uint32le(mdp, NULL); /* reserved */
947
948 /* Get SMB 2/3 File ID and create user fid to return */
949 md_get_uint64le(mdp, &smb2_fid.fid_persistent);
950 error = md_get_uint64le(mdp, &smb2_fid.fid_volatile);
951 if (error)
952 goto out;
953
954 /* Get Context Offset */
955 error = md_get_uint32le(mdp, &rcc_off);
956 if (error)
957 goto out;
958 /* Get Context Length */
959 error = md_get_uint32le(mdp, &rcc_len);
960 if (error)
961 goto out;
962
963 /*
964 * If the caller wants the returned create contexts, parse.
965 * Context offset is from the beginning of SMB 2/3 Header
966 * Calculate how much further we have to go to get to it.
967 * Current offset is: SMB2_HDRLEN + 88
968 */
969 if (rcc_len != 0) {
970 int skip = (int)rcc_off - (SMB2_HDRLEN + 88);
971 if (skip < 0) {
972 error = EBADRPC;
973 goto out;
974 }
975 if (skip > 0) {
976 md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
977 }
978 if (cctx_out != NULL) {
979 mblk_t *m = NULL;
980 error = md_get_mbuf(mdp, rcc_len, &m);
981 if (error)
982 goto out;
983 md_initm(cctx_out, m);
984 }
985 }
986
987 out:
988 smb_rq_done(rqp);
989 if (error)
990 return (error);
991
992 *fidp = smb2_fid;
993 if (cr_act_p)
994 *cr_act_p = createact;
995 if (fap)
996 *fap = fa; /* struct copy */
997
998 return (0);
999 }
1000
1001 int
smb2_smb_close(struct smb_share * ssp,smb2fid_t * fid,struct smb_cred * scrp)1002 smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, struct smb_cred *scrp)
1003 {
1004 struct smb_rq *rqp;
1005 struct mbchain *mbp;
1006 int error;
1007
1008 error = smb_rq_alloc(SSTOCP(ssp), SMB2_CLOSE, scrp, &rqp);
1009 if (error)
1010 return (error);
1011
1012 /*
1013 * Build the SMB 2/3 Close Request
1014 */
1015 smb_rq_getrequest(rqp, &mbp);
1016 mb_put_uint16le(mbp, 24); /* Struct size */
1017 mb_put_uint16le(mbp, 0); /* Flags */
1018 mb_put_uint32le(mbp, 0); /* Reserved */
1019
1020 mb_put_uint64le(mbp, fid->fid_persistent);
1021 mb_put_uint64le(mbp, fid->fid_volatile);
1022
1023 /* Make sure we send, but only if already connected */
1024 rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
1025 error = smb2_rq_simple(rqp);
1026 smb_rq_done(rqp);
1027 return (error);
1028 }
1029
1030 int
smb2_smb_ioctl(struct smb_share * ssp,smb2fid_t * fid,struct mbchain * data_in,struct mdchain * data_out,uint32_t * data_out_sz,uint32_t ctl_code,struct smb_cred * scrp)1031 smb2_smb_ioctl(
1032 struct smb_share *ssp,
1033 smb2fid_t *fid,
1034 struct mbchain *data_in,
1035 struct mdchain *data_out,
1036 uint32_t *data_out_sz, /* max / returned */
1037 uint32_t ctl_code,
1038 struct smb_cred *scrp)
1039 {
1040 struct smb_rq *rqp;
1041 struct mbchain *mbp;
1042 struct mdchain *mdp;
1043 uint32_t *data_in_offp;
1044 uint32_t *data_in_lenp;
1045 uint32_t data_out_off;
1046 uint32_t data_out_len;
1047 uint16_t length = 0;
1048 uint_t off, len;
1049 int error;
1050
1051 error = smb_rq_alloc(SSTOCP(ssp), SMB2_IOCTL, scrp, &rqp);
1052 if (error)
1053 return (error);
1054
1055 /*
1056 * Build the SMB 2 IOCTL Request
1057 */
1058 smb_rq_getrequest(rqp, &mbp);
1059 mb_put_uint16le(mbp, 57); /* Struct size */
1060 mb_put_uint16le(mbp, 0); /* Reserved */
1061 mb_put_uint32le(mbp, ctl_code);
1062
1063 mb_put_uint64le(mbp, fid->fid_persistent);
1064 mb_put_uint64le(mbp, fid->fid_volatile);
1065
1066 data_in_offp = mb_reserve(mbp, 4);
1067 data_in_lenp = mb_reserve(mbp, 4);
1068 mb_put_uint32le(mbp, 0); /* Max input resp */
1069
1070 mb_put_uint32le(mbp, 0); /* Output offset */
1071 mb_put_uint32le(mbp, 0); /* Output count */
1072 mb_put_uint32le(mbp, *data_out_sz);
1073
1074 mb_put_uint32le(mbp, SMB2_IOCTL_IS_FSCTL); /* Flags */
1075 mb_put_uint32le(mbp, 0); /* Reserved2 */
1076
1077 /*
1078 * Now data_in (if provided)
1079 */
1080 if (data_in != NULL) {
1081 off = mbp->mb_count;
1082 *data_in_offp = htolel((uint32_t)off);
1083 mb_put_mbchain(mbp, data_in);
1084 len = mbp->mb_count - off;
1085 *data_in_lenp = htolel((uint32_t)len);
1086 } else {
1087 *data_in_offp = 0;
1088 *data_in_lenp = 0;
1089 }
1090
1091 /*
1092 * Run the request
1093 */
1094 error = smb2_rq_simple_timed(rqp, smb2_timo_default);
1095 if (error)
1096 goto out;
1097
1098 /*
1099 * Parse SMB 2 Ioctl Response
1100 */
1101 smb_rq_getreply(rqp, &mdp);
1102
1103 /* Check structure size is 49 */
1104 md_get_uint16le(mdp, &length);
1105 if (length != 49) {
1106 error = EBADRPC;
1107 goto out;
1108 }
1109 md_get_uint16le(mdp, NULL); /* reserved */
1110 md_get_uint32le(mdp, NULL); /* Get CtlCode */
1111 md_get_uint64le(mdp, NULL); /* fid_persistent */
1112 md_get_uint64le(mdp, NULL); /* fid_volatile */
1113 md_get_uint32le(mdp, NULL); /* Get Input offset */
1114 md_get_uint32le(mdp, NULL); /* Get Input count */
1115
1116 error = md_get_uint32le(mdp, &data_out_off);
1117 if (error)
1118 goto out;
1119 error = md_get_uint32le(mdp, &data_out_len);
1120 if (error)
1121 goto out;
1122
1123 md_get_uint32le(mdp, NULL); /* Flags */
1124 md_get_uint32le(mdp, NULL); /* reserved */
1125
1126 /*
1127 * If the caller wants the ioctl output data, parse.
1128 * Current offset is: SMB2_HDRLEN + 48
1129 * Always return the received length.
1130 */
1131 *data_out_sz = data_out_len;
1132 if (data_out_len != 0) {
1133 int skip = (int)data_out_off - (SMB2_HDRLEN + 48);
1134 if (skip < 0) {
1135 error = EBADRPC;
1136 goto out;
1137 }
1138 if (skip > 0) {
1139 md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
1140 }
1141 if (data_out != NULL) {
1142 mblk_t *m = NULL;
1143 error = md_get_mbuf(mdp, data_out_len, &m);
1144 if (error)
1145 goto out;
1146 md_initm(data_out, m);
1147 }
1148 }
1149
1150 out:
1151 smb_rq_done(rqp);
1152
1153 return (error);
1154 }
1155
1156 int
smb2_smb_read(smb_fh_t * fhp,uint32_t * lenp,uio_t * uiop,smb_cred_t * scred,int timo)1157 smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
1158 uio_t *uiop, smb_cred_t *scred, int timo)
1159 {
1160 struct smb_share *ssp = FHTOSS(fhp);
1161 struct smb_rq *rqp;
1162 struct mbchain *mbp;
1163 struct mdchain *mdp;
1164 int error;
1165 uint64_t off64 = uiop->uio_loffset;
1166 uint32_t rlen;
1167 uint16_t length = 0;
1168 uint8_t data_offset;
1169
1170 error = smb_rq_alloc(SSTOCP(ssp), SMB2_READ, scred, &rqp);
1171 if (error)
1172 return (error);
1173
1174 /*
1175 * Build the SMB 2 Read Request
1176 */
1177 smb_rq_getrequest(rqp, &mbp);
1178 mb_put_uint16le(mbp, 49); /* Struct size */
1179 mb_put_uint16le(mbp, 0); /* Padding and Reserved */
1180
1181 mb_put_uint32le(mbp, *lenp); /* Length of read */
1182 mb_put_uint64le(mbp, off64); /* Offset */
1183
1184 mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
1185 mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
1186
1187 mb_put_uint32le(mbp, 1); /* MinCount */
1188 /* (only indicates blocking) */
1189
1190 mb_put_uint32le(mbp, 0); /* Channel */
1191 mb_put_uint32le(mbp, 0); /* Remaining */
1192 mb_put_uint32le(mbp, 0); /* Channel offset/len */
1193 mb_put_uint8(mbp, 0); /* data "blob" (pad) */
1194
1195 if (timo == 0)
1196 timo = smb2_timo_read;
1197 error = smb2_rq_simple_timed(rqp, timo);
1198 if (error)
1199 goto out;
1200
1201 /*
1202 * Parse SMB 2 Read Response
1203 */
1204 smb_rq_getreply(rqp, &mdp);
1205
1206 /* Check structure size is 17 */
1207 md_get_uint16le(mdp, &length);
1208 if (length != 17) {
1209 error = EBADRPC;
1210 goto out;
1211 }
1212 md_get_uint8(mdp, &data_offset);
1213 md_get_uint8(mdp, NULL); /* reserved */
1214
1215 /* Get Data Length read */
1216 error = md_get_uint32le(mdp, &rlen);
1217 if (error)
1218 goto out;
1219
1220 md_get_uint32le(mdp, NULL); /* Data Remaining (always 0) */
1221 md_get_uint32le(mdp, NULL); /* Get Reserved2 (always 0) */
1222
1223 /*
1224 * Data offset is from the beginning of SMB 2/3 Header
1225 * Calculate how much further we have to go to get to it.
1226 */
1227 if (data_offset < (SMB2_HDRLEN + 16)) {
1228 error = EBADRPC;
1229 goto out;
1230 }
1231 if (data_offset > (SMB2_HDRLEN + 16)) {
1232 int skip = data_offset - (SMB2_HDRLEN + 16);
1233 md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
1234 }
1235
1236 /*
1237 * Get the data
1238 */
1239 if (rlen == 0) {
1240 *lenp = rlen;
1241 goto out;
1242 }
1243 /* paranoid */
1244 if (rlen > *lenp) {
1245 SMBSDEBUG("bad server! rlen %d, len %d\n",
1246 rlen, *lenp);
1247 rlen = *lenp;
1248 }
1249
1250 error = md_get_uio(mdp, uiop, rlen);
1251 if (error)
1252 goto out;
1253
1254 /* Success */
1255 *lenp = rlen;
1256
1257 out:
1258 smb_rq_done(rqp);
1259 return (error);
1260 }
1261
1262 int
smb2_smb_write(smb_fh_t * fhp,uint32_t * lenp,uio_t * uiop,smb_cred_t * scred,int timo)1263 smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
1264 uio_t *uiop, smb_cred_t *scred, int timo)
1265 {
1266 struct smb_share *ssp = FHTOSS(fhp);
1267 struct smb_rq *rqp;
1268 struct mbchain *mbp;
1269 struct mdchain *mdp;
1270 int error;
1271 uint64_t off64 = uiop->uio_loffset;
1272 uint32_t rlen;
1273 uint16_t data_offset;
1274 uint16_t length = 0;
1275
1276 error = smb_rq_alloc(SSTOCP(ssp), SMB2_WRITE, scred, &rqp);
1277 if (error)
1278 return (error);
1279
1280 /*
1281 * Build the SMB 2 Write Request
1282 */
1283 smb_rq_getrequest(rqp, &mbp);
1284 mb_put_uint16le(mbp, 49); /* Struct size */
1285 data_offset = SMB2_HDRLEN + 48;
1286 mb_put_uint16le(mbp, data_offset); /* Data Offset */
1287 mb_put_uint32le(mbp, *lenp); /* Length of write */
1288 mb_put_uint64le(mbp, off64); /* Offset */
1289
1290 mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
1291 mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
1292
1293 mb_put_uint32le(mbp, 0); /* Channel */
1294 mb_put_uint32le(mbp, 0); /* Remaining */
1295 mb_put_uint32le(mbp, 0); /* Channel offset/len */
1296 mb_put_uint32le(mbp, 0); /* Write flags */
1297
1298 error = mb_put_uio(mbp, uiop, *lenp);
1299 if (error)
1300 goto out;
1301
1302 if (timo == 0)
1303 timo = smb2_timo_write;
1304 error = smb2_rq_simple_timed(rqp, timo);
1305 if (error)
1306 goto out;
1307
1308 /*
1309 * Parse SMB 2/3 Write Response
1310 */
1311 smb_rq_getreply(rqp, &mdp);
1312
1313 /* Check structure size is 17 */
1314 md_get_uint16le(mdp, &length);
1315 if (length != 17) {
1316 error = EBADRPC;
1317 goto out;
1318 }
1319
1320 md_get_uint16le(mdp, NULL); /* Get Reserved */
1321
1322 /* Get Data Length written */
1323 error = md_get_uint32le(mdp, &rlen);
1324 if (error)
1325 goto out;
1326
1327 /* Get Data Remaining (always 0) */
1328 md_get_uint32le(mdp, NULL);
1329
1330 /* Get Reserved2 (always 0) */
1331 md_get_uint32le(mdp, NULL);
1332
1333 /* Success */
1334 *lenp = rlen;
1335
1336 out:
1337 smb_rq_done(rqp);
1338 return (error);
1339 }
1340
1341 /*
1342 * Note: the IOD calls this, so this request must not wait for
1343 * connection state changes, etc. (uses smb2_rq_internal)
1344 */
1345 int
smb2_smb_echo(struct smb_vc * vcp,struct smb_cred * scred,int timo)1346 smb2_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1347 {
1348 struct smb_rq *rqp;
1349 struct mbchain *mbp;
1350 int error;
1351
1352 error = smb_rq_alloc(VCTOCP(vcp), SMB2_ECHO, scred, &rqp);
1353 if (error)
1354 return (error);
1355
1356 /*
1357 * Build the SMB 2 Echo Request
1358 */
1359 smb_rq_getrequest(rqp, &mbp);
1360 mb_put_uint16le(mbp, 4); /* Struct size */
1361 mb_put_uint16le(mbp, 0); /* Reserved */
1362
1363 rqp->sr_flags |= SMBR_NORECONNECT;
1364 error = smb2_rq_internal(rqp, timo);
1365
1366 smb_rq_done(rqp);
1367 return (error);
1368 }
1369