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  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  37  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  38  */
  39 
  40 /*
  41  * various SMB requests. Most of the routines merely packs data into mbufs.
  42  */
  43 #include <sys/param.h>
  44 #include <sys/systm.h>
  45 #include <sys/kmem.h>
  46 #include <sys/proc.h>
  47 #include <sys/lock.h>
  48 #include <sys/socket.h>
  49 #include <sys/uio.h>
  50 #include <sys/random.h>
  51 #include <sys/note.h>
  52 #include <sys/cmn_err.h>
  53 
  54 #include <netsmb/smb_osdep.h>
  55 
  56 #include <netsmb/smb.h>
  57 #include <netsmb/smb_conn.h>
  58 #include <netsmb/smb_rq.h>
  59 #include <netsmb/smb_subr.h>
  60 #include <netsmb/smb_tran.h>
  61 
  62 #define STYPE_LEN       8       /* share type strings */
  63 
  64 /*
  65  * Largest size to use with LARGE_READ/LARGE_WRITE.
  66  * Specs say up to 64k data bytes, but Windows traffic
  67  * uses 60k... no doubt for some good reason.
  68  * (Probably to keep 4k block alignment.)
  69  * XXX: Move to smb.h maybe?
  70  */
  71 #define SMB_MAX_LARGE_RW_SIZE (60*1024)
  72 
  73 /*
  74  * Default timeout values, all in seconds.
  75  * Make these tunable (only via mdb for now).
  76  */
  77 int smb_timo_notice = 15;
  78 int smb_timo_default = 30;      /* was SMB_DEFRQTIMO */
  79 int smb_timo_open = 45;
  80 int smb_timo_read = 45;
  81 int smb_timo_write = 60;        /* was SMBWRTTIMO */
  82 int smb_timo_append = 90;
  83 
  84 static int smb_smb_read(struct smb_share *ssp, uint16_t fid,
  85         uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
  86 static int smb_smb_write(struct smb_share *ssp, uint16_t fid,
  87         uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
  88 
  89 static int smb_smb_readx(struct smb_share *ssp, uint16_t fid,
  90         uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
  91 static int smb_smb_writex(struct smb_share *ssp, uint16_t fid,
  92         uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo);
  93 
  94 /*
  95  * Get the string representation of a share "use" type,
  96  * as needed for the "service" in tree connect.
  97  */
  98 static const char *
  99 smb_share_typename(uint32_t stype)
 100 {
 101         const char *p;
 102 
 103         switch (stype) {
 104         case STYPE_DISKTREE:
 105                 p = "A:";
 106                 break;
 107         case STYPE_PRINTQ:
 108                 p = "LPT1:";
 109                 break;
 110         case STYPE_DEVICE:
 111                 p = "COMM";
 112                 break;
 113         case STYPE_IPC:
 114                 p = "IPC";
 115                 break;
 116         case STYPE_UNKNOWN:
 117         default:
 118                 p = "?????";
 119                 break;
 120         }
 121         return (p);
 122 }
 123 
 124 /*
 125  * Parse a share type name (inverse of above)
 126  */
 127 static uint32_t
 128 smb_share_parsetype(char *name)
 129 {
 130         int stype;
 131 
 132         switch (*name) {
 133         case 'A':       /* A: */
 134                 stype = STYPE_DISKTREE;
 135                 break;
 136         case 'C':       /* COMM */
 137                 stype = STYPE_DEVICE;
 138                 break;
 139         case 'I':       /* IPC */
 140                 stype = STYPE_IPC;
 141                 break;
 142         case 'L':       /* LPT: */
 143                 stype = STYPE_PRINTQ;
 144                 break;
 145         default:
 146                 stype = STYPE_UNKNOWN;
 147                 break;
 148         }
 149         return (stype);
 150 }
 151 
 152 int
 153 smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
 154 {
 155         struct smb_vc *vcp;
 156         struct smb_rq *rqp = NULL;
 157         struct mbchain *mbp;
 158         struct mdchain *mdp;
 159         const char *tname;
 160         char *pbuf, *unc_name = NULL;
 161         int error, tlen, plen, unc_len;
 162         uint16_t bcnt, options;
 163         uint8_t wc;
 164         char stype_str[STYPE_LEN];
 165 
 166         vcp = SSTOVC(ssp);
 167 
 168         /*
 169          * Make this a "VC-level" request, so it will have
 170          * rqp->sr_share == NULL, and smb_iod_sendrq()
 171          * will send it with TID = SMB_TID_UNKNOWN
 172          *
 173          * This also serves to bypass the wait for
 174          * share state changes, which this call is
 175          * trying to carry out.
 176          */
 177         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_CONNECT_ANDX,
 178             scred, &rqp);
 179         if (error)
 180                 return (error);
 181 
 182         /*
 183          * Build the UNC name, i.e. "//server/share"
 184          * but with backslashes of course.
 185          * size math: three slashes, one null.
 186          */
 187         unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
 188         unc_name = kmem_alloc(unc_len, KM_SLEEP);
 189         (void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
 190             vcp->vc_srvname, ssp->ss_name);
 191         SMBSDEBUG("unc_name: \"%s\"", unc_name);
 192 
 193 
 194         /*
 195          * Share-level password (pre-computed in user-space)
 196          * MS-SMB 2.2.6 says this should be null terminated,
 197          * and the pw length includes the null.
 198          */
 199         pbuf = ssp->ss_pass;
 200         plen = strlen(pbuf) + 1;
 201 
 202         /*
 203          * Build the request.
 204          */
 205         mbp = &rqp->sr_rq;
 206         smb_rq_wstart(rqp);
 207         mb_put_uint8(mbp, 0xff);
 208         mb_put_uint8(mbp, 0);
 209         mb_put_uint16le(mbp, 0);
 210         mb_put_uint16le(mbp, 0);                /* Flags */
 211         mb_put_uint16le(mbp, plen);
 212         smb_rq_wend(rqp);
 213         smb_rq_bstart(rqp);
 214 
 215         /* Tree connect password, if any */
 216         error = mb_put_mem(mbp, pbuf, plen, MB_MSYSTEM);
 217         if (error)
 218                 goto out;
 219 
 220         /* UNC resource name */
 221         error = smb_put_dstring(mbp, vcp, unc_name, SMB_CS_NONE);
 222         if (error)
 223                 goto out;
 224 
 225         /*
 226          * Put the type string (always ASCII),
 227          * including the null.
 228          */
 229         tname = smb_share_typename(ssp->ss_use);
 230         tlen = strlen(tname) + 1;
 231         error = mb_put_mem(mbp, tname, tlen, MB_MSYSTEM);
 232         if (error)
 233                 goto out;
 234 
 235         smb_rq_bend(rqp);
 236 
 237         /*
 238          * Run the request.
 239          *
 240          * Using NOINTR_RECV because we don't want to risk
 241          * missing a successful tree connect response,
 242          * which would "leak" Tree IDs.
 243          */
 244         rqp->sr_flags |= SMBR_NOINTR_RECV;
 245         error = smb_rq_simple(rqp);
 246         SMBSDEBUG("%d\n", error);
 247         if (error) {
 248                 /*
 249                  * If we get the server name wrong, i.e. due to
 250                  * mis-configured name services, this will be
 251                  * NT_STATUS_DUPLICATE_NAME.  Log this error.
 252                  */
 253                 SMBERROR("(%s) failed, status=0x%x",
 254                     unc_name, rqp->sr_error);
 255                 goto out;
 256         }
 257 
 258         /*
 259          * Parse the TCON response
 260          */
 261         smb_rq_getreply(rqp, &mdp);
 262         md_get_uint8(mdp, &wc);
 263         if (wc != 3 && wc != 7) {
 264                 error = EBADRPC;
 265                 goto out;
 266         }
 267         md_get_uint16le(mdp, NULL);             /* AndX cmd */
 268         md_get_uint16le(mdp, NULL);             /* AndX off */
 269         md_get_uint16le(mdp, &options);             /* option bits (DFS, search) */
 270         if (wc == 7) {
 271                 md_get_uint32le(mdp, NULL);     /* MaximalShareAccessRights */
 272                 md_get_uint32le(mdp, NULL);     /* GuestMaximalShareAcc... */
 273         }
 274         error = md_get_uint16le(mdp, &bcnt);        /* byte count */
 275         if (error)
 276                 goto out;
 277 
 278         /*
 279          * Get the returned share type string, i.e. "IPC" or whatever.
 280          * (See smb_share_typename, smb_share_parsetype).  If we get
 281          * an error reading the type, just say STYPE_UNKNOWN.
 282          */
 283         tlen = STYPE_LEN;
 284         bzero(stype_str, tlen--);
 285         if (tlen > bcnt)
 286                 tlen = bcnt;
 287         md_get_mem(mdp, stype_str, tlen, MB_MSYSTEM);
 288         stype_str[tlen] = '\0';
 289         ssp->ss_type = smb_share_parsetype(stype_str);
 290 
 291         /* Success! */
 292         SMB_SS_LOCK(ssp);
 293         ssp->ss_tid = rqp->sr_rptid;
 294         ssp->ss_vcgenid = vcp->vc_genid;
 295         ssp->ss_options = options;
 296         ssp->ss_flags |= SMBS_CONNECTED;
 297         SMB_SS_UNLOCK(ssp);
 298 
 299 out:
 300         if (unc_name)
 301                 kmem_free(unc_name, unc_len);
 302         smb_rq_done(rqp);
 303         return (error);
 304 }
 305 
 306 int
 307 smb_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
 308 {
 309         struct smb_vc *vcp;
 310         struct smb_rq *rqp;
 311         int error;
 312 
 313         if (ssp->ss_tid == SMB_TID_UNKNOWN)
 314                 return (0);
 315 
 316         /*
 317          * Build this as a "VC-level" request, so it will
 318          * avoid testing the _GONE flag on the share,
 319          * which has already been set at this point.
 320          * Add the share pointer "by hand" below, so
 321          * smb_iod_sendrq will plug in the TID.
 322          */
 323         vcp = SSTOVC(ssp);
 324         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_TREE_DISCONNECT, scred, &rqp);
 325         if (error)
 326                 return (error);
 327         rqp->sr_share = ssp; /* by hand */
 328 
 329         smb_rq_wstart(rqp);
 330         smb_rq_wend(rqp);
 331         smb_rq_bstart(rqp);
 332         smb_rq_bend(rqp);
 333 
 334         /*
 335          * Run this with a relatively short timeout. (5 sec.)
 336          * We don't really care about the result here, but we
 337          * do need to make sure we send this out, or we could
 338          * "leak" active tree IDs on interrupt or timeout.
 339          * The NOINTR_SEND flag makes this request immune to
 340          * interrupt or timeout until the send is done.
 341          * Also, don't reconnect for this, of course!
 342          */
 343         rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
 344         error = smb_rq_simple_timed(rqp, 5);
 345         SMBSDEBUG("%d\n", error);
 346         smb_rq_done(rqp);
 347         ssp->ss_tid = SMB_TID_UNKNOWN;
 348         return (error);
 349 }
 350 
 351 /*
 352  * Modern create/open of file or directory.
 353  */
 354 int
 355 smb_smb_ntcreate(
 356         struct smb_share *ssp,
 357         struct mbchain  *name_mb,
 358         uint32_t cr_flags,      /* create flags */
 359         uint32_t req_acc,       /* requested access */
 360         uint32_t efa,           /* ext. file attrs (DOS attr +) */
 361         uint32_t share_acc,
 362         uint32_t open_disp,     /* open disposition */
 363         uint32_t createopt,     /* NTCREATEX_OPTIONS_ */
 364         uint32_t impersonate,   /* NTCREATEX_IMPERSONATION_... */
 365         struct smb_cred *scrp,
 366         uint16_t *fidp,         /* returned FID */
 367         uint32_t *cr_act_p,     /* optional create action */
 368         struct smbfattr *fap)   /* optional attributes */
 369 {
 370         struct smb_rq rq, *rqp = &rq;
 371         struct smb_vc *vcp = SSTOVC(ssp);
 372         struct mbchain *mbp;
 373         struct mdchain *mdp;
 374         struct smbfattr fa;
 375         uint64_t llongint;
 376         uint32_t longint, createact;
 377         uint16_t fid;
 378         uint8_t wc;
 379         int error;
 380 
 381         bzero(&fa, sizeof (fa));
 382         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp);
 383         if (error)
 384                 return (error);
 385         smb_rq_getrequest(rqp, &mbp);
 386 
 387         /* Word parameters */
 388         smb_rq_wstart(rqp);
 389         mb_put_uint8(mbp, 0xff);        /* secondary command */
 390         mb_put_uint8(mbp, 0);           /* MBZ */
 391         mb_put_uint16le(mbp, 0);        /* offset to next command (none) */
 392         mb_put_uint8(mbp, 0);           /* MBZ */
 393         mb_put_uint16le(mbp, name_mb->mb_count);
 394         mb_put_uint32le(mbp, cr_flags); /* NTCREATEX_FLAGS_* */
 395         mb_put_uint32le(mbp, 0);        /* FID - basis for path if not root */
 396         mb_put_uint32le(mbp, req_acc);
 397         mb_put_uint64le(mbp, 0);        /* "initial allocation size" */
 398         mb_put_uint32le(mbp, efa);
 399         mb_put_uint32le(mbp, share_acc);
 400         mb_put_uint32le(mbp, open_disp);
 401         mb_put_uint32le(mbp, createopt);
 402         mb_put_uint32le(mbp, impersonate);
 403         mb_put_uint8(mbp, 0);   /* security flags (?) */
 404         smb_rq_wend(rqp);
 405 
 406         /*
 407          * Byte parameters: Just the path name, aligned.
 408          * Note: mb_put_mbuf consumes mb_top, so clear it.
 409          */
 410         smb_rq_bstart(rqp);
 411         if (SMB_UNICODE_STRINGS(vcp))
 412                 mb_put_padbyte(mbp);
 413         mb_put_mbuf(mbp, name_mb->mb_top);
 414         bzero(name_mb, sizeof (*name_mb));
 415         smb_rq_bend(rqp);
 416 
 417         /*
 418          * Don't want to risk missing a successful
 419          * open response, or we could "leak" FIDs.
 420          */
 421         rqp->sr_flags |= SMBR_NOINTR_RECV;
 422         error = smb_rq_simple_timed(rqp, smb_timo_open);
 423         if (error)
 424                 goto done;
 425         smb_rq_getreply(rqp, &mdp);
 426         /*
 427          * spec says 26 for word count, but 34 words are defined
 428          * and observed from win2000
 429          */
 430         error = md_get_uint8(mdp, &wc);
 431         if (error)
 432                 goto done;
 433         if (wc != 26 && wc < 34) {
 434                 error = EBADRPC;
 435                 goto done;
 436         }
 437         md_get_uint8(mdp, NULL);                /* secondary cmd */
 438         md_get_uint8(mdp, NULL);                /* mbz */
 439         md_get_uint16le(mdp, NULL);             /* andxoffset */
 440         md_get_uint8(mdp, NULL);                /* oplock lvl granted */
 441         md_get_uint16le(mdp, &fid);         /* file ID */
 442         md_get_uint32le(mdp, &createact);   /* create_action */
 443 
 444         md_get_uint64le(mdp, &llongint);    /* creation time */
 445         smb_time_NT2local(llongint, &fa.fa_createtime);
 446         md_get_uint64le(mdp, &llongint);    /* access time */
 447         smb_time_NT2local(llongint, &fa.fa_atime);
 448         md_get_uint64le(mdp, &llongint);    /* write time */
 449         smb_time_NT2local(llongint, &fa.fa_mtime);
 450         md_get_uint64le(mdp, &llongint);    /* change time */
 451         smb_time_NT2local(llongint, &fa.fa_ctime);
 452 
 453         md_get_uint32le(mdp, &longint);             /* attributes */
 454         fa.fa_attr = longint;
 455         md_get_uint64le(mdp, &llongint);    /* allocation size */
 456         fa.fa_allocsz = llongint;
 457         md_get_uint64le(mdp, &llongint);    /* EOF position */
 458         fa.fa_size = llongint;
 459 
 460         error = md_get_uint16le(mdp, NULL);     /* file type */
 461         /* other stuff we don't care about */
 462 
 463 done:
 464         smb_rq_done(rqp);
 465         if (error)
 466                 return (error);
 467 
 468         *fidp = fid;
 469         if (cr_act_p)
 470                 *cr_act_p = createact;
 471         if (fap)
 472                 *fap = fa; /* struct copy */
 473 
 474         return (0);
 475 }
 476 
 477 int
 478 smb_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime,
 479         struct smb_cred *scrp)
 480 {
 481         struct smb_rq rq, *rqp = &rq;
 482         struct mbchain *mbp;
 483         long time;
 484         int error;
 485 
 486         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_CLOSE, scrp);
 487         if (error)
 488                 return (error);
 489         smb_rq_getrequest(rqp, &mbp);
 490         smb_rq_wstart(rqp);
 491         mb_put_uint16le(mbp, fid);
 492         if (mtime) {
 493                 int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz;
 494                 smb_time_local2server(mtime, sv_tz, &time);
 495         } else {
 496                 time = 0;
 497         }
 498         mb_put_uint32le(mbp, time);
 499         smb_rq_wend(rqp);
 500         smb_rq_bstart(rqp);
 501         smb_rq_bend(rqp);
 502 
 503         /* Make sure we send, but only if already connected */
 504         rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
 505         error = smb_rq_simple(rqp);
 506         smb_rq_done(rqp);
 507         return (error);
 508 }
 509 
 510 int
 511 smb_smb_open_prjob(
 512         struct smb_share *ssp,
 513         char    *title,
 514         uint16_t setuplen,
 515         uint16_t mode,
 516         struct smb_cred *scrp,
 517         uint16_t *fidp)
 518 {
 519         struct smb_rq rq, *rqp = &rq;
 520         struct smb_vc *vcp = SSTOVC(ssp);
 521         struct mbchain *mbp;
 522         struct mdchain *mdp;
 523         uint16_t fid;
 524         uint8_t wc;
 525         int error;
 526 
 527         error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN_PRINT_FILE, scrp);
 528         if (error)
 529                 return (error);
 530         smb_rq_getrequest(rqp, &mbp);
 531 
 532         /* Word parameters */
 533         smb_rq_wstart(rqp);
 534         mb_put_uint16le(mbp, setuplen);
 535         mb_put_uint16le(mbp, mode);
 536         smb_rq_wend(rqp);
 537 
 538         /*
 539          * Byte parameters: Just the title
 540          */
 541         smb_rq_bstart(rqp);
 542         mb_put_uint8(mbp, SMB_DT_ASCII);
 543         error = smb_put_dstring(mbp, vcp, title, SMB_CS_NONE);
 544         smb_rq_bend(rqp);
 545         if (error)
 546                 goto done;
 547 
 548         /*
 549          * Don't want to risk missing a successful
 550          * open response, or we could "leak" FIDs.
 551          */
 552         rqp->sr_flags |= SMBR_NOINTR_RECV;
 553         error = smb_rq_simple_timed(rqp, smb_timo_open);
 554         if (error)
 555                 goto done;
 556 
 557         smb_rq_getreply(rqp, &mdp);
 558         error = md_get_uint8(mdp, &wc);
 559         if (error || wc < 1) {
 560                 error = EBADRPC;
 561                 goto done;
 562         }
 563         error = md_get_uint16le(mdp, &fid);
 564 
 565 done:
 566         smb_rq_done(rqp);
 567         if (error)
 568                 return (error);
 569 
 570         *fidp = fid;
 571         return (0);
 572 }
 573 
 574 /*
 575  * Like smb_smb_close, but for print shares.
 576  */
 577 int
 578 smb_smb_close_prjob(struct smb_share *ssp, uint16_t fid,
 579         struct smb_cred *scrp)
 580 {
 581         struct smb_rq rq, *rqp = &rq;
 582         struct mbchain *mbp;
 583         int error;
 584 
 585         error = smb_rq_init(rqp, SSTOCP(ssp),
 586             SMB_COM_CLOSE_PRINT_FILE, scrp);
 587         if (error)
 588                 return (error);
 589         smb_rq_getrequest(rqp, &mbp);
 590         smb_rq_wstart(rqp);
 591         mb_put_uint16le(mbp, fid);
 592         smb_rq_wend(rqp);
 593         smb_rq_bstart(rqp);
 594         smb_rq_bend(rqp);
 595 
 596         /* Make sure we send but only if already connected */
 597         rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
 598         error = smb_rq_simple(rqp);
 599         smb_rq_done(rqp);
 600         return (error);
 601 }
 602 
 603 /*
 604  * Common function for read/write with UIO.
 605  * Called by netsmb smb_usr_rw,
 606  *  smbfs_readvnode, smbfs_writevnode
 607  */
 608 int
 609 smb_rwuio(struct smb_share *ssp, uint16_t fid, uio_rw_t rw,
 610         uio_t *uiop, smb_cred_t *scred, int timo)
 611 {
 612         struct smb_vc *vcp = SSTOVC(ssp);
 613         ssize_t  save_resid;
 614         uint32_t len, rlen, maxlen;
 615         int error = 0;
 616         int (*iofun)(struct smb_share *, uint16_t, uint32_t *,
 617             uio_t *, smb_cred_t *, int);
 618 
 619         /*
 620          * Determine which function to use,
 621          * and the transfer size per call.
 622          */
 623         if (SMB_DIALECT(vcp) >= SMB_DIALECT_NTLM0_12) {
 624                 /*
 625                  * Using NT LM 0.12, so readx, writex.
 626                  * Make sure we can represent the offset.
 627                  */
 628                 if ((vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) == 0 &&
 629                     (uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
 630                         return (EFBIG);
 631 
 632                 if (rw == UIO_READ) {
 633                         iofun = smb_smb_readx;
 634                         if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_READX)
 635                                 maxlen = SMB_MAX_LARGE_RW_SIZE;
 636                         else
 637                                 maxlen = vcp->vc_rxmax;
 638                 } else { /* UIO_WRITE */
 639                         iofun = smb_smb_writex;
 640                         if (vcp->vc_sopt.sv_caps & SMB_CAP_LARGE_WRITEX)
 641                                 maxlen = SMB_MAX_LARGE_RW_SIZE;
 642                         else
 643                                 maxlen = vcp->vc_wxmax;
 644                 }
 645         } else {
 646                 /*
 647                  * Using the old SMB_READ and SMB_WRITE so
 648                  * we're limited to 32-bit offsets, etc.
 649                  * XXX: Someday, punt the old dialects.
 650                  */
 651                 if ((uiop->uio_loffset + uiop->uio_resid) > UINT32_MAX)
 652                         return (EFBIG);
 653 
 654                 if (rw == UIO_READ) {
 655                         iofun = smb_smb_read;
 656                         maxlen = vcp->vc_rxmax;
 657                 } else { /* UIO_WRITE */
 658                         iofun = smb_smb_write;
 659                         maxlen = vcp->vc_wxmax;
 660                 }
 661         }
 662 
 663         save_resid = uiop->uio_resid;
 664         while (uiop->uio_resid > 0) {
 665                 /* Lint: uio_resid may be 64-bits */
 666                 rlen = len = (uint32_t)min(maxlen, uiop->uio_resid);
 667                 error = (*iofun)(ssp, fid, &rlen, uiop, scred, timo);
 668 
 669                 /*
 670                  * Note: the iofun called uio_update, so
 671                  * not doing that here as one might expect.
 672                  *
 673                  * Quit the loop either on error, or if we
 674                  * transferred less then requested.
 675                  */
 676                 if (error || (rlen < len))
 677                         break;
 678 
 679                 timo = 0; /* only first I/O should wait */
 680         }
 681         if (error && (save_resid != uiop->uio_resid)) {
 682                 /*
 683                  * Stopped on an error after having
 684                  * successfully transferred data.
 685                  * Suppress this error.
 686                  */
 687                 SMBSDEBUG("error %d suppressed\n", error);
 688                 error = 0;
 689         }
 690 
 691         return (error);
 692 }
 693 
 694 static int
 695 smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
 696         uio_t *uiop, smb_cred_t *scred, int timo)
 697 {
 698         struct smb_rq *rqp;
 699         struct mbchain *mbp;
 700         struct mdchain *mdp;
 701         int error;
 702         uint32_t offlo, offhi, rlen;
 703         uint16_t lenhi, lenlo, off, doff;
 704         uint8_t wc;
 705 
 706         lenhi = (uint16_t)(*lenp >> 16);
 707         lenlo = (uint16_t)*lenp;
 708         offhi = (uint32_t)(uiop->uio_loffset >> 32);
 709         offlo = (uint32_t)uiop->uio_loffset;
 710 
 711         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ_ANDX, scred, &rqp);
 712         if (error)
 713                 return (error);
 714         smb_rq_getrequest(rqp, &mbp);
 715         smb_rq_wstart(rqp);
 716         mb_put_uint8(mbp, 0xff);        /* no secondary command */
 717         mb_put_uint8(mbp, 0);           /* MBZ */
 718         mb_put_uint16le(mbp, 0);        /* offset to secondary */
 719         mb_put_uint16le(mbp, fid);
 720         mb_put_uint32le(mbp, offlo);    /* offset (low part) */
 721         mb_put_uint16le(mbp, lenlo);    /* MaxCount */
 722         mb_put_uint16le(mbp, 1);        /* MinCount */
 723                                         /* (only indicates blocking) */
 724         mb_put_uint32le(mbp, lenhi);    /* MaxCountHigh */
 725         mb_put_uint16le(mbp, lenlo);    /* Remaining ("obsolete") */
 726         mb_put_uint32le(mbp, offhi);    /* offset (high part) */
 727         smb_rq_wend(rqp);
 728         smb_rq_bstart(rqp);
 729         smb_rq_bend(rqp);
 730 
 731         if (timo == 0)
 732                 timo = smb_timo_read;
 733         error = smb_rq_simple_timed(rqp, timo);
 734         if (error)
 735                 goto out;
 736 
 737         smb_rq_getreply(rqp, &mdp);
 738         error = md_get_uint8(mdp, &wc);
 739         if (error)
 740                 goto out;
 741         if (wc != 12) {
 742                 error = EBADRPC;
 743                 goto out;
 744         }
 745         md_get_uint8(mdp, NULL);
 746         md_get_uint8(mdp, NULL);
 747         md_get_uint16le(mdp, NULL);
 748         md_get_uint16le(mdp, NULL);
 749         md_get_uint16le(mdp, NULL);     /* data compaction mode */
 750         md_get_uint16le(mdp, NULL);
 751         md_get_uint16le(mdp, &lenlo);       /* data len ret. */
 752         md_get_uint16le(mdp, &doff);        /* data offset */
 753         md_get_uint16le(mdp, &lenhi);
 754         rlen = (lenhi << 16) | lenlo;
 755         md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);
 756         error = md_get_uint16le(mdp, NULL);     /* ByteCount */
 757         if (error)
 758                 goto out;
 759         /*
 760          * Does the data offset indicate padding?
 761          * The current offset is a constant, found
 762          * by counting the md_get_ calls above.
 763          */
 764         off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */
 765         if (doff > off)      /* pad byte(s)? */
 766                 md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM);
 767         if (rlen == 0) {
 768                 *lenp = rlen;
 769                 goto out;
 770         }
 771         /* paranoid */
 772         if (rlen > *lenp) {
 773                 SMBSDEBUG("bad server! rlen %d, len %d\n",
 774                     rlen, *lenp);
 775                 rlen = *lenp;
 776         }
 777         error = md_get_uio(mdp, uiop, rlen);
 778         if (error)
 779                 goto out;
 780 
 781         /* Success */
 782         *lenp = rlen;
 783 
 784 out:
 785         smb_rq_done(rqp);
 786         return (error);
 787 }
 788 
 789 static int
 790 smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
 791         uio_t *uiop, smb_cred_t *scred, int timo)
 792 {
 793         struct smb_rq *rqp;
 794         struct mbchain *mbp;
 795         struct mdchain *mdp;
 796         int error;
 797         uint32_t offlo, offhi, rlen;
 798         uint16_t lenhi, lenlo;
 799         uint8_t wc;
 800 
 801         lenhi = (uint16_t)(*lenp >> 16);
 802         lenlo = (uint16_t)*lenp;
 803         offhi = (uint32_t)(uiop->uio_loffset >> 32);
 804         offlo = (uint32_t)uiop->uio_loffset;
 805 
 806         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE_ANDX, scred, &rqp);
 807         if (error)
 808                 return (error);
 809         smb_rq_getrequest(rqp, &mbp);
 810         smb_rq_wstart(rqp);
 811         mb_put_uint8(mbp, 0xff);        /* no secondary command */
 812         mb_put_uint8(mbp, 0);           /* MBZ */
 813         mb_put_uint16le(mbp, 0);        /* offset to secondary */
 814         mb_put_uint16le(mbp, fid);
 815         mb_put_uint32le(mbp, offlo);    /* offset (low part) */
 816         mb_put_uint32le(mbp, 0);        /* MBZ (timeout) */
 817         mb_put_uint16le(mbp, 0);        /* !write-thru */
 818         mb_put_uint16le(mbp, 0);
 819         mb_put_uint16le(mbp, lenhi);
 820         mb_put_uint16le(mbp, lenlo);
 821         mb_put_uint16le(mbp, 64);       /* data offset from header start */
 822         mb_put_uint32le(mbp, offhi);    /* offset (high part) */
 823         smb_rq_wend(rqp);
 824         smb_rq_bstart(rqp);
 825 
 826         mb_put_uint8(mbp, 0);   /* pad byte */
 827         error = mb_put_uio(mbp, uiop, *lenp);
 828         if (error)
 829                 goto out;
 830         smb_rq_bend(rqp);
 831         if (timo == 0)
 832                 timo = smb_timo_write;
 833         error = smb_rq_simple_timed(rqp, timo);
 834         if (error)
 835                 goto out;
 836         smb_rq_getreply(rqp, &mdp);
 837         error = md_get_uint8(mdp, &wc);
 838         if (error)
 839                 goto out;
 840         if (wc != 6) {
 841                 error = EBADRPC;
 842                 goto out;
 843         }
 844         md_get_uint8(mdp, NULL);        /* andx cmd */
 845         md_get_uint8(mdp, NULL);        /* reserved */
 846         md_get_uint16le(mdp, NULL);     /* andx offset */
 847         md_get_uint16le(mdp, &lenlo);       /* data len ret. */
 848         md_get_uint16le(mdp, NULL);     /* remaining */
 849         error = md_get_uint16le(mdp, &lenhi);
 850         if (error)
 851                 goto out;
 852 
 853         /* Success */
 854         rlen = (lenhi << 16) | lenlo;
 855         *lenp = rlen;
 856 
 857 out:
 858         smb_rq_done(rqp);
 859         return (error);
 860 }
 861 
 862 static int
 863 smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
 864         uio_t *uiop, smb_cred_t *scred, int timo)
 865 {
 866         struct smb_rq *rqp;
 867         struct mbchain *mbp;
 868         struct mdchain *mdp;
 869         int error;
 870         uint32_t off32;
 871         uint16_t bc, cnt, dlen, rcnt, todo;
 872         uint8_t wc;
 873 
 874         ASSERT(uiop->uio_loffset <= UINT32_MAX);
 875         off32 = (uint32_t)uiop->uio_loffset;
 876         ASSERT(*lenp <= UINT16_MAX);
 877         cnt = (uint16_t)*lenp;
 878         /* This next is an "estimate" of planned reads. */
 879         todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
 880 
 881         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_READ, scred, &rqp);
 882         if (error)
 883                 return (error);
 884         smb_rq_getrequest(rqp, &mbp);
 885         smb_rq_wstart(rqp);
 886         mb_put_uint16le(mbp, fid);
 887         mb_put_uint16le(mbp, cnt);
 888         mb_put_uint32le(mbp, off32);
 889         mb_put_uint16le(mbp, todo);
 890         smb_rq_wend(rqp);
 891         smb_rq_bstart(rqp);
 892         smb_rq_bend(rqp);
 893 
 894         if (timo == 0)
 895                 timo = smb_timo_read;
 896         error = smb_rq_simple_timed(rqp, timo);
 897         if (error)
 898                 goto out;
 899         smb_rq_getreply(rqp, &mdp);
 900         error = md_get_uint8(mdp, &wc);
 901         if (error)
 902                 goto out;
 903         if (wc != 5) {
 904                 error = EBADRPC;
 905                 goto out;
 906         }
 907         md_get_uint16le(mdp, &rcnt);                /* ret. count */
 908         md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM);  /* res. */
 909         md_get_uint16le(mdp, &bc);          /* byte count */
 910         md_get_uint8(mdp, NULL);                /* buffer format */
 911         error = md_get_uint16le(mdp, &dlen);        /* data len */
 912         if (error)
 913                 goto out;
 914         if (dlen < rcnt) {
 915                 SMBSDEBUG("oops: dlen=%d rcnt=%d\n",
 916                     (int)dlen, (int)rcnt);
 917                 rcnt = dlen;
 918         }
 919         if (rcnt == 0) {
 920                 *lenp = 0;
 921                 goto out;
 922         }
 923         /* paranoid */
 924         if (rcnt > cnt) {
 925                 SMBSDEBUG("bad server! rcnt %d, cnt %d\n",
 926                     (int)rcnt, (int)cnt);
 927                 rcnt = cnt;
 928         }
 929         error = md_get_uio(mdp, uiop, (int)rcnt);
 930         if (error)
 931                 goto out;
 932 
 933         /* success */
 934         *lenp = (int)rcnt;
 935 
 936 out:
 937         smb_rq_done(rqp);
 938         return (error);
 939 }
 940 
 941 static int
 942 smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp,
 943         uio_t *uiop, smb_cred_t *scred, int timo)
 944 {
 945         struct smb_rq *rqp;
 946         struct mbchain *mbp;
 947         struct mdchain *mdp;
 948         int error;
 949         uint32_t off32;
 950         uint16_t cnt, rcnt, todo;
 951         uint8_t wc;
 952 
 953         ASSERT(uiop->uio_loffset <= UINT32_MAX);
 954         off32 = (uint32_t)uiop->uio_loffset;
 955         ASSERT(*lenp <= UINT16_MAX);
 956         cnt = (uint16_t)*lenp;
 957         /* This next is an "estimate" of planned writes. */
 958         todo = (uint16_t)min(uiop->uio_resid, UINT16_MAX);
 959 
 960         error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_WRITE, scred, &rqp);
 961         if (error)
 962                 return (error);
 963         smb_rq_getrequest(rqp, &mbp);
 964         smb_rq_wstart(rqp);
 965         mb_put_uint16le(mbp, fid);
 966         mb_put_uint16le(mbp, cnt);
 967         mb_put_uint32le(mbp, off32);
 968         mb_put_uint16le(mbp, todo);
 969         smb_rq_wend(rqp);
 970         smb_rq_bstart(rqp);
 971         mb_put_uint8(mbp, SMB_DT_DATA);
 972         mb_put_uint16le(mbp, cnt);
 973 
 974         error = mb_put_uio(mbp, uiop, *lenp);
 975         if (error)
 976                 goto out;
 977         smb_rq_bend(rqp);
 978         if (timo == 0)
 979                 timo = smb_timo_write;
 980         error = smb_rq_simple_timed(rqp, timo);
 981         if (error)
 982                 goto out;
 983         smb_rq_getreply(rqp, &mdp);
 984         error = md_get_uint8(mdp, &wc);
 985         if (error)
 986                 goto out;
 987         if (wc != 1) {
 988                 error = EBADRPC;
 989                 goto out;
 990         }
 991         error = md_get_uint16le(mdp, &rcnt);
 992         if (error)
 993                 goto out;
 994         *lenp = rcnt;
 995 
 996 out:
 997         smb_rq_done(rqp);
 998         return (error);
 999 }
1000 
1001 
1002 static u_int32_t        smbechoes = 0;
1003 
1004 int
1005 smb_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1006 {
1007         struct smb_rq *rqp;
1008         struct mbchain *mbp;
1009         int error;
1010 
1011         error = smb_rq_alloc(VCTOCP(vcp), SMB_COM_ECHO, scred, &rqp);
1012         if (error)
1013                 return (error);
1014         mbp = &rqp->sr_rq;
1015         smb_rq_wstart(rqp);
1016         mb_put_uint16le(mbp, 1); /* echo count */
1017         smb_rq_wend(rqp);
1018         smb_rq_bstart(rqp);
1019         mb_put_uint32le(mbp, atomic_inc_32_nv(&smbechoes));
1020         smb_rq_bend(rqp);
1021         /*
1022          * Note: the IOD calls this, so
1023          * this request must not wait for
1024          * connection state changes, etc.
1025          */
1026         rqp->sr_flags |= SMBR_NORECONNECT;
1027         error = smb_rq_simple_timed(rqp, timo);
1028         SMBSDEBUG("%d\n", error);
1029         smb_rq_done(rqp);
1030         return (error);
1031 }