1 /*
   2  * Copyright (c) 2000-2001 Boris Popov
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. All advertising materials mentioning features or use of this software
  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  *
  32  * $Id: smb_smb.c,v 1.35.100.2 2005/06/02 00:55:39 lindak Exp $
  33  */
  34 
  35 /*
  36  * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved.
  37  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  38  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  39  */
  40 
  41 /*
  42  * various SMB requests. Most of the routines merely packs data into mbufs.
  43  */
  44 #include <sys/param.h>
  45 #include <sys/systm.h>
  46 #include <sys/kmem.h>
  47 #include <sys/proc.h>
  48 #include <sys/lock.h>
  49 #include <sys/socket.h>
  50 #include <sys/uio.h>
  51 #include <sys/random.h>
  52 #include <sys/note.h>
  53 #include <sys/errno.h>
  54 #include <sys/cmn_err.h>
  55 
  56 #include <netsmb/smb_osdep.h>
  57 
  58 #include <netsmb/smb.h>
  59 #include <netsmb/smb_conn.h>
  60 #include <netsmb/smb_rq.h>
  61 #include <netsmb/smb_subr.h>
  62 #include <netsmb/smb_tran.h>
  63 
  64 #define STYPE_LEN       8       /* share type strings */
  65 
  66 struct smb_dialect {
  67         int             d_id;
  68         const char      *d_name;
  69 };
  70 
  71 static struct smb_dialect smb_dialects[3] = {
  72         {SMB_DIALECT_NTLM0_12,  "NT LANMAN 1.0"},
  73         {SMB_DIALECT_NTLM0_12,  "NT LM 0.12"},
  74 #define NDIALECT_SMB1   2
  75         {SMB_DIALECT_SMB2_FF,   "SMB 2.???"},
  76 #define NDIALECT_SMB2   3
  77 };
  78 
  79 static const uint32_t smb_clnt_caps_mask =
  80     SMB_CAP_UNICODE |
  81     SMB_CAP_LARGE_FILES |
  82     SMB_CAP_NT_SMBS |
  83     SMB_CAP_STATUS32 |
  84     SMB_CAP_EXT_SECURITY;
  85 
  86 /*
  87  * Default timeout values, all in seconds.
  88  * Make these tunable (only via mdb for now).
  89  */
  90 int smb_timo_notice = 15;
  91 int smb_timo_default = 30;      /* was SMB_DEFRQTIMO */
  92 int smb_timo_logon = 45;
  93 int smb_timo_open = 45;
  94 int smb_timo_read = 45;
  95 int smb_timo_write = 60;        /* was SMBWRTTIMO */
  96 int smb_timo_append = 90;
  97 
  98 int
  99 smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
 100 {
 101         smb_sopt_t *sv = &vcp->vc_sopt;
 102         smbioc_ssn_work_t *wk = &vcp->vc_work;
 103         struct smb_rq *rqp = NULL;
 104         struct mbchain *mbp = NULL;
 105         struct mdchain *mdp = NULL;
 106         struct smb_dialect *dp;
 107         int err, sblen, tlen;
 108         uint8_t wc, eklen;
 109         uint16_t dindex, bc;
 110         uint16_t ndialects;
 111         boolean_t will_sign = B_FALSE;
 112 
 113         /*
 114          * Initialize: vc_hflags and vc_hflags2.
 115          * Note: vcp->vc_hflags* are copied into the
 116          * (per request) rqp->rq_hflags* by smb_rq_init.
 117          *
 118          * Like Windows, set FLAGS2_UNICODE in our first request,
 119          * even though technically we don't yet know whether the
 120          * server supports Unicode.  Will clear this flag below
 121          * if we find out it doesn't.  Need to do this because
 122          * some servers reject all non-Unicode requests.
 123          */
 124         vcp->vc_hflags =
 125             SMB_FLAGS_CASELESS |
 126             SMB_FLAGS_CANONICAL_PATHNAMES;
 127         vcp->vc_hflags2 =
 128             SMB_FLAGS2_KNOWS_LONG_NAMES |
 129             SMB_FLAGS2_KNOWS_EAS |
 130             SMB_FLAGS2_IS_LONG_NAME |
 131             SMB_FLAGS2_EXT_SEC |
 132             SMB_FLAGS2_ERR_STATUS |
 133             SMB_FLAGS2_UNICODE;
 134 
 135         /*
 136          * The initial UID needs to be zero,
 137          */
 138         vcp->vc_smbuid = 0;
 139 
 140         /*
 141          * (Re)init negotiated values
 142          */
 143         bzero(sv, sizeof (*sv));
 144         sv->sv_maxmux = 1;
 145         sv->sv_maxvcs = 1;
 146         sv->sv_maxtx = 1024;
 147 
 148         /*
 149          * Should we offer the magic SMB2 dialect?
 150          */
 151         if (vcp->vc_ssn.ssn_maxver >= SMB2_DIALECT_BASE)
 152                 ndialects = NDIALECT_SMB2;
 153         else
 154                 ndialects = NDIALECT_SMB1;
 155 
 156         err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_NEGOTIATE, scred, &rqp);
 157         if (err)
 158                 return (err);
 159 
 160         /*
 161          * Build the SMB request.
 162          */
 163         smb_rq_getrequest(rqp, &mbp);
 164         smb_rq_wstart(rqp);
 165         smb_rq_wend(rqp);
 166         smb_rq_bstart(rqp);
 167         for (dindex = 0; dindex < ndialects; dindex++) {
 168                 dp = &smb_dialects[dindex];
 169                 mb_put_uint8(mbp, SMB_DT_DIALECT);
 170                 tlen = strlen(dp->d_name) + 1;
 171                 mb_put_mem(mbp, dp->d_name, tlen, MB_MSYSTEM);
 172         }
 173         smb_rq_bend(rqp);
 174 
 175         /*
 176          * Do the OTW call.
 177          */
 178         err = smb_rq_internal(rqp, smb_timo_default);
 179         /*
 180          * If it's an SMB1-to-SMB2 negotiate response,
 181          * call the special handler and then skip the
 182          * whole rest of this function.
 183          */
 184         if (err == EPROTO) {
 185                 err = smb2_parse_smb1nego_resp(rqp);
 186                 smb_rq_done(rqp);
 187                 return (err);
 188         }
 189         if (err) {
 190                 SMBSDEBUG("smb_rq_internal, err %d", err);
 191                 goto errout;
 192         }
 193         /* Should only get status success. */
 194         if (rqp->sr_error != NT_STATUS_SUCCESS) {
 195                 err = ENOTSUP;
 196                 goto errout;
 197         }
 198 
 199         /*
 200          * Decode the response
 201          *
 202          * Comments to right show names as described in
 203          * The Microsoft SMB Protocol spec. [MS-SMB]
 204          * section 2.2.3
 205          */
 206         smb_rq_getreply(rqp, &mdp);
 207         (void) md_get_uint8(mdp, &wc);
 208         err = md_get_uint16le(mdp, &dindex);
 209         if (err != 0)
 210                 goto errout;
 211         if (dindex >= ndialects) {
 212                 SMBERROR("Invalid dialect index from server: %s\n",
 213                     vcp->vc_srvname);
 214                 err = EBADRPC;
 215                 goto errout;
 216         }
 217         dp = smb_dialects + dindex;
 218         sv->sv_proto = dp->d_id;
 219         SMBSDEBUG("Dialect %s", dp->d_name);
 220         if (dp->d_id < SMB_DIALECT_NTLM0_12) {
 221                 SMBSDEBUG("old dialect %s", dp->d_name);
 222                 goto errout;
 223         }
 224         if (wc != 17) {
 225                 SMBSDEBUG("bad wc %d", (int)wc);
 226                 goto errout;
 227         }
 228         md_get_uint8(mdp, &sv->sv_sm);           /* SecurityMode */
 229         md_get_uint16le(mdp, &sv->sv_maxmux);    /* MaxMpxCount */
 230         md_get_uint16le(mdp, &sv->sv_maxvcs);    /* MaxCountVCs */
 231         md_get_uint32le(mdp, &sv->sv_maxtx);     /* MaxBufferSize */
 232         md_get_uint32le(mdp, &sv->sv_maxraw);    /* MaxRawSize */
 233         md_get_uint32le(mdp, &sv->sv_skey);      /* SessionKey */
 234         md_get_uint32le(mdp, &sv->sv_caps);      /* Capabilities */
 235         md_get_mem(mdp, NULL, 8, MB_MSYSTEM);   /* SystemTime(s) */
 236         md_get_uint16le(mdp, (uint16_t *)&sv->sv_tz);
 237         md_get_uint8(mdp, &eklen);  /* EncryptionKeyLength */
 238         err = md_get_uint16le(mdp, &bc);    /* ByteCount */
 239         if (err)
 240                 goto errout;
 241 
 242         /* BEGIN CSTYLED */
 243         /*
 244          * Will we do SMB signing?  Or block the connection?
 245          * The table below describes this logic.  References:
 246          * [Windows Server Protocols: MS-SMB, sec. 3.2.4.2.3]
 247          * http://msdn.microsoft.com/en-us/library/cc212511.aspx
 248          * http://msdn.microsoft.com/en-us/library/cc212929.aspx
 249          *
 250          * Srv/Cli     | Required | Enabled    | If Required | Disabled
 251          * ------------+----------+------------+-------------+-----------
 252          * Required    | Signed   | Signed     | Signed      | Blocked [1]
 253          * ------------+----------+------------+-------------+-----------
 254          * Enabled     | Signed   | Signed     | Not Signed  | Not Signed
 255          * ------------+----------+------------+-------------+-----------
 256          * If Required | Signed   | Not Signed | Not Signed  | Not Signed
 257          * ------------+----------+------------+-------------+-----------
 258          * Disabled    | Blocked  | Not Signed | Not Signed  | Not Signed
 259          *
 260          * [1] Like Windows 2003 and later, we don't really implement
 261          * the "Disabled" setting.  Instead we implement "If Required",
 262          * so we always sign if the server requires signing.
 263          */
 264         /* END CSTYLED */
 265 
 266         if (sv->sv_sm & SMB_SM_SIGS_REQUIRE) {
 267                 /*
 268                  * Server requires signing.  We will sign,
 269                  * even if local setting is "disabled".
 270                  */
 271                 will_sign = B_TRUE;
 272         } else if (sv->sv_sm & SMB_SM_SIGS) {
 273                 /*
 274                  * Server enables signing (client's option).
 275                  * If enabled locally, do signing.
 276                  */
 277                 if (vcp->vc_vopt & SMBVOPT_SIGNING_ENABLED)
 278                         will_sign = B_TRUE;
 279                 /* else not signing. */
 280         } else {
 281                 /*
 282                  * Server does not support signing.
 283                  * If we "require" it, bail now.
 284                  */
 285                 if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
 286                         SMBERROR("Client requires signing "
 287                             "but server has it disabled.");
 288                         err = EBADRPC;
 289                         goto errout;
 290                 }
 291         }
 292 
 293         /*
 294          * Anonymous sessions can't sign.
 295          */
 296         if (vcp->vc_vopt & SMBVOPT_ANONYMOUS) {
 297                 will_sign = B_FALSE;
 298         }
 299 
 300         SMBSDEBUG("Security signatures: %d", (int)will_sign);
 301         if (will_sign) {
 302                 vcp->vc_flags |= SMBV_SIGNING;
 303                 vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE;
 304 
 305                 /*
 306                  * MS-SMB 2.2.4.5 says that when SMB signing is enabled,
 307                  * we should NOT use "large read/write" even though the
 308                  * server might offer those capabilities.
 309                  */
 310                 sv->sv_caps &= ~(SMB_CAP_LARGE_READX | SMB_CAP_LARGE_WRITEX);
 311         }
 312 
 313         /* See comment above re. FLAGS2_UNICODE */
 314         if ((sv->sv_caps & SMB_CAP_UNICODE) != 0)
 315                 vcp->vc_flags |= SMBV_UNICODE;
 316         else
 317                 vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE;
 318 
 319         if ((sv->sv_caps & SMB_CAP_STATUS32) == 0) {
 320                 /* They don't do NT error codes. */
 321                 vcp->vc_hflags2 &= ~SMB_FLAGS2_ERR_STATUS;
 322         }
 323 
 324         /*
 325          * Warn if they don't support SMB_CAP_NT_SMBS
 326          * (We'll try to use NtCreate anyway)
 327          */
 328         if ((sv->sv_caps & SMB_CAP_NT_SMBS) == 0) {
 329                 cmn_err(CE_NOTE, "%s does not support SMB_CAP_NT_SMBS",
 330                     vcp->vc_srvname);
 331         }
 332 
 333         /*
 334          * The rest of the message varies depending on
 335          * whether we've negotiated "extended security".
 336          *
 337          * With extended security, we have:
 338          *      Server_GUID     (length 16)
 339          *      Security_BLOB
 340          * Otherwise we have:
 341          *      EncryptionKey (length is eklen)
 342          *      PrimaryDomain
 343          */
 344         if (sv->sv_caps & SMB_CAP_EXT_SECURITY) {
 345                 SMBSDEBUG("Ext.Security: yes");
 346 
 347                 /*
 348                  * Skip the server GUID.
 349                  */
 350                 err = md_get_mem(mdp, NULL, SMB_GUIDLEN, MB_MSYSTEM);
 351                 if (err)
 352                         goto errout;
 353                 /*
 354                  * Remainder is the security blob.
 355                  * Note: eklen "must be ignored" [MS-SMB]
 356                  */
 357                 sblen = (int)bc - SMB_GUIDLEN;
 358                 if (sblen < 0)
 359                         goto errout;
 360                 /* Security blob (hint) is next */
 361         } else {
 362                 SMBSDEBUG("Ext.Security: no");
 363                 err = ENOTSUP;
 364                 goto errout;
 365         }
 366 
 367         /*
 368          * Copy the security blob out to user space.
 369          * Buffer addr,size in vc_auth_rbuf,rlen
 370          */
 371         if (wk->wk_u_auth_rlen < sblen) {
 372                 SMBSDEBUG("vc_auth_rbuf too small");
 373                 /* Give caller required size. */
 374                 wk->wk_u_auth_rlen = sblen;
 375                 err = EMSGSIZE;
 376                 goto errout;
 377         }
 378         wk->wk_u_auth_rlen = sblen;
 379         err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr, sblen, MB_MUSER);
 380         if (err)
 381                 goto errout;
 382 
 383         /*
 384          * A few sanity checks on what we received,
 385          * becuse we will send these in ssnsetup.
 386          *
 387          * Maximum outstanding requests (we care),
 388          * and Max. VCs (we only use one).  Also,
 389          * MaxBufferSize lower limit per spec.
 390          */
 391         if (sv->sv_maxmux < 1)
 392                 sv->sv_maxmux = 1;
 393         if (sv->sv_maxvcs < 1)
 394                 sv->sv_maxvcs = 1;
 395         if (sv->sv_maxtx < 1024)
 396                 sv->sv_maxtx = 1024;
 397 
 398         /*
 399          * Maximum transfer size.
 400          * Sanity checks:
 401          *
 402          * Let's be conservative about an upper limit here.
 403          * Win2k uses 16644 (and others) so 32k should be a
 404          * reasonable sanity limit for this value.
 405          *
 406          * Note that this limit does NOT affect READX/WRITEX
 407          * with CAP_LARGE_..., which we nearly always use.
 408          */
 409         vcp->vc_txmax = sv->sv_maxtx;
 410         if (vcp->vc_txmax > 0x8000)
 411                 vcp->vc_txmax = 0x8000;
 412 
 413         /*
 414          * Max read/write sizes, WITHOUT overhead.
 415          * This is just the payload size, so we must
 416          * leave room for the SMB headers, etc.
 417          * This is just the ct_txmax value, but
 418          * reduced and rounded down.  Tricky bit:
 419          *
 420          * Servers typically give us a value that's
 421          * some nice "round" number, i.e 0x4000 plus
 422          * some overhead, i.e. Win2k: 16644==0x4104
 423          * Subtract for the SMB header (32) and the
 424          * SMB command word and byte vectors (34?),
 425          * then round down to a 512 byte multiple.
 426          */
 427         tlen = vcp->vc_txmax - 68;
 428         tlen &= 0xFE00;
 429 
 430         vcp->vc_rwmax = tlen;
 431         vcp->vc_rxmax = tlen;
 432         vcp->vc_wxmax = tlen;
 433 
 434         /*
 435          * Most of the "capability" bits we offer in session setup
 436          * are just copied from those offered by the server.
 437          */
 438         sv->sv_caps &= smb_clnt_caps_mask;
 439 
 440         smb_rq_done(rqp);
 441         return (0);
 442 
 443 errout:
 444         smb_rq_done(rqp);
 445         if (err == 0)
 446                 err = EBADRPC;
 447         return (err);
 448 }
 449 
 450 static const char NativeOS[] = "illumos";
 451 static const char LanMan[] = "NETSMB";
 452 
 453 int
 454 smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
 455 {
 456         smb_sopt_t *sv = &vcp->vc_sopt;
 457         smbioc_ssn_work_t *wk = &vcp->vc_work;
 458         struct smb_rq *rqp = NULL;
 459         struct mbchain *mbp = NULL;
 460         struct mdchain *mdp = NULL;
 461         char *sb;
 462         int err, ret;
 463         uint32_t caps;
 464         uint16_t action, bc, sblen;
 465         uint8_t wc;
 466 
 467         caps = sv->sv_caps;
 468         sb = wk->wk_u_auth_wbuf.lp_ptr;
 469         sblen = (uint16_t)wk->wk_u_auth_wlen;
 470 
 471         err = smb_rq_alloc(VCTOCP(vcp), SMB_COM_SESSION_SETUP_ANDX,
 472             scred, &rqp);
 473         if (err != 0) {
 474                 ret = err;
 475                 goto out;
 476         }
 477 
 478         /*
 479          * Build the SMB Session Setup request.
 480          * Always extended security form.
 481          */
 482         mbp = &rqp->sr_rq;
 483         smb_rq_wstart(rqp);
 484         mb_put_uint16le(mbp, 0xff);             /* 0: AndXCommand */
 485         mb_put_uint16le(mbp, 0);                /* 1: AndXOffset */
 486         mb_put_uint16le(mbp, sv->sv_maxtx);  /* 2: MaxBufferSize */
 487         mb_put_uint16le(mbp, sv->sv_maxmux); /* 3: MaxMpxCount */
 488         mb_put_uint16le(mbp, 1);                /* 4: VcNumber */
 489         mb_put_uint32le(mbp, sv->sv_skey);   /* 5,6: Session Key */
 490         mb_put_uint16le(mbp, sblen);    /* 7: Sec. Blob Len */
 491         mb_put_uint32le(mbp, 0);        /* 8,9: reserved */
 492         mb_put_uint32le(mbp, caps);     /* 10,11: Capabilities */
 493         smb_rq_wend(rqp);               /* 12: Byte Count */
 494         smb_rq_bstart(rqp);
 495         err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
 496         if (err != 0) {
 497                 ret = err;
 498                 goto out;
 499         }
 500         (void) smb_put_dstring(mbp, vcp, NativeOS, SMB_CS_NONE);
 501         (void) smb_put_dstring(mbp, vcp, LanMan, SMB_CS_NONE);
 502         smb_rq_bend(rqp);
 503 
 504         /*
 505          * Run the request.  The return value here should be the
 506          * return from this function, unless we fail decoding.
 507          * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
 508          * the caller expects EINPROGRESS for that case.
 509          */
 510         ret = smb_rq_internal(rqp, smb_timo_logon);
 511         if (ret != 0)
 512                 goto out;
 513         switch (rqp->sr_error) {
 514         case NT_STATUS_SUCCESS:
 515                 break;
 516         case NT_STATUS_MORE_PROCESSING_REQUIRED:
 517                 /* Keep going, but return... */
 518                 ret = EINPROGRESS;
 519                 break;
 520         default:
 521                 ret = EAUTH;
 522                 goto out;
 523         }
 524 
 525         if (vcp->vc_smbuid == 0)
 526                 vcp->vc_smbuid = rqp->sr_rpuid;
 527 
 528         /*
 529          * Parse the reply
 530          */
 531         smb_rq_getreply(rqp, &mdp);
 532 
 533         err = md_get_uint8(mdp, &wc);
 534         if (err != 0)
 535                 wc = 0;
 536         if (wc != 4) {
 537                 ret = EBADRPC;
 538                 goto out;
 539         }
 540         md_get_uint16le(mdp, NULL);     /* secondary cmd */
 541         md_get_uint16le(mdp, NULL);     /* andxoffset */
 542         md_get_uint16le(mdp, &action);      /* action XXX */
 543         md_get_uint16le(mdp, &sblen);       /* sec. blob len */
 544         md_get_uint16le(mdp, &bc);  /* byte count */
 545         /*
 546          * Get the security blob, after
 547          * sanity-checking the length.
 548          */
 549         if (sblen == 0 || sblen > bc) {
 550                 ret = EBADRPC;
 551                 goto out;
 552         }
 553         if (sblen > wk->wk_u_auth_rlen) {
 554                 ret = EBADRPC;
 555                 goto out;
 556         }
 557         sb = wk->wk_u_auth_rbuf.lp_ptr;
 558         err = md_get_mem(mdp, sb, sblen, MB_MUSER);
 559         if (err) {
 560                 ret = EBADRPC;
 561                 goto out;
 562         }
 563 
 564         /*
 565          * Native OS, LANMGR, & Domain follow here.
 566          * We don't need them and don't parse them.
 567          */
 568 
 569 out:
 570         if (err != 0 && err != EINPROGRESS) {
 571                 /* UID no longer valid. */
 572                 vcp->vc_smbuid = 0;
 573         }
 574         if (rqp)
 575                 smb_rq_done(rqp);
 576 
 577         return (ret);
 578 }
 579 
 580 int
 581 smb_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
 582 {
 583         struct smb_rq *rqp;
 584         struct mbchain *mbp;
 585         int error;
 586 
 587         if (vcp->vc_smbuid == SMB_UID_UNKNOWN)
 588                 return (0);
 589 
 590         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_LOGOFF_ANDX, scred, &rqp);
 591         if (error)
 592                 return (error);
 593         mbp = &rqp->sr_rq;
 594         smb_rq_wstart(rqp);
 595         mb_put_uint8(mbp, 0xff);
 596         mb_put_uint8(mbp, 0);
 597         mb_put_uint16le(mbp, 0);
 598         smb_rq_wend(rqp);
 599         smb_rq_bstart(rqp);
 600         smb_rq_bend(rqp);
 601 
 602         /*
 603          * Run this with a relatively short timeout. (5 sec.)
 604          * We don't really care about the result here.
 605          * Also, don't reconnect for this, of course!
 606          */
 607         rqp->sr_flags |= SMBR_NORECONNECT;
 608         error = smb_rq_internal(rqp, 5);
 609         smb_rq_done(rqp);
 610         return (error);
 611 }
 612 
 613 /*
 614  * Get the string representation of a share "use" type,
 615  * as needed for the "service" in tree connect.
 616  */
 617 static const char *
 618 smb_share_typename(uint32_t stype)
 619 {
 620         const char *p;
 621 
 622         switch (stype) {
 623         case STYPE_DISKTREE:
 624                 p = "A:";
 625                 break;
 626         case STYPE_PRINTQ:
 627                 p = "LPT1:";
 628                 break;
 629         case STYPE_DEVICE:
 630                 p = "COMM";
 631                 break;
 632         case STYPE_IPC:
 633                 p = "IPC";
 634                 break;
 635         case STYPE_UNKNOWN:
 636         default:
 637                 p = "?????";
 638                 break;
 639         }
 640         return (p);
 641 }
 642 
 643 /*
 644  * Parse a share type name (inverse of above)
 645  */
 646 static uint32_t
 647 smb_share_parsetype(char *name)
 648 {
 649         int stype;
 650 
 651         switch (*name) {
 652         case 'A':       /* A: */
 653                 stype = STYPE_DISKTREE;
 654                 break;
 655         case 'C':       /* COMM */
 656                 stype = STYPE_DEVICE;
 657                 break;
 658         case 'I':       /* IPC */
 659                 stype = STYPE_IPC;
 660                 break;
 661         case 'L':       /* LPT: */
 662                 stype = STYPE_PRINTQ;
 663                 break;
 664         default:
 665                 stype = STYPE_UNKNOWN;
 666                 break;
 667         }
 668         return (stype);
 669 }
 670 
 671 int
 672 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
 673 {
 674         struct smb_vc *vcp;
 675         struct smb_rq *rqp = NULL;
 676         struct mbchain *mbp;
 677         struct mdchain *mdp;
 678         const char *tname;
 679         char *pbuf, *unc_name = NULL;
 680         int error, tlen, plen, unc_len;
 681         uint16_t bcnt, options;
 682         uint8_t wc;
 683         char stype_str[STYPE_LEN];
 684 
 685         vcp = SSTOVC(ssp);
 686 
 687         /*
 688          * Make this a "VC-level" request, so it will have
 689          * rqp->sr_share == NULL, and smb_iod_sendrq()
 690          * will send it with TID = SMB_TID_UNKNOWN
 691          *
 692          * This also serves to bypass the wait for
 693          * share state changes, which this call is
 694          * trying to carry out.
 695          */
 696         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX,
 697             scred, &rqp);
 698         if (error)
 699                 return (error);
 700 
 701         /*
 702          * Build the UNC name, i.e. "//server/share"
 703          * but with backslashes of course.
 704          * size math: three slashes, one null.
 705          */
 706         unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
 707         unc_name = kmem_alloc(unc_len, KM_SLEEP);
 708         (void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
 709             vcp->vc_srvname, ssp->ss_name);
 710         SMBSDEBUG("unc_name: \"%s\"", unc_name);
 711 
 712 
 713         /*
 714          * Share-level password (pre-computed in user-space)
 715          * MS-SMB 2.2.6 says this should be null terminated,
 716          * and the pw length includes the null.
 717          */
 718         pbuf = ssp->ss_pass;
 719         plen = strlen(pbuf) + 1;
 720 
 721         /*
 722          * Build the request.
 723          */
 724         mbp = &rqp->sr_rq;
 725         smb_rq_wstart(rqp);
 726         mb_put_uint8(mbp, 0xff);
 727         mb_put_uint8(mbp, 0);
 728         mb_put_uint16le(mbp, 0);
 729         mb_put_uint16le(mbp, 0);                /* Flags */
 730         mb_put_uint16le(mbp, plen);
 731         smb_rq_wend(rqp);
 732         smb_rq_bstart(rqp);
 733 
 734         /* Tree connect password, if any */
 735         error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM);
 736         if (error)
 737                 goto out;
 738 
 739         /* UNC resource name */
 740         error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE);
 741         if (error)
 742                 goto out;
 743 
 744         /*
 745          * Put the type string (always ASCII),
 746          * including the null.
 747          */
 748         tname = smb_share_typename(ssp->ss_use);
 749         tlen = strlen(tname) + 1;
 750         error = mb_put_mem(mbp, tname, tlen, MB_MSYSTEM);
 751         if (error)
 752                 goto out;
 753 
 754         smb_rq_bend(rqp);
 755 
 756         /*
 757          * Run the request.
 758          *
 759          * Using NOINTR_RECV because we don't want to risk
 760          * missing a successful tree connect response,
 761          * which would "leak" Tree IDs.
 762          */
 763         rqp->sr_flags |= SMBR_NOINTR_RECV;
 764         error = smb_rq_simple(rqp);
 765         SMBSDEBUG("%d\n", error);
 766         if (error) {
 767                 /*
 768                  * If we get the server name wrong, i.e. due to
 769                  * mis-configured name services, this will be
 770                  * NT_STATUS_DUPLICATE_NAME.  Log this error.
 771                  */
 772                 SMBERROR("(%s) failed, status=0x%x",
 773                     unc_name, rqp->sr_error);
 774                 goto out;
 775         }
 776 
 777         /*
 778          * Parse the TCON response
 779          */
 780         smb_rq_getreply(rqp, &mdp);
 781         md_get_uint8(mdp, &wc);
 782         if (wc != 3 && wc != 7) {
 783                 error = EBADRPC;
 784                 goto out;
 785         }
 786         md_get_uint16le(mdp, NULL);             /* AndX cmd */
 787         md_get_uint16le(mdp, NULL);             /* AndX off */
 788         md_get_uint16le(mdp, &options);             /* option bits (DFS, search) */
 789         if (wc == 7) {
 790                 md_get_uint32le(mdp, NULL);     /* MaximalShareAccessRights */
 791                 md_get_uint32le(mdp, NULL);     /* GuestMaximalShareAcc... */
 792         }
 793         error = md_get_uint16le(mdp, &bcnt);        /* byte count */
 794         if (error)
 795                 goto out;
 796 
 797         /*
 798          * Get the returned share type string, i.e. "IPC" or whatever.
 799          * (See smb_share_typename, smb_share_parsetype).  If we get
 800          * an error reading the type, just say STYPE_UNKNOWN.
 801          */
 802         tlen = STYPE_LEN;
 803         bzero(stype_str, tlen--);
 804         if (tlen > bcnt)
 805                 tlen = bcnt;
 806         md_get_mem(mdp, stype_str, tlen, MB_MSYSTEM);
 807         stype_str[tlen] = '\0';
 808         ssp->ss_type = smb_share_parsetype(stype_str);
 809 
 810         /* Success! */
 811         SMB_SS_LOCK(ssp);
 812         ssp->ss_tid = rqp->sr_rptid;
 813         ssp->ss_vcgenid = vcp->vc_genid;
 814         ssp->ss_options = options;
 815         ssp->ss_flags |= SMBS_CONNECTED;
 816         SMB_SS_UNLOCK(ssp);
 817 
 818 out:
 819         if (unc_name)
 820                 kmem_free(unc_name, unc_len);
 821         smb_rq_done(rqp);
 822         return (error);
 823 }
 824 
 825 int
 826 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
 827 {
 828         struct smb_vc *vcp;
 829         struct smb_rq *rqp;
 830         int error;
 831 
 832         if (ssp->ss_tid == SMB_TID_UNKNOWN)
 833                 return (0);
 834 
 835         /*
 836          * Build this as a "VC-level" request, so it will
 837          * avoid testing the _GONE flag on the share,
 838          * which has already been set at this point.
 839          * Add the share pointer "by hand" below, so
 840          * smb_iod_sendrq will plug in the TID.
 841          */
 842         vcp = SSTOVC(ssp);
 843         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
 844         if (error)
 845                 return (error);
 846         rqp->sr_share = ssp; /* by hand */
 847 
 848         smb_rq_wstart(rqp);
 849         smb_rq_wend(rqp);
 850         smb_rq_bstart(rqp);
 851         smb_rq_bend(rqp);
 852 
 853         /*
 854          * Run this with a relatively short timeout. (5 sec.)
 855          * We don't really care about the result here, but we
 856          * do need to make sure we send this out, or we could
 857          * "leak" active tree IDs on interrupt or timeout.
 858          * The NOINTR_SEND flag makes this request immune to
 859          * interrupt or timeout until the send is done.
 860          * Also, don't reconnect for this, of course!
 861          */
 862         rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
 863         error = smb_rq_simple_timed(rqp, 5);
 864         SMBSDEBUG("%d\n", error);
 865         smb_rq_done(rqp);
 866         ssp->ss_tid = SMB_TID_UNKNOWN;
 867         return (error);
 868 }
 869 
 870 /*
 871  * Modern create/open of file or directory.
 872  */
 873 int
 874 smb1_smb_ntcreate(
 875         struct smb_share *ssp,
 876         struct mbchain  *name_mb,
 877         uint32_t cr_flags,      /* create flags */
 878         uint32_t req_acc,       /* requested access */
 879         uint32_t efa,           /* ext. file attrs (DOS attr +) */
 880         uint32_t share_acc,
 881         uint32_t open_disp,     /* open disposition */
 882         uint32_t createopt,     /* NTCREATEX_OPTIONS_ */
 883         uint32_t impersonate,   /* NTCREATEX_IMPERSONATION_... */
 884         struct smb_cred *scrp,
 885         uint16_t *fidp,         /* returned FID */
 886         uint32_t *cr_act_p,     /* optional create action */
 887         struct smbfattr *fap)   /* optional attributes */
 888 {
 889         struct smb_rq rq, *rqp = &rq;
 890         struct smb_vc *vcp = SSTOVC(ssp);
 891         struct mbchain *mbp;
 892         struct mdchain *mdp;
 893         struct smbfattr fa;
 894         uint64_t llongint;
 895         uint32_t longint, createact;
 896         uint16_t fid;
 897         uint8_t wc;
 898         int error;
 899 
 900         bzero(&fa, sizeof (fa));
 901         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
 902         if (error)
 903                 return (error);
 904         smb_rq_getrequest(rqp, &mbp);
 905 
 906         /* Word parameters */
 907         smb_rq_wstart(rqp);
 908         mb_put_uint8(mbp, 0xff);        /* secondary command */
 909         mb_put_uint8(mbp, 0);           /* MBZ */
 910         mb_put_uint16le(mbp, 0);        /* offset to next command (none) */
 911         mb_put_uint8(mbp, 0);           /* MBZ */
 912         mb_put_uint16le(mbp, name_mb->mb_count);
 913         mb_put_uint32le(mbp, cr_flags); /* NTCREATEX_FLAGS_* */
 914         mb_put_uint32le(mbp, 0);        /* FID - basis for path if not root */
 915         mb_put_uint32le(mbp, req_acc);
 916         mb_put_uint64le(mbp, 0);        /* "initial allocation size" */
 917         mb_put_uint32le(mbp, efa);
 918         mb_put_uint32le(mbp, share_acc);
 919         mb_put_uint32le(mbp, open_disp);
 920         mb_put_uint32le(mbp, createopt);
 921         mb_put_uint32le(mbp, impersonate);
 922         mb_put_uint8(mbp, 0);   /* security flags (?) */
 923         smb_rq_wend(rqp);
 924 
 925         /*
 926          * Byte parameters: Just the path name, aligned.
 927          * Note: mb_put_mbuf consumes mb_top, so clear it.
 928          */
 929         smb_rq_bstart(rqp);
 930         if (SMB_UNICODE_STRINGS(vcp))
 931                 mb_put_padbyte(mbp);
 932         mb_put_mbuf(mbp, name_mb->mb_top);
 933         bzero(name_mb, sizeof (*name_mb));
 934         smb_rq_bend(rqp);
 935 
 936         /*
 937          * Don't want to risk missing a successful
 938          * open response, or we could "leak" FIDs.
 939          */
 940         rqp->sr_flags |= SMBR_NOINTR_RECV;
 941         error = smb_rq_simple_timed(rqp, smb_timo_open);
 942         if (error)
 943                 goto done;
 944         smb_rq_getreply(rqp, &mdp);
 945         /*
 946          * spec says 26 for word count, but 34 words are defined
 947          * and observed from win2000
 948          */
 949         error = md_get_uint8(mdp, &wc);
 950         if (error)
 951                 goto done;
 952         if (wc != 26 && wc < 34) {
 953                 error = EBADRPC;
 954                 goto done;
 955         }
 956         md_get_uint8(mdp, NULL);                /* secondary cmd */
 957         md_get_uint8(mdp, NULL);                /* mbz */
 958         md_get_uint16le(mdp, NULL);             /* andxoffset */
 959         md_get_uint8(mdp, NULL);                /* oplock lvl granted */
 960         md_get_uint16le(mdp, &fid);         /* file ID */
 961         md_get_uint32le(mdp, &createact);   /* create_action */
 962 
 963         md_get_uint64le(mdp, &llongint);    /* creation time */
 964         smb_time_NT2local(llongint, &fa.fa_createtime);
 965         md_get_uint64le(mdp, &llongint);    /* access time */
 966         smb_time_NT2local(llongint, &fa.fa_atime);
 967         md_get_uint64le(mdp, &llongint);    /* write time */
 968         smb_time_NT2local(llongint, &fa.fa_mtime);
 969         md_get_uint64le(mdp, &llongint);    /* change time */
 970         smb_time_NT2local(llongint, &fa.fa_ctime);
 971 
 972         md_get_uint32le(mdp, &longint);             /* attributes */
 973         fa.fa_attr = longint;
 974         md_get_uint64le(mdp, &llongint);    /* allocation size */
 975         fa.fa_allocsz = llongint;
 976         md_get_uint64le(mdp, &llongint);    /* EOF position */
 977         fa.fa_size = llongint;
 978 
 979         error = md_get_uint16le(mdp, NULL);     /* file type */
 980         /* other stuff we don't care about */
 981 
 982 done:
 983         smb_rq_done(rqp);
 984         if (error)
 985                 return (error);
 986 
 987         *fidp = fid;
 988         if (cr_act_p)
 989                 *cr_act_p = createact;
 990         if (fap)
 991                 *fap = fa; /* struct copy */
 992 
 993         return (0);
 994 }
 995 
 996 int
 997 smb1_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
 998         struct smb_cred *scrp)
 999 {
1000         struct smb_rq rq, *rqp = &rq;
1001         struct mbchain *mbp;
1002         long time;
1003         int error;
1004 
1005         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
1006         if (error)
1007                 return (error);
1008         smb_rq_getrequest(rqp, &mbp);
1009         smb_rq_wstart(rqp);
1010         mb_put_uint16le(mbp, fid);
1011         if (mtime) {
1012                 int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz;
1013                 smb_time_local2server(mtime, sv_tz, &time);
1014         } else {
1015                 time = 0;
1016         }
1017         mb_put_uint32le(mbp, time);
1018         smb_rq_wend(rqp);
1019         smb_rq_bstart(rqp);
1020         smb_rq_bend(rqp);
1021 
1022         /* Make sure we send, but only if already connected */
1023         rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
1024         error = smb_rq_simple(rqp);
1025         smb_rq_done(rqp);
1026         return (error);
1027 }
1028 
1029 int
1030 smb_smb_open_prjob(
1031         struct smb_share *ssp,
1032         char    *title,
1033         uint16_t setuplen,
1034         uint16_t mode,
1035         struct smb_cred *scrp,
1036         uint16_t *fidp)
1037 {
1038         struct smb_rq rq, *rqp = &rq;
1039         struct smb_vc *vcp = SSTOVC(ssp);
1040         struct mbchain *mbp;
1041         struct mdchain *mdp;
1042         uint16_t fid;
1043         uint8_t wc;
1044         int error;
1045 
1046         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN_PRINT_FILE, scrp);
1047         if (error)
1048                 return (error);
1049         smb_rq_getrequest(rqp, &mbp);
1050 
1051         /* Word parameters */
1052         smb_rq_wstart(rqp);
1053         mb_put_uint16le(mbp, setuplen);
1054         mb_put_uint16le(mbp, mode);
1055         smb_rq_wend(rqp);
1056 
1057         /*
1058          * Byte parameters: Just the title
1059          */
1060         smb_rq_bstart(rqp);
1061         mb_put_uint8(mbp, SMB_DT_ASCII);
1062         error = smb_put_dstring(mbp, vcp, title, SMB_CS_NONE);
1063         smb_rq_bend(rqp);
1064         if (error)
1065                 goto done;
1066 
1067         /*
1068          * Don't want to risk missing a successful
1069          * open response, or we could "leak" FIDs.
1070          */
1071         rqp->sr_flags |= SMBR_NOINTR_RECV;
1072         error = smb_rq_simple_timed(rqp, smb_timo_open);
1073         if (error)
1074                 goto done;
1075 
1076         smb_rq_getreply(rqp, &mdp);
1077         error = md_get_uint8(mdp, &wc);
1078         if (error || wc < 1) {
1079                 error = EBADRPC;
1080                 goto done;
1081         }
1082         error = md_get_uint16le(mdp, &fid);
1083 
1084 done:
1085         smb_rq_done(rqp);
1086         if (error)
1087                 return (error);
1088 
1089         *fidp = fid;
1090         return (0);
1091 }
1092 
1093 /*
1094  * Like smb_smb_close, but for print shares.
1095  */
1096 int
1097 smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
1098         struct smb_cred *scrp)
1099 {
1100         struct smb_rq rq, *rqp = &rq;
1101         struct mbchain *mbp;
1102         int error;
1103 
1104         error = smb_rq_init(rqp, SSTOCP(ssp),
1105             SMB_COM_CLOSE_PRINT_FILE, scrp);
1106         if (error)
1107                 return (error);
1108         smb_rq_getrequest(rqp, &mbp);
1109         smb_rq_wstart(rqp);
1110         mb_put_uint16le(mbp, fid);
1111         smb_rq_wend(rqp);
1112         smb_rq_bstart(rqp);
1113         smb_rq_bend(rqp);
1114 
1115         /* Make sure we send but only if already connected */
1116         rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
1117         error = smb_rq_simple(rqp);
1118         smb_rq_done(rqp);
1119         return (error);
1120 }
1121 
1122 int
1123 smb_smb_readx(smb_fh_t *fhp, uint32_t *lenp,
1124         uio_t *uiop, smb_cred_t *scred, int timo)
1125 {
1126         struct smb_share *ssp = FHTOSS(fhp);
1127         struct smb_rq *rqp;
1128         struct mbchain *mbp;
1129         struct mdchain *mdp;
1130         int error;
1131         uint32_t offlo, offhi, rlen;
1132         uint16_t lenhi, lenlo, off, doff;
1133         uint8_t wc;
1134 
1135         lenhi = (uint16_t)(*lenp >> 16);
1136         lenlo = (uint16_t)*lenp;
1137         offhi = (uint32_t)(uiop->uio_loffset >> 32);
1138         offlo = (uint32_t)uiop->uio_loffset;
1139 
1140         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
1141         if (error)
1142                 return (error);
1143         smb_rq_getrequest(rqp, &mbp);
1144         smb_rq_wstart(rqp);
1145         mb_put_uint8(mbp, 0xff);        /* no secondary command */
1146         mb_put_uint8(mbp, 0);           /* MBZ */
1147         mb_put_uint16le(mbp, 0);        /* offset to secondary */
1148         mb_put_uint16le(mbp, fhp->fh_fid1);
1149         mb_put_uint32le(mbp, offlo);    /* offset (low part) */
1150         mb_put_uint16le(mbp, lenlo);    /* MaxCount */
1151         mb_put_uint16le(mbp, 1);        /* MinCount */
1152                                         /* (only indicates blocking) */
1153         mb_put_uint32le(mbp, lenhi);    /* MaxCountHigh */
1154         mb_put_uint16le(mbp, lenlo);    /* Remaining ("obsolete") */
1155         mb_put_uint32le(mbp, offhi);    /* offset (high part) */
1156         smb_rq_wend(rqp);
1157         smb_rq_bstart(rqp);
1158         smb_rq_bend(rqp);
1159 
1160         if (timo == 0)
1161                 timo = smb_timo_read;
1162         error = smb_rq_simple_timed(rqp, timo);
1163         if (error)
1164                 goto out;
1165 
1166         smb_rq_getreply(rqp, &mdp);
1167         error = md_get_uint8(mdp, &wc);
1168         if (error)
1169                 goto out;
1170         if (wc != 12) {
1171                 error = EBADRPC;
1172                 goto out;
1173         }
1174         md_get_uint8(mdp, NULL);
1175         md_get_uint8(mdp, NULL);
1176         md_get_uint16le(mdp, NULL);
1177         md_get_uint16le(mdp, NULL);
1178         md_get_uint16le(mdp, NULL);     /* data compaction mode */
1179         md_get_uint16le(mdp, NULL);
1180         md_get_uint16le(mdp, &lenlo);       /* data len ret. */
1181         md_get_uint16le(mdp, &doff);        /* data offset */
1182         md_get_uint16le(mdp, &lenhi);
1183         rlen = (lenhi << 16) | lenlo;
1184         md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
1185         error = md_get_uint16le(mdp, NULL);     /* ByteCount */
1186         if (error)
1187                 goto out;
1188         /*
1189          * Does the data offset indicate padding?
1190          * The current offset is a constant, found
1191          * by counting the md_get_ calls above.
1192          */
1193         off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */
1194         if (doff > off)      /* pad byte(s)? */
1195                 md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
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         error = md_get_uio(mdp, uiop, rlen);
1207         if (error)
1208                 goto out;
1209 
1210         /* Success */
1211         *lenp = rlen;
1212 
1213 out:
1214         smb_rq_done(rqp);
1215         return (error);
1216 }
1217 
1218 int
1219 smb_smb_writex(smb_fh_t *fhp, uint32_t *lenp,
1220         uio_t *uiop, smb_cred_t *scred, int timo)
1221 {
1222         struct smb_share *ssp = FHTOSS(fhp);
1223         struct smb_rq *rqp;
1224         struct mbchain *mbp;
1225         struct mdchain *mdp;
1226         int error;
1227         uint32_t offlo, offhi, rlen;
1228         uint16_t lenhi, lenlo;
1229         uint8_t wc;
1230 
1231         lenhi = (uint16_t)(*lenp >> 16);
1232         lenlo = (uint16_t)*lenp;
1233         offhi = (uint32_t)(uiop->uio_loffset >> 32);
1234         offlo = (uint32_t)uiop->uio_loffset;
1235 
1236         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
1237         if (error)
1238                 return (error);
1239         smb_rq_getrequest(rqp, &mbp);
1240         smb_rq_wstart(rqp);
1241         mb_put_uint8(mbp, 0xff);        /* no secondary command */
1242         mb_put_uint8(mbp, 0);           /* MBZ */
1243         mb_put_uint16le(mbp, 0);        /* offset to secondary */
1244         mb_put_uint16le(mbp, fhp->fh_fid1);
1245         mb_put_uint32le(mbp, offlo);    /* offset (low part) */
1246         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
1247         mb_put_uint16le(mbp, 0);        /* !write-thru */
1248         mb_put_uint16le(mbp, 0);
1249         mb_put_uint16le(mbp, lenhi);
1250         mb_put_uint16le(mbp, lenlo);
1251         mb_put_uint16le(mbp, 64);       /* data offset from header start */
1252         mb_put_uint32le(mbp, offhi);    /* offset (high part) */
1253         smb_rq_wend(rqp);
1254         smb_rq_bstart(rqp);
1255 
1256         mb_put_uint8(mbp, 0);   /* pad byte */
1257         error = mb_put_uio(mbp, uiop, *lenp);
1258         if (error)
1259                 goto out;
1260         smb_rq_bend(rqp);
1261         if (timo == 0)
1262                 timo = smb_timo_write;
1263         error = smb_rq_simple_timed(rqp, timo);
1264         if (error)
1265                 goto out;
1266         smb_rq_getreply(rqp, &mdp);
1267         error = md_get_uint8(mdp, &wc);
1268         if (error)
1269                 goto out;
1270         if (wc != 6) {
1271                 error = EBADRPC;
1272                 goto out;
1273         }
1274         md_get_uint8(mdp, NULL);        /* andx cmd */
1275         md_get_uint8(mdp, NULL);        /* reserved */
1276         md_get_uint16le(mdp, NULL);     /* andx offset */
1277         md_get_uint16le(mdp, &lenlo);       /* data len ret. */
1278         md_get_uint16le(mdp, NULL);     /* remaining */
1279         error = md_get_uint16le(mdp, &lenhi);
1280         if (error)
1281                 goto out;
1282 
1283         /* Success */
1284         rlen = (lenhi << 16) | lenlo;
1285         *lenp = rlen;
1286 
1287 out:
1288         smb_rq_done(rqp);
1289         return (error);
1290 }
1291 
1292 
1293 static u_int32_t        smbechoes = 0;
1294 
1295 /*
1296  * Note: the IOD calls this, so this request must not wait for
1297  * connection state changes, etc. (uses smb_rq_internal)
1298  */
1299 int
1300 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1301 {
1302         struct smb_rq *rqp;
1303         struct mbchain *mbp;
1304         int error;
1305 
1306         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
1307         if (error)
1308                 return (error);
1309         mbp = &rqp->sr_rq;
1310         smb_rq_wstart(rqp);
1311         mb_put_uint16le(mbp, 1); /* echo count */
1312         smb_rq_wend(rqp);
1313         smb_rq_bstart(rqp);
1314         mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
1315         smb_rq_bend(rqp);
1316         rqp->sr_flags |= SMBR_NORECONNECT;
1317         error = smb_rq_internal(rqp, timo);
1318         SMBSDEBUG("%d\n", error);
1319         smb_rq_done(rqp);
1320         return (error);
1321 }