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)


  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_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $
  33  */
  34 
  35 /*
  36  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  37  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  38  * Use is subject to license terms.


  39  */
  40 
  41 #include <sys/param.h>
  42 #include <sys/kmem.h>
  43 #include <sys/systm.h>
  44 #include <sys/policy.h>
  45 #include <sys/conf.h>
  46 #include <sys/proc.h>
  47 #include <sys/fcntl.h>
  48 #include <sys/file.h>
  49 #include <sys/socket.h>
  50 #include <sys/sunddi.h>
  51 #include <sys/cmn_err.h>
  52 
  53 #include <netsmb/smb_osdep.h>
  54 

  55 #include <netsmb/smb.h>
  56 #include <netsmb/smb_conn.h>
  57 #include <netsmb/smb_rq.h>
  58 #include <netsmb/smb_subr.h>
  59 #include <netsmb/smb_dev.h>
  60 
  61 static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
  62 
  63 /*
  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  * Ioctl function for SMBIOC_GETSSNKEY
  87  * Size copied out is SMBIOC_HASH_SZ.
  88  *
  89  * The RPC library needs this for encrypting things
  90  * like "set password" requests.  This is called
  91  * with an active RPC binding, so the connection
  92  * will already be active (but this checks).
  93  */
  94 int
  95 smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
  96 {
  97         struct smb_vc *vcp = NULL;
  98 
  99         /* This ioctl requires an active session. */
 100         if ((vcp = sdp->sd_vc) == NULL)
 101                 return (ENOTCONN);
 102         if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
 103                 return (ENOTCONN);
 104 
 105         /*
 106          * Return the session key.
 107          */
 108         if (ddi_copyout(vcp->vc_ssn_key, (void *)arg,



 109             SMBIOC_HASH_SZ, flags))
 110                 return (EFAULT);
 111 
 112         return (0);
 113 }
 114 
 115 /*
 116  * Ioctl function for SMBIOC_REQUEST
 117  */
 118 int
 119 smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 120 {
 121         struct smb_cred scred;
 122         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;
 128         int err, mbseg;
 129 
 130         /* This ioctl requires a share. */
 131         if ((ssp = sdp->sd_share) == NULL)
 132                 return (ENOTCONN);

 133 
 134         smb_credinit(&scred, cr);






 135         ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 136         if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 137                 err = EFAULT;
 138                 goto out;
 139         }
 140 
 141         /* See ddi_copyin, ddi_copyout */
 142         mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
 143 
 144         /*
 145          * Lots of SMB commands could be safe, but
 146          * these are the only ones used by libsmbfs.
 147          */
 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);
 163         if (err)
 164                 goto out;

 165 
 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         /*
 243          * Fill in the FID for libsmbfs transact named pipe.
 244          */
 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;
 251         }
 252 
 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         /* 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) {
 308                         err = EMSGSIZE;
 309                         goto out;
 310                 }
 311                 ioc->ioc_rdatacnt = (ushort_t)len;
 312                 err = md_get_mem(mdp, ioc->ioc_rdata, len, mbseg);
 313                 if (err)
 314                         goto out;
 315         } else
 316                 ioc->ioc_rdatacnt = 0;
 317 
 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;
 322 
 323         (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
 324 
 325 
 326 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         kmem_free(ioc, sizeof (*ioc));
 333         smb_credrele(&scred);
 334 
 335         return (err);
 336 }
 337 
 338 /* helper for _t2request */
 339 static int
 340 smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
 341 {
 342         int error;
 343 
 344         if (len == 0)
 345                 return (0);
 346         error = mb_init(mbp);
 347         if (error)
 348                 return (error);
 349         return (mb_put_mem(mbp, data, len, mbseg));
 350 }
 351 
 352 /*
 353  * Helper for nsmb_ioctl cases
 354  * SMBIOC_READ, SMBIOC_WRITE
 355  */
 356 int
 357 smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 358 {
 359         struct smb_cred scred;
 360         struct smb_share *ssp;

 361         smbioc_rw_t *ioc = NULL;
 362         struct iovec aiov[1];
 363         struct uio  auio;
 364         uint16_t fh;
 365         int err;
 366         uio_rw_t rw;
 367 
 368         /* This ioctl requires a share. */
 369         if ((ssp = sdp->sd_share) == NULL)
 370                 return (ENOTCONN);

 371 
 372         /* After reconnect, force close+reopen */
 373         if (sdp->sd_vcgenid != ssp->ss_vcgenid)
 374                 return (ESTALE);
 375 
 376         smb_credinit(&scred, cr);
 377         ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 378         if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 379                 err = EFAULT;
 380                 goto out;
 381         }
 382 
 383         switch (cmd) {
 384         case SMBIOC_READ:
 385                 rw = UIO_READ;
 386                 break;
 387         case SMBIOC_WRITE:
 388                 rw = UIO_WRITE;
 389                 break;
 390         default:
 391                 err = ENODEV;
 392                 goto out;
 393         }
 394 
 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         aiov[0].iov_base = ioc->ioc_base;
 405         aiov[0].iov_len = (size_t)ioc->ioc_cnt;
 406 
 407         auio.uio_iov = aiov;
 408         auio.uio_iovcnt = 1;
 409         auio.uio_loffset = ioc->ioc_offset;
 410         auio.uio_segflg = (flags & FKIOCTL) ?
 411             UIO_SYSSPACE : UIO_USERSPACE;
 412         auio.uio_fmode = 0;
 413         auio.uio_resid = (size_t)ioc->ioc_cnt;
 414 
 415         err = smb_rwuio(ssp, fh, rw, &auio, &scred, 0);


 416 
 417         /*
 418          * On return ioc_cnt holds the
 419          * number of bytes transferred.
 420          */
 421         ioc->ioc_cnt -= auio.uio_resid;
 422 
 423         (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
 424 
 425 out:
 426         kmem_free(ioc, sizeof (*ioc));
 427         smb_credrele(&scred);
 428 
 429         return (err);
 430 }
 431 
 432 /*
 433  * Helper for nsmb_ioctl case
 434  * SMBIOC_NTCREATE
 435  */
 436 int
 437 smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 438 {
 439         struct smb_cred scred;
 440         struct mbchain name_mb;
 441         struct smb_share *ssp;

 442         smbioc_ntcreate_t *ioc = NULL;
 443         uint16_t fid;
 444         int err, nmlen;
 445 


 446         /* This ioctl requires a share. */
 447         if ((ssp = sdp->sd_share) == NULL)
 448                 return (ENOTCONN);
 449 
 450         /* Must not be already open. */
 451         if (sdp->sd_smbfid != -1)
 452                 return (EINVAL);
 453 
 454         mb_init(&name_mb);
 455         smb_credinit(&scred, cr);
 456         ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 457         if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 458                 err = EFAULT;
 459                 goto out;
 460         }
 461 
 462         /* Build name_mb */
 463         ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
 464         nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
 465         err = smb_put_dmem(&name_mb, SSTOVC(ssp),
 466             ioc->ioc_name, nmlen,
 467             SMB_CS_NONE, NULL);
 468         if (err != 0)
 469                 goto out;
 470 
 471         /* Do the OtW open, save the FID. */







 472         err = smb_smb_ntcreate(ssp, &name_mb,
 473             0,  /* create flags */
 474             ioc->ioc_req_acc,
 475             ioc->ioc_efattr,
 476             ioc->ioc_share_acc,
 477             ioc->ioc_open_disp,
 478             ioc->ioc_creat_opts,
 479             NTCREATEX_IMPERSONATION_IMPERSONATION,
 480             &scred,
 481             &fid,
 482             NULL,
 483             NULL);

 484         if (err != 0)
 485                 goto out;
 486 
 487         sdp->sd_smbfid = fid;
 488         sdp->sd_vcgenid = ssp->ss_vcgenid;


 489 
 490 out:


 491         kmem_free(ioc, sizeof (*ioc));
 492         smb_credrele(&scred);
 493         mb_done(&name_mb);
 494 
 495         return (err);
 496 }
 497 
 498 /*
 499  * Helper for nsmb_ioctl case
 500  * SMBIOC_PRINTJOB
 501  */
 502 int
 503 smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 504 {

 505         struct smb_cred scred;

 506         struct smb_share *ssp;

 507         smbioc_printjob_t *ioc = NULL;
 508         uint16_t fid;
 509         int err;

 510 


 511         /* This ioctl requires a share. */
 512         if ((ssp = sdp->sd_share) == NULL)
 513                 return (ENOTCONN);
 514 
 515         /* The share must be a print queue. */
 516         if (ssp->ss_type != STYPE_PRINTQ)
 517                 return (EINVAL);
 518 
 519         /* Must not be already open. */
 520         if (sdp->sd_smbfid != -1)
 521                 return (EINVAL);
 522 
 523         smb_credinit(&scred, cr);
 524         ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 525         if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 526                 err = EFAULT;
 527                 goto out;
 528         }






 529         ioc->ioc_title[SMBIOC_MAX_NAME-1] = '\0';






 530 
 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);


 535         if (err != 0)
 536                 goto out;
 537 
 538         sdp->sd_smbfid = fid;
 539         sdp->sd_vcgenid = ssp->ss_vcgenid;


 540 
 541 out:


 542         kmem_free(ioc, sizeof (*ioc));
 543         smb_credrele(&scred);
 544 
 545         return (err);
 546 }
 547 
 548 /*
 549  * Helper for nsmb_ioctl case
 550  * SMBIOC_CLOSEFH
 551  */

 552 int
 553 smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
 554 {
 555         struct smb_cred scred;
 556         struct smb_share *ssp;
 557         uint16_t fid;
 558         int err;
 559 
 560         /* This ioctl requires a share. */
 561         if ((ssp = sdp->sd_share) == NULL)
 562                 return (ENOTCONN);

 563 
 564         if (sdp->sd_smbfid == -1)
 565                 return (0);
 566         fid = (uint16_t)sdp->sd_smbfid;
 567         sdp->sd_smbfid = -1;
 568 
 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);
 577 }
 578 
 579 /*
 580  * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
 581  * Find or create a session (a.k.a. "VC" in here)
 582  */
 583 int
 584 smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 585 {
 586         struct smb_cred scred;
 587         smbioc_ossn_t *ossn = NULL;
 588         struct smb_vc *vcp = NULL;
 589         int error = 0;
 590         uid_t realuid;
 591 
 592         /* Should be no VC */
 593         if (sdp->sd_vc != NULL)
 594                 return (EISCONN);
 595 
 596         smb_credinit(&scred, cr);


 808 {
 809         struct smb_share *ssp = NULL;
 810 
 811         /* Must have a VC and a share. */
 812         if (sdp->sd_vc == NULL)
 813                 return (ENOTCONN);
 814         if ((ssp = sdp->sd_share) == NULL)
 815                 return (ENOTCONN);
 816 
 817         if (cmd == SMBIOC_TREE_KILL)
 818                 smb_share_kill(ssp);
 819 
 820         /* Drop the share ref. */
 821         smb_share_rele(sdp->sd_share);
 822         sdp->sd_share = NULL;
 823         sdp->sd_level = SMBL_VC;
 824 
 825         return (0);
 826 }
 827 
 828 
 829 /*
 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)
 835  */
 836 int
 837 smb_usr_iod_work(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 838 {
 839         struct smb_vc *vcp = NULL;
 840         int err = 0;
 841 
 842         /* Must have a valid session. */



 843         if ((vcp = sdp->sd_vc) == NULL)
 844                 return (EINVAL);
 845         if (vcp->vc_flags & SMBV_GONE)
 846                 return (EINVAL);
 847 
 848         /*
 849          * Is there already an IOD for this VC?
 850          * (Should never happen.)
 851          */
 852         SMB_VC_LOCK(vcp);
 853         if (vcp->iod_thr == NULL)
 854                 vcp->iod_thr = curthread;
 855         else
 856                 err = EEXIST;
 857         SMB_VC_UNLOCK(vcp);
 858         if (err)
 859                 return (err);
 860 
 861         /*
 862          * Copy the "work" state, etc. into the VC
 863          * The MAC key is copied separately.

 864          */
 865         if (ddi_copyin((void *)arg, &vcp->vc_work,
 866             sizeof (smbioc_ssn_work_t), flags)) {
 867                 err = EFAULT;
 868                 goto out;
 869         }
 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         }
 879 
 880         err = smb_iod_vc_work(vcp, cr);
 881 
 882         /* Caller wants state here. */
 883         vcp->vc_work.wk_out_state = vcp->vc_state;

 884 
 885         (void) ddi_copyout(&vcp->vc_work, (void *)arg,
 886             sizeof (smbioc_ssn_work_t), flags);

 887 
 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;














 893         }
 894 





 895         /*
 896          * The IOD thread is leaving the driver.  Clear iod_thr,
 897          * and wake up anybody waiting for us to quit.
 898          */
 899         SMB_VC_LOCK(vcp);
 900         vcp->iod_thr = NULL;
 901         cv_broadcast(&vcp->vc_statechg);
 902         SMB_VC_UNLOCK(vcp);
 903 
 904         return (err);
 905 }
 906 
 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 int
 915 smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags)
 916 {
 917         struct smb_vc *vcp = NULL;
 918         int err = 0;
 919 
 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         /*
 927          * Is there already an IOD for this VC?
 928          * (Should never happen.)
 929          */
 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);
 938 
 939         /* nothing to copyin */
 940 
 941         switch (cmd) {
 942         case SMBIOC_IOD_IDLE:
 943                 err = smb_iod_vc_idle(vcp);

 944                 break;
 945 






















































 946         case SMBIOC_IOD_RCFAIL:
 947                 err = smb_iod_vc_rcfail(vcp);
 948                 break;
 949 








 950         default:
 951                 err = ENOTTY;
 952                 goto out;
 953         }
 954 
 955         /* Both of these ioctls copy out the new state. */
 956         (void) ddi_copyout(&vcp->vc_state, (void *)arg,
 957             sizeof (int), flags);
 958 
 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         return (err);
 970 }


  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_usr.c,v 1.15 2004/12/13 00:25:18 lindak Exp $
  33  */
  34 
  35 /*

  36  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  37  * Use is subject to license terms.
  38  *
  39  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  40  */
  41 
  42 #include <sys/param.h>
  43 #include <sys/kmem.h>
  44 #include <sys/systm.h>
  45 #include <sys/policy.h>
  46 #include <sys/conf.h>
  47 #include <sys/proc.h>
  48 #include <sys/fcntl.h>
  49 #include <sys/file.h>
  50 #include <sys/socket.h>
  51 #include <sys/sunddi.h>
  52 #include <sys/cmn_err.h>
  53 
  54 #include <netsmb/smb_osdep.h>
  55 
  56 #include <smb/winioctl.h>
  57 #include <netsmb/smb.h>
  58 #include <netsmb/smb_conn.h>
  59 #include <netsmb/smb_rq.h>
  60 #include <netsmb/smb_subr.h>
  61 #include <netsmb/smb_dev.h>
  62 
  63 static int smb_cpdatain(struct mbchain *mbp, int len, char *data, int seg);
  64 
  65 /*






















  66  * Ioctl function for SMBIOC_GETSSNKEY
  67  * Size copied out is SMBIOC_HASH_SZ.
  68  *
  69  * The RPC library needs this for encrypting things
  70  * like "set password" requests.  This is called
  71  * with an active RPC binding, so the connection
  72  * will already be active (but this checks).
  73  */
  74 int
  75 smb_usr_get_ssnkey(smb_dev_t *sdp, intptr_t arg, int flags)
  76 {
  77         struct smb_vc *vcp = NULL;
  78 
  79         /* This ioctl requires an active session. */
  80         if ((vcp = sdp->sd_vc) == NULL)
  81                 return (ENOTCONN);
  82         if (vcp->vc_state != SMBIOD_ST_VCACTIVE)
  83                 return (ENOTCONN);
  84 
  85         /*
  86          * Return the session key.
  87          */
  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,
  92             SMBIOC_HASH_SZ, flags))
  93                 return (EFAULT);
  94 
  95         return (0);
  96 }
  97 
  98 /*
  99  * Ioctl function for SMBIOC_XACTNP (transact named pipe)
 100  */
 101 int
 102 smb_usr_xnp(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 103 {
 104         struct smb_cred scred;
 105         struct smb_share *ssp;
 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;
 111         int err, mbseg;
 112 
 113         /* This ioctl requires a file handle. */
 114         if ((fhp = sdp->sd_fh) == NULL)
 115                 return (EINVAL);
 116         ssp = FHTOSS(fhp);
 117 
 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 
 125         ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 126         if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 127                 err = EFAULT;
 128                 goto out;
 129         }
 130 



 131         /*
 132          * Copyin the send data, into an mbchain,
 133          * save output buffer size.
 134          */
 135         mbseg = (flags & FKIOCTL) ? MB_MSYSTEM : MB_MUSER;
 136         err = smb_cpdatain(&send_mb, ioc->ioc_tdlen, ioc->ioc_tdata, mbseg);













 137         if (err)
 138                 goto out;
 139         rdlen = ioc->ioc_rdlen;
 140 





 141         /*
 142          * Run the SMB2 ioctl or SMB1 trans2


 143          */
 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);


 153         }
















 154         smb_credrele(&scred);
 155 
 156         /* Copyout returned data. */
 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) {

















































































 161                         err = EMSGSIZE;
 162                         goto out;
 163                 }
 164                 err = md_get_mem(&recv_md, ioc->ioc_rdata, len, mbseg);

 165                 if (err)
 166                         goto out;
 167         } else
 168                 ioc->ioc_rdlen = 0;
 169 
 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         }






 178 





 179         (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
 180 

 181 out:





 182         kmem_free(ioc, sizeof (*ioc));

 183 
 184         return (err);
 185 }
 186 
 187 /* helper for _t2request */
 188 static int
 189 smb_cpdatain(struct mbchain *mbp, int len, char *data, int mbseg)
 190 {
 191         int error;
 192 
 193         if (len == 0)
 194                 return (0);
 195         error = mb_init(mbp);
 196         if (error)
 197                 return (error);
 198         return (mb_put_mem(mbp, data, len, mbseg));
 199 }
 200 
 201 /*
 202  * Helper for nsmb_ioctl cases
 203  * SMBIOC_READ, SMBIOC_WRITE
 204  */
 205 int
 206 smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 207 {
 208         struct smb_cred scred;
 209         struct smb_share *ssp;
 210         struct smb_fh *fhp;
 211         smbioc_rw_t *ioc = NULL;
 212         struct iovec aiov[1];
 213         struct uio  auio;

 214         int err;
 215         uio_rw_t rw;
 216 
 217         /* This ioctl requires a file handle. */
 218         if ((fhp = sdp->sd_fh) == NULL)
 219                 return (EINVAL);
 220         ssp = FHTOSS(fhp);
 221 
 222         /* After reconnect, force close+reopen */
 223         if (fhp->fh_vcgenid != ssp->ss_vcgenid)
 224                 return (ESTALE);
 225 

 226         ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 227         if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 228                 err = EFAULT;
 229                 goto out;
 230         }
 231 
 232         switch (cmd) {
 233         case SMBIOC_READ:
 234                 rw = UIO_READ;
 235                 break;
 236         case SMBIOC_WRITE:
 237                 rw = UIO_WRITE;
 238                 break;
 239         default:
 240                 err = ENODEV;
 241                 goto out;
 242         }
 243 









 244         aiov[0].iov_base = ioc->ioc_base;
 245         aiov[0].iov_len = (size_t)ioc->ioc_cnt;
 246 
 247         auio.uio_iov = aiov;
 248         auio.uio_iovcnt = 1;
 249         auio.uio_loffset = ioc->ioc_offset;
 250         auio.uio_segflg = (flags & FKIOCTL) ?
 251             UIO_SYSSPACE : UIO_USERSPACE;
 252         auio.uio_fmode = 0;
 253         auio.uio_resid = (size_t)ioc->ioc_cnt;
 254 
 255         smb_credinit(&scred, cr);
 256         err = smb_rwuio(fhp, rw, &auio, &scred, 0);
 257         smb_credrele(&scred);
 258 
 259         /*
 260          * On return ioc_cnt holds the
 261          * number of bytes transferred.
 262          */
 263         ioc->ioc_cnt -= auio.uio_resid;
 264 
 265         (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags);
 266 
 267 out:
 268         kmem_free(ioc, sizeof (*ioc));

 269 
 270         return (err);
 271 }
 272 
 273 /*
 274  * Helper for nsmb_ioctl case
 275  * SMBIOC_NTCREATE
 276  */
 277 int
 278 smb_usr_ntcreate(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 279 {
 280         struct smb_cred scred;
 281         struct mbchain name_mb;
 282         struct smb_share *ssp;
 283         struct smb_fh *fhp = NULL;
 284         smbioc_ntcreate_t *ioc = NULL;

 285         int err, nmlen;
 286 
 287         mb_init(&name_mb);
 288 
 289         /* This ioctl requires a share. */
 290         if ((ssp = sdp->sd_share) == NULL)
 291                 return (ENOTCONN);
 292 
 293         /* Must not already have a file handle. */
 294         if (sdp->sd_fh != NULL)
 295                 return (EINVAL);
 296 


 297         ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 298         if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 299                 err = EFAULT;
 300                 goto out;
 301         }
 302 
 303         /* Build name_mb */
 304         ioc->ioc_name[SMBIOC_MAX_NAME-1] = '\0';
 305         nmlen = strnlen(ioc->ioc_name, SMBIOC_MAX_NAME-1);
 306         err = smb_put_dmem(&name_mb, SSTOVC(ssp),
 307             ioc->ioc_name, nmlen,
 308             SMB_CS_NONE, NULL);
 309         if (err != 0)
 310                 goto out;
 311 
 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);
 320         err = smb_smb_ntcreate(ssp, &name_mb,
 321             0,  /* create flags */
 322             ioc->ioc_req_acc,
 323             ioc->ioc_efattr,
 324             ioc->ioc_share_acc,
 325             ioc->ioc_open_disp,
 326             ioc->ioc_creat_opts,
 327             NTCREATEX_IMPERSONATION_IMPERSONATION,
 328             &scred,
 329             fhp,
 330             NULL,
 331             NULL);
 332         smb_credrele(&scred);
 333         if (err != 0)
 334                 goto out;
 335 
 336         fhp->fh_rights = ioc->ioc_req_acc;
 337         smb_fh_opened(fhp);
 338         sdp->sd_fh = fhp;
 339         fhp = NULL;
 340 
 341 out:
 342         if (fhp != NULL)
 343                 smb_fh_rele(fhp);
 344         kmem_free(ioc, sizeof (*ioc));

 345         mb_done(&name_mb);
 346 
 347         return (err);
 348 }
 349 
 350 /*
 351  * Helper for nsmb_ioctl case
 352  * SMBIOC_PRINTJOB
 353  */
 354 int
 355 smb_usr_printjob(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr)
 356 {
 357         static const char invalid_chars[] = SMB_FILENAME_INVALID_CHARS;
 358         struct smb_cred scred;
 359         struct mbchain name_mb;
 360         struct smb_share *ssp;
 361         struct smb_fh *fhp = NULL;
 362         smbioc_printjob_t *ioc = NULL;
 363         int err, cklen, nmlen;
 364         uint32_t access = SA_RIGHT_FILE_WRITE_DATA |
 365             SA_RIGHT_FILE_READ_ATTRIBUTES;
 366 
 367         mb_init(&name_mb);
 368 
 369         /* This ioctl requires a share. */
 370         if ((ssp = sdp->sd_share) == NULL)
 371                 return (ENOTCONN);
 372 
 373         /* The share must be a print queue. */
 374         if (ssp->ss_type != STYPE_PRINTQ)
 375                 return (EINVAL);
 376 
 377         /* Must not already have a file handle. */
 378         if (sdp->sd_fh != NULL)
 379                 return (EINVAL);
 380 
 381         smb_credinit(&scred, cr);
 382         ioc = kmem_alloc(sizeof (*ioc), KM_SLEEP);
 383         if (ddi_copyin((void *) arg, ioc, sizeof (*ioc), flags)) {
 384                 err = EFAULT;
 385                 goto out;
 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          */
 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         }
 400 
 401         /* Build name_mb */
 402         err = smb_put_dmem(&name_mb, SSTOVC(ssp),
 403             ioc->ioc_title, nmlen,
 404             SMB_CS_NONE, NULL);
 405         if (err != 0)
 406                 goto out;
 407 
 408         err = smb_fh_create(ssp, &fhp);
 409         if (err != 0)
 410                 goto out;
 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 
 444 out:
 445         if (fhp != NULL)
 446                 smb_fh_rele(fhp);
 447         kmem_free(ioc, sizeof (*ioc));
 448         mb_done(&name_mb);
 449 
 450         return (err);
 451 }
 452 
 453 /*
 454  * Helper for nsmb_ioctl case
 455  * SMBIOC_CLOSEFH
 456  */
 457 /*ARGSUSED*/
 458 int
 459 smb_usr_closefh(smb_dev_t *sdp, cred_t *cr)
 460 {
 461         struct smb_fh *fhp;



 462 
 463         /* This ioctl requires a file handle. */
 464         if ((fhp = sdp->sd_fh) == NULL)
 465                 return (EINVAL);
 466         sdp->sd_fh = NULL;
 467 
 468         smb_fh_close(fhp);
 469         smb_fh_rele(fhp);


 470 
 471         return (0);







 472 }
 473 
 474 /*
 475  * Ioctl functions: SMBIOC_SSN_FIND, SMBIOC_SSN_CREATE
 476  * Find or create a session (a.k.a. "VC" in here)
 477  */
 478 int
 479 smb_usr_get_ssn(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 480 {
 481         struct smb_cred scred;
 482         smbioc_ossn_t *ossn = NULL;
 483         struct smb_vc *vcp = NULL;
 484         int error = 0;
 485         uid_t realuid;
 486 
 487         /* Should be no VC */
 488         if (sdp->sd_vc != NULL)
 489                 return (EISCONN);
 490 
 491         smb_credinit(&scred, cr);


 703 {
 704         struct smb_share *ssp = NULL;
 705 
 706         /* Must have a VC and a share. */
 707         if (sdp->sd_vc == NULL)
 708                 return (ENOTCONN);
 709         if ((ssp = sdp->sd_share) == NULL)
 710                 return (ENOTCONN);
 711 
 712         if (cmd == SMBIOC_TREE_KILL)
 713                 smb_share_kill(ssp);
 714 
 715         /* Drop the share ref. */
 716         smb_share_rele(sdp->sd_share);
 717         sdp->sd_share = NULL;
 718         sdp->sd_level = SMBL_VC;
 719 
 720         return (0);
 721 }
 722 

 723 /*
 724  * Ioctl handler for all SMBIOC_IOD_...




 725  */
 726 int
 727 smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 728 {
 729         struct smb_vc *vcp;
 730         int err = 0;
 731 
 732         /* Must be the IOD. */
 733         if ((sdp->sd_flags & NSMBFL_IOD) == 0)
 734                 return (EINVAL);
 735         /* Must have a VC and no share. */
 736         if ((vcp = sdp->sd_vc) == NULL)
 737                 return (EINVAL);
 738         if (sdp->sd_share != NULL)
 739                 return (EINVAL);
 740 
 741         /*
 742          * Is there already an IOD for this VC?
 743          * (Should never happen.)
 744          */
 745         SMB_VC_LOCK(vcp);
 746         if (vcp->iod_thr == NULL)
 747                 vcp->iod_thr = curthread;
 748         else
 749                 err = EEXIST;
 750         SMB_VC_UNLOCK(vcp);
 751         if (err)
 752                 return (err);
 753 
 754         /*
 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.
 758          */
 759         if (ddi_copyin((void *)arg, &vcp->vc_work,
 760             sizeof (smbioc_ssn_work_t), flags)) {
 761                 err = EFAULT;
 762                 goto out;
 763         }
 764         vcp->vc_work.wk_out_state = 0;








 765 
 766         switch (cmd) {
 767 
 768         case SMBIOC_IOD_CONNECT:
 769                 err = nsmb_iod_connect(vcp, cr);
 770                 break;
 771 
 772         case SMBIOC_IOD_NEGOTIATE:
 773                 err = nsmb_iod_negotiate(vcp, cr);
 774                 break;
 775 
 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;
 795         }
 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 
 802         /*
 803          * The IOD thread is leaving the driver.  Clear iod_thr,
 804          * and wake up anybody waiting for us to quit.
 805          */
 806         SMB_VC_LOCK(vcp);
 807         vcp->iod_thr = NULL;
 808         cv_broadcast(&vcp->vc_statechg);
 809         SMB_VC_UNLOCK(vcp);
 810 
 811         return (err);
 812 }
 813 







 814 int
 815 smb_usr_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr)
 816 {
 817         int err;

 818 






 819         /*
 820          * Serialize ioctl calls.  The smb_usr_... functions
 821          * don't expect concurrent calls on a given sdp.
 822          */
 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);

 830 
 831         err = 0;

 832         switch (cmd) {
 833         case SMBIOC_GETVERS:
 834                 (void) ddi_copyout(&nsmb_version, (void *)arg,
 835                     sizeof (nsmb_version), flags);
 836                 break;
 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:
 892         case SMBIOC_IOD_RCFAIL:
 893                 err = smb_usr_iod_ioctl(sdp, cmd, arg, flags, cr);
 894                 break;
 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 
 904         default:
 905                 err = ENOTTY;
 906                 break;
 907         }
 908 
 909         mutex_enter(&sdp->sd_lock);
 910         sdp->sd_flags &= ~NSMBFL_IOCTL;
 911         mutex_exit(&sdp->sd_lock);
 912 










 913         return (err);
 914 }