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