Print this page
    
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16824 SMB client connection setup rework
NEX-17232 SMB client reconnect failures
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (improve debug)
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
          +++ new/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c
   1    1  /*
   2    2   * Copyright (c) 2000-2001 Boris Popov
   3    3   * All rights reserved.
   4    4   *
   5    5   * Redistribution and use in source and binary forms, with or without
   6    6   * modification, are permitted provided that the following conditions
   7    7   * are met:
   8    8   * 1. Redistributions of source code must retain the above copyright
   9    9   *    notice, this list of conditions and the following disclaimer.
  10   10   * 2. Redistributions in binary form must reproduce the above copyright
  11   11   *    notice, this list of conditions and the following disclaimer in the
  12   12   *    documentation and/or other materials provided with the distribution.
  13   13   * 3. All advertising materials mentioning features or use of this software
  14   14   *    must display the following acknowledgement:
  15   15   *    This product includes software developed by Boris Popov.
  16   16   * 4. Neither the name of the author nor the names of any co-contributors
  17   17   *    may be used to endorse or promote products derived from this software
  18   18   *    without specific prior written permission.
  19   19   *
  20   20   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21   21   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22   22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23   23   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24   24   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25   25   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  
    | 
      ↓ open down ↓ | 
    25 lines elided | 
    
      ↑ open up ↑ | 
  
  26   26   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27   27   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28   28   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29   29   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30   30   * SUCH DAMAGE.
  31   31   *
  32   32   * $Id: smb_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $
  33   33   */
  34   34  
  35   35  /*
  36      - * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  37   36   * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  38   37   * Use is subject to license terms.
       38 + *
       39 + * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  39   40   */
  40   41  
  41   42  #include <sys/param.h>
  42   43  #include <sys/kmem.h>
  43   44  #include <sys/systm.h>
  44   45  #include <sys/policy.h>
  45   46  #include <sys/conf.h>
  46   47  #include <sys/proc.h>
  47   48  #include <sys/fcntl.h>
  48   49  #include <sys/file.h>
  49   50  #include <sys/socket.h>
  50   51  #include <sys/sunddi.h>
  51   52  #include <sys/cmn_err.h>
  52   53  
  53   54  #include <netsmb/smb_osdep.h>
  54   55  
       56 +#include <smb/winioctl.h>
  55   57  #include <netsmb/smb.h>
  56   58  #include <netsmb/smb_conn.h>
  57   59  #include <netsmb/smb_rq.h>
  58   60  #include <netsmb/smb_subr.h>
  59   61  #include <netsmb/smb_dev.h>
  60   62  
  61   63  static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
  62   64  
  63   65  /*
  64      - * Ioctl function for SMBIOC_FLAGS2
  65      - */
  66      -int
  67      -smb_usr_get_flags2(smb_dev_t *sdp, intptr_t arg, int flags)
  68      -{
  69      -        struct smb_vc *vcp = NULL;
  70      -
  71      -        /* This ioctl requires a session. */
  72      -        if ((vcp = sdp->sd_vc) == NULL)
  73      -                return (ENOTCONN);
  74      -
  75      -        /*
  76      -         * Return the flags2 value.
  77      -         */
  78      -        if (ddi_copyout(&vcp->vc_hflags2, (void *)arg,
  79      -            sizeof (u_int16_t), flags))
  80      -                return (EFAULT);
  81      -
  82      -        return (0);
  83      -}
  84      -
  85      -/*
  86   66   * Ioctl function for SMBIOC_GETSSNKEY
  87   67   * Size copied out is SMBIOC_HASH_SZ.
  88   68   *
  89   69   * The RPC library needs this for encrypting things
  90   70   * like "set password" requests.  This is called
  91   71   * with an active RPC binding, so the connection
  92   72   * will already be active (but this checks).
  93   73   */
  94   74  int
  95   75  smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
  96   76  {
  97   77          struct smb_vc *vcp = NULL;
  
    | 
      ↓ open down ↓ | 
    2 lines elided | 
    
      ↑ open up ↑ | 
  
  98   78  
  99   79          /* This ioctl requires an active session. */
 100   80          if ((vcp = sdp->sd_vc) == NULL)
 101   81                  return (ENOTCONN);
 102   82          if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
 103   83                  return (ENOTCONN);
 104   84  
 105   85          /*
 106   86           * Return the session key.
 107   87           */
 108      -        if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,
       88 +        if (vcp->vc_ssnkey == NULL ||
       89 +            vcp->vc_ssnkeylen < SMBIOC_HASH_SZ)
       90 +                return (EINVAL);
       91 +        if (ddi_copyout(vcp->vc_ssnkey, (void *)arg,
 109   92              SMBIOC_HASH_SZ, flags))
 110   93                  return (EFAULT);
 111   94  
 112   95          return (0);
 113   96  }
 114   97  
 115   98  /*
 116      - * Ioctl function for SMBIOC_REQUEST
       99 + * Ioctl function for SMBIOC_XACTNP (transact named pipe)
 117  100   */
 118  101  int
 119      -smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
      102 +smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 120  103  {
 121  104          struct smb_cred scred;
 122  105          struct smb_share *ssp;
 123      -        smbioc_rq_t *ioc = NULL;
 124      -        struct smb_rq *rqp = NULL;
 125      -        struct mbchain *mbp;
 126      -        struct mdchain *mdp;
 127      -        uint32_t rsz;
      106 +        struct smb_fh *fhp;
      107 +        smbioc_xnp_t *ioc = NULL;
      108 +        struct mbchain send_mb;
      109 +        struct mdchain recv_md;
      110 +        uint32_t rdlen;
 128  111          int err, mbseg;
 129  112  
 130      -        /* This ioctl requires a share. */
 131      -        if ((ssp = sdp->sd_share) == NULL)
 132      -                return (ENOTCONN);
      113 +        /* This ioctl requires a file handle. */
      114 +        if ((fhp = sdp->sd_fh) == NULL)
      115 +                return (EINVAL);
      116 +        ssp = FHTOSS(fhp);
 133  117  
 134      -        smb_credinit(&scred, cr);
      118 +        /* After reconnect, force close+reopen */
      119 +        if (fhp->fh_vcgenid != ssp->ss_vcgenid)
      120 +                return (ESTALE);
      121 +
      122 +        bzero(&send_mb, sizeof (send_mb));
      123 +        bzero(&recv_md, sizeof (recv_md));
      124 +
 135  125          ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 136  126          if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 137  127                  err = EFAULT;
 138  128                  goto out;
 139  129          }
 140  130  
 141      -        /* See ddi_copyin, ddi_copyout */
 142      -        mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
 143      -
 144  131          /*
 145      -         * Lots of SMB commands could be safe, but
 146      -         * these are the only ones used by libsmbfs.
      132 +         * Copyin the send data, into an mbchain,
      133 +         * save output buffer size.
 147  134           */
 148      -        switch (ioc->ioc_cmd) {
 149      -                /* These are OK */
 150      -        case SMB_COM_CLOSE:
 151      -        case SMB_COM_FLUSH:
 152      -        case SMB_COM_NT_CREATE_ANDX:
 153      -        case SMB_COM_OPEN_PRINT_FILE:
 154      -        case SMB_COM_CLOSE_PRINT_FILE:
 155      -                break;
 156      -
 157      -        default:
 158      -                err = EPERM;
 159      -                goto out;
 160      -        }
 161      -
 162      -        err = smb_rq_alloc(SSTOCP(ssp), ioc->ioc_cmd, &scred, &rqp);
      135 +        mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
      136 +        err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);
 163  137          if (err)
 164  138                  goto out;
      139 +        rdlen = ioc->ioc_rdlen;
 165  140  
 166      -        mbp = &rqp->sr_rq;
 167      -        err = mb_put_mem(mbp, ioc->ioc_tbuf, ioc->ioc_tbufsz, mbseg);
 168      -
 169      -        err = smb_rq_simple(rqp);
 170      -        if (err == 0) {
 171      -                /*
 172      -                 * This may have been an open, so save the
 173      -                 * generation ID of the share, which we
 174      -                 * check before trying read or write.
 175      -                 */
 176      -                sdp->sd_vcgenid = ssp->ss_vcgenid;
 177      -
 178      -                /*
 179      -                 * Have reply data. to copyout.
 180      -                 * SMB header already parsed.
 181      -                 */
 182      -                mdp = &rqp->sr_rp;
 183      -                rsz = msgdsize(mdp->md_top) - SMB_HDRLEN;
 184      -                if (ioc->ioc_rbufsz < rsz) {
 185      -                        err = EOVERFLOW;
 186      -                        goto out;
 187      -                }
 188      -                ioc->ioc_rbufsz = rsz;
 189      -                err = md_get_mem(mdp, ioc->ioc_rbuf, rsz, mbseg);
 190      -                if (err)
 191      -                        goto out;
 192      -
 193      -        }
 194      -
 195      -        ioc->ioc_errclass = rqp->sr_errclass;
 196      -        ioc->ioc_serror = rqp->sr_serror;
 197      -        ioc->ioc_error = rqp->sr_error;
 198      -        (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
 199      -
 200      -out:
 201      -        if (rqp != NULL)
 202      -                smb_rq_done(rqp); /* free rqp */
 203      -        kmem_free(ioc, sizeof (*ioc));
 204      -        smb_credrele(&scred);
 205      -
 206      -        return (err);
 207      -
 208      -}
 209      -
 210      -/*
 211      - * Ioctl function for SMBIOC_T2RQ
 212      - */
 213      -int
 214      -smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 215      -{
 216      -        struct smb_cred scred;
 217      -        struct smb_share *ssp;
 218      -        smbioc_t2rq_t *ioc = NULL;
 219      -        struct smb_t2rq *t2p = NULL;
 220      -        struct mdchain *mdp;
 221      -        int err, len, mbseg;
 222      -
 223      -        /* This ioctl requires a share. */
 224      -        if ((ssp = sdp->sd_share) == NULL)
 225      -                return (ENOTCONN);
 226      -
 227      -        smb_credinit(&scred, cr);
 228      -        ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 229      -        if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 230      -                err = EFAULT;
 231      -                goto out;
 232      -        }
 233      -
 234      -        /* See ddi_copyin, ddi_copyout */
 235      -        mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
 236      -
 237      -        if (ioc->ioc_setupcnt > SMBIOC_T2RQ_MAXSETUP) {
 238      -                err = EINVAL;
 239      -                goto out;
 240      -        }
 241      -
 242  141          /*
 243      -         * Fill in the FID for libsmbfs transact named pipe.
      142 +         * Run the SMB2 ioctl or SMB1 trans2
 244  143           */
 245      -        if (ioc->ioc_setupcnt > 1 && ioc->ioc_setup[1] == 0xFFFF) {
 246      -                if (sdp->sd_vcgenid != ssp->ss_vcgenid) {
 247      -                        err = ESTALE;
 248      -                        goto out;
 249      -                }
 250      -                ioc->ioc_setup[1] = (uint16_t)sdp->sd_smbfid;
      144 +        smb_credinit(&scred, cr);
      145 +        if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
      146 +                err = smb2_smb_ioctl(ssp, &fhp->fh_fid2,
      147 +                    &send_mb, &recv_md, &rdlen,
      148 +                    FSCTL_PIPE_TRANSCEIVE, &scred);
      149 +        } else {
      150 +                err = smb_t2_xnp(ssp, fhp->fh_fid1,
      151 +                    &send_mb, &recv_md, &rdlen,
      152 +                    &ioc->ioc_more, &scred);
 251  153          }
      154 +        smb_credrele(&scred);
 252  155  
 253      -        t2p = kmem_alloc(sizeof (*t2p), KM_SLEEP);
 254      -        err = smb_t2_init(t2p, SSTOCP(ssp),
 255      -            ioc->ioc_setup, ioc->ioc_setupcnt, &scred);
 256      -        if (err)
 257      -                goto out;
 258      -        t2p->t2_setupcount = ioc->ioc_setupcnt;
 259      -        t2p->t2_setupdata  = ioc->ioc_setup;
 260      -
 261      -        /* This ioc member is a fixed-size array. */
 262      -        if (ioc->ioc_name[0]) {
 263      -                /* Get the name length - carefully! */
 264      -                ioc->ioc_name[SMBIOC_T2RQ_MAXNAME-1] = '\0';
 265      -                t2p->t_name_len = strlen(ioc->ioc_name);
 266      -                t2p->t_name = ioc->ioc_name;
 267      -        }
 268      -        t2p->t2_maxscount = 0;
 269      -        t2p->t2_maxpcount = ioc->ioc_rparamcnt;
 270      -        t2p->t2_maxdcount = ioc->ioc_rdatacnt;
 271      -
 272      -        /* Transmit parameters */
 273      -        err = smb_cpdatain(&t2p->t2_tparam,
 274      -            ioc->ioc_tparamcnt, ioc->ioc_tparam, mbseg);
 275      -        if (err)
 276      -                goto out;
 277      -
 278      -        /* Transmit data */
 279      -        err = smb_cpdatain(&t2p->t2_tdata,
 280      -            ioc->ioc_tdatacnt, ioc->ioc_tdata, mbseg);
 281      -        if (err)
 282      -                goto out;
 283      -
 284      -        err = smb_t2_request(t2p);
 285      -
 286      -        /* Copyout returned parameters. */
 287      -        mdp = &t2p->t2_rparam;
 288      -        if (err == 0 && mdp->md_top != NULL) {
 289      -                /* User's buffer large enough? */
 290      -                len = m_fixhdr(mdp->md_top);
 291      -                if (len > ioc->ioc_rparamcnt) {
 292      -                        err = EMSGSIZE;
 293      -                        goto out;
 294      -                }
 295      -                ioc->ioc_rparamcnt = (ushort_t)len;
 296      -                err = md_get_mem(mdp, ioc->ioc_rparam, len, mbseg);
 297      -                if (err)
 298      -                        goto out;
 299      -        } else
 300      -                ioc->ioc_rparamcnt = 0;
 301      -
 302  156          /* Copyout returned data. */
 303      -        mdp = &t2p->t2_rdata;
 304      -        if (err == 0 && mdp->md_top != NULL) {
 305      -                /* User's buffer large enough? */
 306      -                len = m_fixhdr(mdp->md_top);
 307      -                if (len > ioc->ioc_rdatacnt) {
      157 +        if (err == 0 && recv_md.md_top != NULL) {
      158 +                /* User's buffer large enough for copyout? */
      159 +                size_t len = m_fixhdr(recv_md.md_top);
      160 +                if (len > ioc->ioc_rdlen) {
 308  161                          err = EMSGSIZE;
 309  162                          goto out;
 310  163                  }
 311      -                ioc->ioc_rdatacnt = (ushort_t)len;
 312      -                err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
      164 +                err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg);
 313  165                  if (err)
 314  166                          goto out;
 315  167          } else
 316      -                ioc->ioc_rdatacnt = 0;
      168 +                ioc->ioc_rdlen = 0;
 317  169  
 318      -        ioc->ioc_errclass = t2p->t2_sr_errclass;
 319      -        ioc->ioc_serror = t2p->t2_sr_serror;
 320      -        ioc->ioc_error = t2p->t2_sr_error;
 321      -        ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2;
      170 +        /* Tell caller received length */
      171 +        if (rdlen <= ioc->ioc_rdlen) {
      172 +                /* Normal case */
      173 +                ioc->ioc_rdlen = rdlen;
      174 +        } else {
      175 +                /* Buffer overlow. Leave ioc_rdlen */
      176 +                ioc->ioc_more = 1;
      177 +        }
 322  178  
 323  179          (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
 324  180  
 325      -
 326  181  out:
 327      -        if (t2p != NULL) {
 328      -                /* Note: t2p->t_name no longer allocated */
 329      -                smb_t2_done(t2p);
 330      -                kmem_free(t2p, sizeof (*t2p));
 331      -        }
 332  182          kmem_free(ioc, sizeof (*ioc));
 333      -        smb_credrele(&scred);
 334  183  
 335  184          return (err);
 336  185  }
 337  186  
 338  187  /* helper for _t2request */
 339  188  static int
 340  189  smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
 341  190  {
 342  191          int error;
 343  192  
 344  193          if (len == 0)
 345  194                  return (0);
 346  195          error = mb_init(mbp);
 347  196          if (error)
 348  197                  return (error);
 349  198          return (mb_put_mem(mbp, data, len, mbseg));
 350  199  }
  
    | 
      ↓ open down ↓ | 
    7 lines elided | 
    
      ↑ open up ↑ | 
  
 351  200  
 352  201  /*
 353  202   * Helper for nsmb_ioctl cases
 354  203   * SMBIOC_READ, SMBIOC_WRITE
 355  204   */
 356  205  int
 357  206  smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 358  207  {
 359  208          struct smb_cred scred;
 360  209          struct smb_share *ssp;
      210 +        struct smb_fh *fhp;
 361  211          smbioc_rw_t *ioc = NULL;
 362  212          struct iovec aiov[1];
 363  213          struct uio  auio;
 364      -        uint16_t fh;
 365  214          int err;
 366  215          uio_rw_t rw;
 367  216  
 368      -        /* This ioctl requires a share. */
 369      -        if ((ssp = sdp->sd_share) == NULL)
 370      -                return (ENOTCONN);
      217 +        /* This ioctl requires a file handle. */
      218 +        if ((fhp = sdp->sd_fh) == NULL)
      219 +                return (EINVAL);
      220 +        ssp = FHTOSS(fhp);
 371  221  
 372  222          /* After reconnect, force close+reopen */
 373      -        if (sdp->sd_vcgenid != ssp->ss_vcgenid)
      223 +        if (fhp->fh_vcgenid != ssp->ss_vcgenid)
 374  224                  return (ESTALE);
 375  225  
 376      -        smb_credinit(&scred, cr);
 377  226          ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 378  227          if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 379  228                  err = EFAULT;
 380  229                  goto out;
 381  230          }
 382  231  
 383  232          switch (cmd) {
 384  233          case SMBIOC_READ:
 385  234                  rw = UIO_READ;
 386  235                  break;
 387  236          case SMBIOC_WRITE:
 388  237                  rw = UIO_WRITE;
 389  238                  break;
 390  239          default:
 391  240                  err = ENODEV;
 392  241                  goto out;
 393  242          }
 394  243  
 395      -        /*
 396      -         * If caller passes -1 in ioc_fh, then
 397      -         * use the FID from SMBIOC_NTCREATE.
 398      -         */
 399      -        if (ioc->ioc_fh == -1)
 400      -                fh = (uint16_t)sdp->sd_smbfid;
 401      -        else
 402      -                fh = (uint16_t)ioc->ioc_fh;
 403      -
 404  244          aiov[0].iov_base = ioc->ioc_base;
 405  245          aiov[0].iov_len = (size_t)ioc->ioc_cnt;
 406  246  
 407  247          auio.uio_iov = aiov;
 408  248          auio.uio_iovcnt = 1;
 409  249          auio.uio_loffset = ioc->ioc_offset;
 410  250          auio.uio_segflg = (flags & FKIOCTL) ?
 411  251              UIO_SYSSPACE : UIO_USERSPACE;
 412  252          auio.uio_fmode = 0;
 413  253          auio.uio_resid = (size_t)ioc->ioc_cnt;
 414  254  
 415      -        err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);
      255 +        smb_credinit(&scred, cr);
      256 +        err = smb_rwuio(fhp, rw, &auio, &scred, 0);
      257 +        smb_credrele(&scred);
 416  258  
 417  259          /*
 418  260           * On return ioc_cnt holds the
 419  261           * number of bytes transferred.
 420  262           */
 421  263          ioc->ioc_cnt -= auio.uio_resid;
 422  264  
 423  265          (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
 424  266  
 425  267  out:
 426  268          kmem_free(ioc, sizeof (*ioc));
 427      -        smb_credrele(&scred);
 428  269  
 429  270          return (err);
 430  271  }
 431  272  
 432  273  /*
 433  274   * Helper for nsmb_ioctl case
 434  275   * SMBIOC_NTCREATE
 435  276   */
 436  277  int
 437  278  smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 438  279  {
 439  280          struct smb_cred scred;
 440  281          struct mbchain name_mb;
 441  282          struct smb_share *ssp;
      283 +        struct smb_fh *fhp = NULL;
 442  284          smbioc_ntcreate_t *ioc = NULL;
 443      -        uint16_t fid;
 444  285          int err, nmlen;
 445  286  
      287 +        mb_init(&name_mb);
      288 +
 446  289          /* This ioctl requires a share. */
 447  290          if ((ssp = sdp->sd_share) == NULL)
 448  291                  return (ENOTCONN);
 449  292  
 450      -        /* Must not be already open. */
 451      -        if (sdp->sd_smbfid != -1)
      293 +        /* Must not already have a file handle. */
      294 +        if (sdp->sd_fh != NULL)
 452  295                  return (EINVAL);
 453  296  
 454      -        mb_init(&name_mb);
 455      -        smb_credinit(&scred, cr);
 456  297          ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 457  298          if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 458  299                  err = EFAULT;
 459  300                  goto out;
 460  301          }
 461  302  
 462  303          /* Build name_mb */
 463  304          ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
 464  305          nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
 465  306          err = smb_put_dmem(&name_mb, SSTOVC(ssp),
 466  307              ioc->ioc_name, nmlen,
 467  308              SMB_CS_NONE, NULL);
 468  309          if (err != 0)
 469  310                  goto out;
 470  311  
 471      -        /* Do the OtW open, save the FID. */
      312 +        err = smb_fh_create(ssp, &fhp);
      313 +        if (err != 0)
      314 +                goto out;
      315 +
      316 +        /*
      317 +         * Do the OtW open, save the FID.
      318 +         */
      319 +        smb_credinit(&scred, cr);
 472  320          err = smb_smb_ntcreate(ssp, &name_mb,
 473  321              0,  /* create flags */
 474  322              ioc->ioc_req_acc,
 475  323              ioc->ioc_efattr,
 476  324              ioc->ioc_share_acc,
 477  325              ioc->ioc_open_disp,
 478  326              ioc->ioc_creat_opts,
 479  327              NTCREATEX_IMPERSONATION_IMPERSONATION,
 480  328              &scred,
 481      -            &fid,
      329 +            fhp,
 482  330              NULL,
 483  331              NULL);
      332 +        smb_credrele(&scred);
 484  333          if (err != 0)
 485  334                  goto out;
 486  335  
 487      -        sdp->sd_smbfid = fid;
 488      -        sdp->sd_vcgenid = ssp->ss_vcgenid;
      336 +        fhp->fh_rights = ioc->ioc_req_acc;
      337 +        smb_fh_opened(fhp);
      338 +        sdp->sd_fh = fhp;
      339 +        fhp = NULL;
 489  340  
 490  341  out:
      342 +        if (fhp != NULL)
      343 +                smb_fh_rele(fhp);
 491  344          kmem_free(ioc, sizeof (*ioc));
 492      -        smb_credrele(&scred);
 493  345          mb_done(&name_mb);
 494  346  
 495  347          return (err);
 496  348  }
 497  349  
 498  350  /*
 499  351   * Helper for nsmb_ioctl case
 500  352   * SMBIOC_PRINTJOB
 501  353   */
 502  354  int
 503  355  smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 504  356  {
      357 +        static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
 505  358          struct smb_cred scred;
      359 +        struct mbchain name_mb;
 506  360          struct smb_share *ssp;
      361 +        struct smb_fh *fhp = NULL;
 507  362          smbioc_printjob_t *ioc = NULL;
 508      -        uint16_t fid;
 509      -        int err;
      363 +        int err, cklen, nmlen;
      364 +        uint32_t access = SA_RIGHT_FILE_WRITE_DATA |
      365 +            SA_RIGHT_FILE_READ_ATTRIBUTES;
 510  366  
      367 +        mb_init(&name_mb);
      368 +
 511  369          /* This ioctl requires a share. */
 512  370          if ((ssp = sdp->sd_share) == NULL)
 513  371                  return (ENOTCONN);
 514  372  
 515  373          /* The share must be a print queue. */
 516  374          if (ssp->ss_type != STYPE_PRINTQ)
 517  375                  return (EINVAL);
 518  376  
 519      -        /* Must not be already open. */
 520      -        if (sdp->sd_smbfid != -1)
      377 +        /* Must not already have a file handle. */
      378 +        if (sdp->sd_fh != NULL)
 521  379                  return (EINVAL);
 522  380  
 523  381          smb_credinit(&scred, cr);
 524  382          ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 525  383          if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 526  384                  err = EFAULT;
 527  385                  goto out;
 528  386          }
      387 +
      388 +        /*
      389 +         * Use the print job title as the file name to open, but
      390 +         * check for invalid characters first.  See the notes in
      391 +         * libsmbfs/smb/print.c about job name sanitizing.
      392 +         */
 529  393          ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';
      394 +        nmlen = strnlen(ioc->ioc_title, SMBIOC_MAX_NAME-1);
      395 +        cklen = strcspn(ioc->ioc_title, invalid_chars);
      396 +        if (cklen < nmlen) {
      397 +                err = EINVAL;
      398 +                goto out;
      399 +        }
 530  400  
 531      -        /* Do the OtW open, save the FID. */
 532      -        err = smb_smb_open_prjob(ssp, ioc->ioc_title,
 533      -            ioc->ioc_setuplen, ioc->ioc_prmode,
 534      -            &scred, &fid);
      401 +        /* Build name_mb */
      402 +        err = smb_put_dmem(&name_mb, SSTOVC(ssp),
      403 +            ioc->ioc_title, nmlen,
      404 +            SMB_CS_NONE, NULL);
 535  405          if (err != 0)
 536  406                  goto out;
 537  407  
 538      -        sdp->sd_smbfid = fid;
 539      -        sdp->sd_vcgenid = ssp->ss_vcgenid;
      408 +        err = smb_fh_create(ssp, &fhp);
      409 +        if (err != 0)
      410 +                goto out;
 540  411  
      412 +        /*
      413 +         * Do the OtW open, save the FID.
      414 +         */
      415 +        smb_credinit(&scred, cr);
      416 +        if (SSTOVC(ssp)->vc_flags & SMBV_SMB2) {
      417 +                err = smb2_smb_ntcreate(ssp, &name_mb,
      418 +                    NULL, NULL, /* cctx in, out */
      419 +                    0,  /* create flags */
      420 +                    access,
      421 +                    SMB_EFA_NORMAL,
      422 +                    NTCREATEX_SHARE_ACCESS_NONE,
      423 +                    NTCREATEX_DISP_CREATE,
      424 +                    NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
      425 +                    NTCREATEX_IMPERSONATION_IMPERSONATION,
      426 +                    &scred,
      427 +                    &fhp->fh_fid2,
      428 +                    NULL,
      429 +                    NULL);
      430 +        } else {
      431 +                err = smb_smb_open_prjob(ssp, ioc->ioc_title,
      432 +                    ioc->ioc_setuplen, ioc->ioc_prmode,
      433 +                    &scred, &fhp->fh_fid1);
      434 +        }
      435 +        smb_credrele(&scred);
      436 +        if (err != 0)
      437 +                goto out;
      438 +
      439 +        fhp->fh_rights = access;
      440 +        smb_fh_opened(fhp);
      441 +        sdp->sd_fh = fhp;
      442 +        fhp = NULL;
      443 +
 541  444  out:
      445 +        if (fhp != NULL)
      446 +                smb_fh_rele(fhp);
 542  447          kmem_free(ioc, sizeof (*ioc));
 543      -        smb_credrele(&scred);
      448 +        mb_done(&name_mb);
 544  449  
 545  450          return (err);
 546  451  }
 547  452  
 548  453  /*
 549  454   * Helper for nsmb_ioctl case
 550  455   * SMBIOC_CLOSEFH
 551  456   */
      457 +/*ARGSUSED*/
 552  458  int
 553  459  smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
 554  460  {
 555      -        struct smb_cred scred;
 556      -        struct smb_share *ssp;
 557      -        uint16_t fid;
 558      -        int err;
      461 +        struct smb_fh *fhp;
 559  462  
 560      -        /* This ioctl requires a share. */
 561      -        if ((ssp = sdp->sd_share) == NULL)
 562      -                return (ENOTCONN);
      463 +        /* This ioctl requires a file handle. */
      464 +        if ((fhp = sdp->sd_fh) == NULL)
      465 +                return (EINVAL);
      466 +        sdp->sd_fh = NULL;
 563  467  
 564      -        if (sdp->sd_smbfid == -1)
 565      -                return (0);
 566      -        fid = (uint16_t)sdp->sd_smbfid;
 567      -        sdp->sd_smbfid = -1;
      468 +        smb_fh_close(fhp);
      469 +        smb_fh_rele(fhp);
 568  470  
 569      -        smb_credinit(&scred, cr);
 570      -        if (ssp->ss_type == STYPE_PRINTQ)
 571      -                err = smb_smb_close_prjob(ssp, fid, &scred);
 572      -        else
 573      -                err = smb_smb_close(ssp, fid, NULL, &scred);
 574      -        smb_credrele(&scred);
 575      -
 576      -        return (err);
      471 +        return (0);
 577  472  }
 578  473  
 579  474  /*
 580  475   * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
 581  476   * Find or create a session (a.k.a. "VC" in here)
 582  477   */
 583  478  int
 584  479  smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 585  480  {
 586  481          struct smb_cred scred;
 587  482          smbioc_ossn_t *ossn = NULL;
 588  483          struct smb_vc *vcp = NULL;
 589  484          int error = 0;
 590  485          uid_t realuid;
 591  486  
 592  487          /* Should be no VC */
 593  488          if (sdp->sd_vc != NULL)
 594  489                  return (EISCONN);
 595  490  
 596  491          smb_credinit(&scred, cr);
 597  492          ossn = kmem_alloc(sizeof (*ossn), KM_SLEEP);
 598  493          if (ddi_copyin((void *)arg, ossn, sizeof (*ossn), flags)) {
 599  494                  error = EFAULT;
 600  495                  goto out;
 601  496          }
 602  497  
 603  498          /*
 604  499           * Only superuser can specify a UID or GID.
 605  500           */
 606  501          realuid = crgetruid(cr);
 607  502          if (ossn->ssn_owner == SMBM_ANY_OWNER)
 608  503                  ossn->ssn_owner = realuid;
 609  504          else {
 610  505                  /*
 611  506                   * Do we have the privilege to create with the
 612  507                   * specified uid?  (does uid == cr->cr_uid, etc.)
 613  508                   */
 614  509                  if (secpolicy_vnode_owner(cr, ossn->ssn_owner)) {
 615  510                          error = EPERM;
 616  511                          goto out;
 617  512                  }
 618  513                  /* ossn->ssn_owner is OK */
 619  514          }
 620  515  
 621  516          /*
 622  517           * Make sure the strings are null terminated.
 623  518           */
 624  519          ossn->ssn_srvname[SMBIOC_MAX_NAME-1] = '\0';
 625  520          ossn->ssn_id.id_domain[ SMBIOC_MAX_NAME-1] = '\0';
 626  521          ossn->ssn_id.id_user[   SMBIOC_MAX_NAME-1] = '\0';
 627  522  
 628  523          if (cmd == SMBIOC_SSN_CREATE)
 629  524                  ossn->ssn_vopt |= SMBVOPT_CREATE;
 630  525          else /* FIND */
 631  526                  ossn->ssn_vopt &= ~SMBVOPT_CREATE;
 632  527  
 633  528          error = smb_vc_findcreate(ossn, &scred, &vcp);
 634  529          if (error)
 635  530                  goto out;
 636  531          ASSERT(vcp != NULL);
 637  532  
 638  533          /*
 639  534           * We have a VC, held, but not locked.
 640  535           * If we're creating, mark this instance as
 641  536           * an open from IOD so close can do cleanup.
 642  537           *
 643  538           * XXX: Would be nice to have a back pointer
 644  539           * from the VC to this (IOD) sdp instance.
 645  540           */
 646  541          if (cmd == SMBIOC_SSN_CREATE) {
 647  542                  if (vcp->iod_thr != NULL) {
 648  543                          error = EEXIST;
 649  544                          goto out;
 650  545                  }
 651  546                  sdp->sd_flags |= NSMBFL_IOD;
 652  547          } else {
 653  548                  /*
 654  549                   * Wait for it to finish connecting
 655  550                   * (or reconnect) if necessary.
 656  551                   */
 657  552                  if (vcp->vc_state != SMBIOD_ST_VCACTIVE) {
 658  553                          error = smb_iod_reconnect(vcp);
 659  554                          if (error != 0)
 660  555                                  goto out;
 661  556                  }
 662  557          }
 663  558  
 664  559          /*
 665  560           * The VC has a hold from _findvc
 666  561           * which we keep until _SSN_RELE
 667  562           * or nsmb_close().
 668  563           */
 669  564          sdp->sd_level = SMBL_VC;
 670  565          sdp->sd_vc = vcp;
 671  566          vcp = NULL;
 672  567          (void) ddi_copyout(ossn, (void *)arg, sizeof (*ossn), flags);
 673  568  
 674  569  out:
 675  570          if (vcp) {
 676  571                  /* Error path: rele hold from _findcreate */
 677  572                  smb_vc_rele(vcp);
 678  573          }
 679  574          kmem_free(ossn, sizeof (*ossn));
 680  575          smb_credrele(&scred);
 681  576  
 682  577          return (error);
 683  578  }
 684  579  
 685  580  /*
 686  581   * Ioctl functions: SMBIOC_SSN_RELE, SMBIOC_SSN_KILL
 687  582   * Release or kill the current session.
 688  583   */
 689  584  int
 690  585  smb_usr_drop_ssn(smb_dev_t *sdp, int cmd)
 691  586  {
 692  587          struct smb_vc *vcp = NULL;
 693  588  
 694  589          /* Must have a VC. */
 695  590          if ((vcp = sdp->sd_vc) == NULL)
 696  591                  return (ENOTCONN);
 697  592  
 698  593          /* If we have a share ref, drop it too. */
 699  594          if (sdp->sd_share) {
 700  595                  smb_share_rele(sdp->sd_share);
 701  596                  sdp->sd_share = NULL;
 702  597                  sdp->sd_level = SMBL_VC;
 703  598          }
 704  599  
 705  600          if (cmd == SMBIOC_SSN_KILL)
 706  601                  smb_vc_kill(vcp);
 707  602  
 708  603          /* Drop the VC ref. */
 709  604          smb_vc_rele(vcp);
 710  605          sdp->sd_vc = NULL;
 711  606          sdp->sd_level = 0;
 712  607  
 713  608          return (0);
 714  609  }
 715  610  
 716  611  /*
 717  612   * Find or create a tree (connected share)
 718  613   */
 719  614  int
 720  615  smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 721  616  {
 722  617          struct smb_cred scred;
 723  618          smbioc_tcon_t *tcon = NULL;
 724  619          struct smb_vc *vcp = NULL;
 725  620          struct smb_share *ssp = NULL;
 726  621          int error = 0;
 727  622  
 728  623          /* Must have a VC. */
 729  624          if ((vcp = sdp->sd_vc) == NULL)
 730  625                  return (ENOTCONN);
 731  626          /* Should not have a share. */
 732  627          if (sdp->sd_share != NULL)
 733  628                  return (EISCONN);
 734  629  
 735  630          smb_credinit(&scred, cr);
 736  631          tcon = kmem_alloc(sizeof (*tcon), KM_SLEEP);
 737  632          if (ddi_copyin((void *)arg, tcon, sizeof (*tcon), flags)) {
 738  633                  error = EFAULT;
 739  634                  goto out;
 740  635          }
 741  636  
 742  637          /*
 743  638           * Make sure the strings are null terminated.
 744  639           */
 745  640          tcon->tc_sh.sh_name[SMBIOC_MAX_NAME-1] = '\0';
 746  641          tcon->tc_sh.sh_pass[SMBIOC_MAX_NAME-1] = '\0';
 747  642  
 748  643          if (cmd == SMBIOC_TREE_CONNECT)
 749  644                  tcon->tc_opt |= SMBSOPT_CREATE;
 750  645          else /* FIND */
 751  646                  tcon->tc_opt &= ~SMBSOPT_CREATE;
 752  647  
 753  648          error = smb_share_findcreate(tcon, vcp, &ssp, &scred);
 754  649          if (error)
 755  650                  goto out;
 756  651          ASSERT(ssp != NULL);
 757  652  
 758  653          /*
 759  654           * We have a share, held, but not locked.
 760  655           * If we're creating, do tree connect now,
 761  656           * otherwise let that wait for a request.
 762  657           */
 763  658          if (cmd == SMBIOC_TREE_CONNECT) {
 764  659                  error = smb_share_tcon(ssp, &scred);
 765  660                  if (error)
 766  661                          goto out;
 767  662          }
 768  663  
 769  664          /*
 770  665           * Give caller the real share type from
 771  666           * the tree connect response, so they can
 772  667           * see if they got the requested type.
 773  668           */
 774  669          tcon->tc_sh.sh_type = ssp->ss_type;
 775  670  
 776  671          /*
 777  672           * The share has a hold from _tcon
 778  673           * which we keep until nsmb_close()
 779  674           * or the SMBIOC_TDIS below.
 780  675           */
 781  676          sdp->sd_level = SMBL_SHARE;
 782  677          sdp->sd_share = ssp;
 783  678          ssp = NULL;
 784  679          (void) ddi_copyout(tcon, (void *)arg, sizeof (*tcon), flags);
 785  680  
 786  681  out:
 787  682          if (ssp) {
 788  683                  /* Error path: rele hold from _findcreate */
 789  684                  smb_share_rele(ssp);
 790  685          }
 791  686          /*
 792  687           * This structure may contain a
 793  688           * cleartext password, so zap it.
 794  689           */
 795  690          bzero(tcon, sizeof (*tcon));
 796  691          kmem_free(tcon, sizeof (*tcon));
 797  692          smb_credrele(&scred);
 798  693  
 799  694          return (error);
 800  695  }
 801  696  
 802  697  /*
 803  698   * Ioctl functions: SMBIOC_TREE_RELE, SMBIOC_TREE_KILL
 804  699   * Release or kill the current tree
 805  700   */
 806  701  int
 807  702  smb_usr_drop_tree(smb_dev_t *sdp, int cmd)
 808  703  {
 809  704          struct smb_share *ssp = NULL;
 810  705  
 811  706          /* Must have a VC and a share. */
 812  707          if (sdp->sd_vc == NULL)
 813  708                  return (ENOTCONN);
 814  709          if ((ssp = sdp->sd_share) == NULL)
 815  710                  return (ENOTCONN);
 816  711  
 817  712          if (cmd == SMBIOC_TREE_KILL)
  
    | 
      ↓ open down ↓ | 
    231 lines elided | 
    
      ↑ open up ↑ | 
  
 818  713                  smb_share_kill(ssp);
 819  714  
 820  715          /* Drop the share ref. */
 821  716          smb_share_rele(sdp->sd_share);
 822  717          sdp->sd_share = NULL;
 823  718          sdp->sd_level = SMBL_VC;
 824  719  
 825  720          return (0);
 826  721  }
 827  722  
 828      -
 829  723  /*
 830      - * Ioctl function: SMBIOC_IOD_WORK
 831      - *
 832      - * Become the reader (IOD) thread, until either the connection is
 833      - * reset by the server, or until the connection is idle longer than
 834      - * some max time. (max idle time not yet implemented)
      724 + * Ioctl handler for all SMBIOC_IOD_...
 835  725   */
 836  726  int
 837      -smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
      727 +smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 838  728  {
 839      -        struct smb_vc *vcp = NULL;
      729 +        struct smb_vc *vcp;
 840  730          int err = 0;
 841  731  
 842      -        /* Must have a valid session. */
      732 +        /* Must be the IOD. */
      733 +        if ((sdp->sd_flags & NSMBFL_IOD) == 0)
      734 +                return (EINVAL);
      735 +        /* Must have a VC and no share. */
 843  736          if ((vcp = sdp->sd_vc) == NULL)
 844  737                  return (EINVAL);
 845      -        if (vcp->vc_flags & SMBV_GONE)
      738 +        if (sdp->sd_share != NULL)
 846  739                  return (EINVAL);
 847  740  
 848  741          /*
 849  742           * Is there already an IOD for this VC?
 850  743           * (Should never happen.)
 851  744           */
 852  745          SMB_VC_LOCK(vcp);
 853  746          if (vcp->iod_thr == NULL)
 854  747                  vcp->iod_thr = curthread;
 855  748          else
 856  749                  err = EEXIST;
 857  750          SMB_VC_UNLOCK(vcp);
 858  751          if (err)
 859  752                  return (err);
 860  753  
 861  754          /*
 862      -         * Copy the "work" state, etc. into the VC
 863      -         * The MAC key is copied separately.
      755 +         * Copy the "work" state, etc. into the VC,
      756 +         * and back to the caller on the way out.
      757 +         * Clear the "out only" part.
 864  758           */
 865  759          if (ddi_copyin((void *)arg, &vcp->vc_work,
 866  760              sizeof (smbioc_ssn_work_t), flags)) {
 867  761                  err = EFAULT;
 868  762                  goto out;
 869  763          }
 870      -        if (vcp->vc_u_maclen) {
 871      -                vcp->vc_mackeylen = vcp->vc_u_maclen;
 872      -                vcp->vc_mackey = kmem_alloc(vcp->vc_mackeylen, KM_SLEEP);
 873      -                if (ddi_copyin(vcp->vc_u_mackey.lp_ptr, vcp->vc_mackey,
 874      -                    vcp->vc_mackeylen, flags)) {
 875      -                        err = EFAULT;
 876      -                        goto out;
 877      -                }
 878      -        }
      764 +        vcp->vc_work.wk_out_state = 0;
 879  765  
 880      -        err = smb_iod_vc_work(vcp, cr);
      766 +        switch (cmd) {
 881  767  
 882      -        /* Caller wants state here. */
 883      -        vcp->vc_work.wk_out_state = vcp->vc_state;
      768 +        case SMBIOC_IOD_CONNECT:
      769 +                err = nsmb_iod_connect(vcp, cr);
      770 +                break;
 884  771  
 885      -        (void) ddi_copyout(&vcp->vc_work, (void *)arg,
 886      -            sizeof (smbioc_ssn_work_t), flags);
      772 +        case SMBIOC_IOD_NEGOTIATE:
      773 +                err = nsmb_iod_negotiate(vcp, cr);
      774 +                break;
 887  775  
 888      -out:
 889      -        if (vcp->vc_mackey) {
 890      -                kmem_free(vcp->vc_mackey, vcp->vc_mackeylen);
 891      -                vcp->vc_mackey = NULL;
 892      -                vcp->vc_mackeylen = 0;
      776 +        case SMBIOC_IOD_SSNSETUP:
      777 +                err = nsmb_iod_ssnsetup(vcp, cr);
      778 +                break;
      779 +
      780 +        case SMBIOC_IOD_WORK:
      781 +                err = smb_iod_vc_work(vcp, flags, cr);
      782 +                break;
      783 +
      784 +        case SMBIOC_IOD_IDLE:
      785 +                err = smb_iod_vc_idle(vcp);
      786 +                break;
      787 +
      788 +        case SMBIOC_IOD_RCFAIL:
      789 +                err = smb_iod_vc_rcfail(vcp);
      790 +                break;
      791 +
      792 +        default:
      793 +                err = ENOTTY;
      794 +                break;
 893  795          }
 894  796  
      797 +out:
      798 +        vcp->vc_work.wk_out_state = vcp->vc_state;
      799 +        (void) ddi_copyout(&vcp->vc_work, (void *)arg,
      800 +            sizeof (smbioc_ssn_work_t), flags);
      801 +
 895  802          /*
 896  803           * The IOD thread is leaving the driver.  Clear iod_thr,
 897  804           * and wake up anybody waiting for us to quit.
 898  805           */
 899  806          SMB_VC_LOCK(vcp);
 900  807          vcp->iod_thr = NULL;
 901  808          cv_broadcast(&vcp->vc_statechg);
 902  809          SMB_VC_UNLOCK(vcp);
 903  810  
 904  811          return (err);
 905  812  }
 906  813  
 907      -/*
 908      - * Ioctl functions: SMBIOC_IOD_IDLE, SMBIOC_IOD_RCFAIL
 909      - *
 910      - * Wait for user-level requests to be enqueued on this session,
 911      - * and then return to the user-space helper, which will then
 912      - * initiate a reconnect, etc.
 913      - */
 914  814  int
 915      -smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
      815 +smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 916  816  {
 917      -        struct smb_vc *vcp = NULL;
 918      -        int err = 0;
      817 +        int err;
 919  818  
 920      -        /* Must have a valid session. */
 921      -        if ((vcp = sdp->sd_vc) == NULL)
 922      -                return (EINVAL);
 923      -        if (vcp->vc_flags & SMBV_GONE)
 924      -                return (EINVAL);
 925      -
 926  819          /*
 927      -         * Is there already an IOD for this VC?
 928      -         * (Should never happen.)
      820 +         * Serialize ioctl calls.  The smb_usr_... functions
      821 +         * don't expect concurrent calls on a given sdp.
 929  822           */
 930      -        SMB_VC_LOCK(vcp);
 931      -        if (vcp->iod_thr == NULL)
 932      -                vcp->iod_thr = curthread;
 933      -        else
 934      -                err = EEXIST;
 935      -        SMB_VC_UNLOCK(vcp);
 936      -        if (err)
 937      -                return (err);
      823 +        mutex_enter(&sdp->sd_lock);
      824 +        if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
      825 +                mutex_exit(&sdp->sd_lock);
      826 +                return (EBUSY);
      827 +        }
      828 +        sdp->sd_flags |= NSMBFL_IOCTL;
      829 +        mutex_exit(&sdp->sd_lock);
 938  830  
 939      -        /* nothing to copyin */
 940      -
      831 +        err = 0;
 941  832          switch (cmd) {
 942      -        case SMBIOC_IOD_IDLE:
 943      -                err = smb_iod_vc_idle(vcp);
      833 +        case SMBIOC_GETVERS:
      834 +                (void) ddi_copyout(&nsmb_version, (void *)arg,
      835 +                    sizeof (nsmb_version), flags);
 944  836                  break;
 945  837  
      838 +        case SMBIOC_GETSSNKEY:
      839 +                err = smb_usr_get_ssnkey(sdp, arg, flags);
      840 +                break;
      841 +
      842 +        case SMBIOC_DUP_DEV:
      843 +                err = smb_usr_dup_dev(sdp, arg, flags);
      844 +                break;
      845 +
      846 +        case SMBIOC_XACTNP:
      847 +                err = smb_usr_xnp(sdp, arg, flags, cr);
      848 +                break;
      849 +
      850 +        case SMBIOC_READ:
      851 +        case SMBIOC_WRITE:
      852 +                err = smb_usr_rw(sdp, cmd, arg, flags, cr);
      853 +                break;
      854 +
      855 +        case SMBIOC_NTCREATE:
      856 +                err = smb_usr_ntcreate(sdp, arg, flags, cr);
      857 +                break;
      858 +
      859 +        case SMBIOC_PRINTJOB:
      860 +                err = smb_usr_printjob(sdp, arg, flags, cr);
      861 +                break;
      862 +
      863 +        case SMBIOC_CLOSEFH:
      864 +                err = smb_usr_closefh(sdp, cr);
      865 +                break;
      866 +
      867 +        case SMBIOC_SSN_CREATE:
      868 +        case SMBIOC_SSN_FIND:
      869 +                err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
      870 +                break;
      871 +
      872 +        case SMBIOC_SSN_KILL:
      873 +        case SMBIOC_SSN_RELE:
      874 +                err = smb_usr_drop_ssn(sdp, cmd);
      875 +                break;
      876 +
      877 +        case SMBIOC_TREE_CONNECT:
      878 +        case SMBIOC_TREE_FIND:
      879 +                err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
      880 +                break;
      881 +
      882 +        case SMBIOC_TREE_KILL:
      883 +        case SMBIOC_TREE_RELE:
      884 +                err = smb_usr_drop_tree(sdp, cmd);
      885 +                break;
      886 +
      887 +        case SMBIOC_IOD_CONNECT:
      888 +        case SMBIOC_IOD_NEGOTIATE:
      889 +        case SMBIOC_IOD_SSNSETUP:
      890 +        case SMBIOC_IOD_WORK:
      891 +        case SMBIOC_IOD_IDLE:
 946  892          case SMBIOC_IOD_RCFAIL:
 947      -                err = smb_iod_vc_rcfail(vcp);
      893 +                err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
 948  894                  break;
 949  895  
      896 +        case SMBIOC_PK_ADD:
      897 +        case SMBIOC_PK_DEL:
      898 +        case SMBIOC_PK_CHK:
      899 +        case SMBIOC_PK_DEL_OWNER:
      900 +        case SMBIOC_PK_DEL_EVERYONE:
      901 +                err = smb_pkey_ioctl(cmd, arg, flags, cr);
      902 +                break;
      903 +
 950  904          default:
 951  905                  err = ENOTTY;
 952      -                goto out;
      906 +                break;
 953  907          }
 954  908  
 955      -        /* Both of these ioctls copy out the new state. */
 956      -        (void) ddi_copyout(&vcp->vc_state, (void *)arg,
 957      -            sizeof (int), flags);
      909 +        mutex_enter(&sdp->sd_lock);
      910 +        sdp->sd_flags &= ~NSMBFL_IOCTL;
      911 +        mutex_exit(&sdp->sd_lock);
 958  912  
 959      -out:
 960      -        /*
 961      -         * The IOD thread is leaving the driver.  Clear iod_thr,
 962      -         * and wake up anybody waiting for us to quit.
 963      -         */
 964      -        SMB_VC_LOCK(vcp);
 965      -        vcp->iod_thr = NULL;
 966      -        cv_broadcast(&vcp->vc_statechg);
 967      -        SMB_VC_UNLOCK(vcp);
 968      -
 969  913          return (err);
 970  914  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX