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)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)
re #11128 nsmb_close locking and teardown deadlock


  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  33 /*
  34  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  35  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  36  * Use is subject to license terms.


  37  */
  38 
  39 #include <sys/types.h>
  40 #include <sys/param.h>
  41 #include <sys/errno.h>
  42 #include <sys/sysmacros.h>
  43 #include <sys/uio.h>
  44 #include <sys/buf.h>
  45 #include <sys/modctl.h>
  46 #include <sys/open.h>
  47 #include <sys/file.h>
  48 #include <sys/kmem.h>
  49 #include <sys/conf.h>
  50 #include <sys/cmn_err.h>
  51 #include <sys/stat.h>
  52 #include <sys/ddi.h>
  53 #include <sys/sunddi.h>
  54 #include <sys/sunldi.h>
  55 #include <sys/policy.h>
  56 #include <sys/zone.h>
  57 #include <sys/pathname.h>
  58 #include <sys/mount.h>
  59 #include <sys/sdt.h>
  60 #include <fs/fs_subr.h>
  61 #include <sys/modctl.h>
  62 #include <sys/devops.h>
  63 #include <sys/thread.h>
  64 #include <sys/types.h>
  65 #include <sys/zone.h>
  66 
  67 #include <netsmb/smb_osdep.h>
  68 #include <netsmb/mchain.h>                /* for "htoles()" */
  69 
  70 #include <netsmb/smb.h>

  71 #include <netsmb/smb_conn.h>
  72 #include <netsmb/smb_subr.h>
  73 #include <netsmb/smb_dev.h>
  74 #include <netsmb/smb_pass.h>
  75 








  76 #define NSMB_MIN_MINOR  1
  77 #define NSMB_MAX_MINOR  L_MAXMIN32
  78 
  79 /* for version checks */
  80 const uint32_t nsmb_version = NSMB_VERSION;
  81 




  82 static void *statep;
  83 static major_t nsmb_major;
  84 static minor_t last_minor = NSMB_MIN_MINOR;
  85 static dev_info_t *nsmb_dip;
  86 static kmutex_t  dev_lck;
  87 
  88 /* Zone support */
  89 zone_key_t nsmb_zone_key;
  90 extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
  91 extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
  92 
  93 /*
  94  * cb_ops device operations.
  95  */
  96 static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
  97 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
  98 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
  99                                 cred_t *credp, int *rvalp);
 100 static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
 101 









 102 /* smbfs cb_ops */
 103 static struct cb_ops nsmb_cbops = {
 104         nsmb_open,      /* open */
 105         nsmb_close,     /* close */
 106         nodev,          /* strategy */
 107         nodev,          /* print */
 108         nodev,          /* dump */
 109         nodev,          /* read */
 110         nodev,          /* write */
 111         nsmb_ioctl,     /* ioctl */
 112         nodev,          /* devmap */
 113         nodev,          /* mmap */
 114         nodev,          /* segmap */
 115         nochpoll,       /* poll */
 116         ddi_prop_op,    /* prop_op */
 117         NULL,           /* stream */
 118         D_MP,           /* cb_flag */
 119         CB_REV,         /* rev */
 120         nodev,          /* int (*cb_aread)() */
 121         nodev           /* int (*cb_awrite)() */


 143         NULL,           /* power */
 144         ddi_quiesce_not_needed, /* quiesce */
 145 };
 146 
 147 /*
 148  * Module linkage information.
 149  */
 150 
 151 static struct modldrv nsmb_modldrv = {
 152         &mod_driverops,                             /* Driver module */
 153         "SMBFS network driver",
 154         &nsmb_ops                           /* Driver ops */
 155 };
 156 
 157 static struct modlinkage nsmb_modlinkage = {
 158         MODREV_1,
 159         (void *)&nsmb_modldrv,
 160         NULL
 161 };
 162 


 163 int
 164 _init(void)
 165 {

 166         int error;

 167 
 168         (void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
 169 
 170         /* Can initialize some mutexes also. */
 171         mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);
 172 
 173         /* Connection data structures. */
 174         (void) smb_sm_init();
 175 
 176         /* Initialize password Key chain DB. */
 177         smb_pkey_init();
 178 
 179         /* Time conversion stuff. */
 180         smb_time_init();
 181 
 182         /* Initialize crypto mechanisms. */
 183         smb_crypto_mech_init();
 184 
 185         zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
 186             nsmb_zone_destroy);
 187 
 188         /*
 189          * Install the module.  Do this after other init,
 190          * to prevent entrances before we're ready.
 191          */
 192         if ((error = mod_install((&nsmb_modlinkage))) != 0) {
 193 
 194                 /* Same as 2nd half of _fini */
 195                 (void) zone_key_delete(nsmb_zone_key);
 196                 smb_pkey_fini();
 197                 smb_sm_done();
 198                 mutex_destroy(&dev_lck);
 199                 ddi_soft_state_fini(&statep);
 200 
 201                 return (error);
 202         }








 203 
 204         return (0);
 205 }
 206 
 207 int
 208 _fini(void)
 209 {
 210         int status;
 211 
 212         /*
 213          * Prevent unload if we have active VCs
 214          * or stored passwords
 215          */
 216         if ((status = smb_sm_idle()) != 0)
 217                 return (status);
 218         if ((status = smb_pkey_idle()) != 0)
 219                 return (status);
 220 

 221         /*
 222          * Remove the module.  Do this before destroying things,
 223          * to prevent new entrances while we're destorying.
 224          */
 225         if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
 226                 return (status);
 227         }
 228 
 229         (void) zone_key_delete(nsmb_zone_key);

 230 
 231         /* Time conversion stuff. */
 232         smb_time_fini();
 233 
 234         /* Destroy password Key chain DB. */
 235         smb_pkey_fini();
 236 
 237         smb_sm_done();
 238 
 239         mutex_destroy(&dev_lck);
 240         ddi_soft_state_fini(&statep);
 241 
 242         return (status);
 243 }
 244 


 245 int
 246 _info(struct modinfo *modinfop)
 247 {
 248         return (mod_info(&nsmb_modlinkage, modinfop));
 249 }
 250 
 251 /*ARGSUSED*/
 252 static int
 253 nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 254 {
 255         int ret = DDI_SUCCESS;
 256 
 257         switch (cmd) {
 258         case DDI_INFO_DEVT2DEVINFO:
 259                 *result = nsmb_dip;
 260                 break;
 261         case DDI_INFO_DEVT2INSTANCE:
 262                 *result = NULL;
 263                 break;
 264         default:
 265                 ret = DDI_FAILURE;
 266         }
 267         return (ret);
 268 }
 269 
 270 static int
 271 nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 272 {

 273 
 274         if (cmd != DDI_ATTACH)
 275                 return (DDI_FAILURE);
 276 
 277         /*
 278          * We only support only one "instance".  Note that
 279          * "instances" are different from minor units.
 280          * We get one (unique) minor unit per open.
 281          */
 282         if (ddi_get_instance(dip) > 0)
 283                 return (DDI_FAILURE);
 284 
 285         if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
 286             NULL) == DDI_FAILURE) {
 287                 cmn_err(CE_WARN, "nsmb_attach: create minor");
 288                 return (DDI_FAILURE);
 289         }
 290 
 291         /*
 292          * We need the major number a couple places,
 293          * i.e. in smb_dev2share()
 294          */
 295         nsmb_major = ddi_name_to_major(NSMB_NAME);
 296 














 297         nsmb_dip = dip;
 298         ddi_report_dev(dip);
 299         return (DDI_SUCCESS);
 300 }
 301 
 302 /*ARGSUSED*/
 303 static int
 304 nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 305 {
 306 
 307         if (cmd != DDI_DETACH)
 308                 return (DDI_FAILURE);
 309         if (ddi_get_instance(dip) > 0)
 310                 return (DDI_FAILURE);
 311 
 312         nsmb_dip = NULL;
 313         ddi_remove_minor_node(dip, NULL);
 314 
 315         return (DDI_SUCCESS);
 316 }
 317 






 318 /*ARGSUSED*/





















































 319 static int
 320 nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
 321     cred_t *cr, int *rvalp)
 322 {
 323         smb_dev_t *sdp;
 324         int err;
 325 
 326         sdp = ddi_get_soft_state(statep, getminor(dev));
 327         if (sdp == NULL) {
 328                 return (DDI_FAILURE);
 329         }
 330         if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
 331                 return (EBADF);
 332         }
 333 
 334         /*
 335          * Dont give access if the zone id is not as the same as we
 336          * set in the nsmb_open or dont belong to the global zone.
 337          * Check if the user belongs to this zone..
 338          */
 339         if (sdp->zoneid != getzoneid())
 340                 return (EIO);
 341 
 342         /*
 343          * We have a zone_shutdown call back that kills all the VCs
 344          * in a zone that's shutting down.  That action will cause
 345          * all of these ioctls to fail on such VCs, so no need to
 346          * check the zone status here on every ioctl call.
 347          */
 348 
 349         /*
 350          * Serialize ioctl calls.  The smb_usr_... functions
 351          * don't expect concurrent calls on a given sdp.
 352          */
 353         mutex_enter(&sdp->sd_lock);
 354         if ((sdp->sd_flags & NSMBFL_IOCTL) != 0) {
 355                 mutex_exit(&sdp->sd_lock);
 356                 return (EBUSY);
 357         }
 358         sdp->sd_flags |= NSMBFL_IOCTL;
 359         mutex_exit(&sdp->sd_lock);
 360 
 361         err = 0;
 362         switch (cmd) {
 363         case SMBIOC_GETVERS:
 364                 (void) ddi_copyout(&nsmb_version, (void *)arg,
 365                     sizeof (nsmb_version), flags);
 366                 break;
 367 
 368         case SMBIOC_FLAGS2:
 369                 err = smb_usr_get_flags2(sdp, arg, flags);
 370                 break;
 371 
 372         case SMBIOC_GETSSNKEY:
 373                 err = smb_usr_get_ssnkey(sdp, arg, flags);
 374                 break;
 375 
 376         case SMBIOC_DUP_DEV:
 377                 err = smb_usr_dup_dev(sdp, arg, flags);
 378                 break;
 379 
 380         case SMBIOC_REQUEST:
 381                 err = smb_usr_simplerq(sdp, arg, flags, cr);
 382                 break;
 383 
 384         case SMBIOC_T2RQ:
 385                 err = smb_usr_t2request(sdp, arg, flags, cr);
 386                 break;
 387 
 388         case SMBIOC_READ:
 389         case SMBIOC_WRITE:
 390                 err = smb_usr_rw(sdp, cmd, arg, flags, cr);
 391                 break;
 392 
 393         case SMBIOC_NTCREATE:
 394                 err = smb_usr_ntcreate(sdp, arg, flags, cr);
 395                 break;
 396 
 397         case SMBIOC_PRINTJOB:
 398                 err = smb_usr_printjob(sdp, arg, flags, cr);
 399                 break;
 400 
 401         case SMBIOC_CLOSEFH:
 402                 err = smb_usr_closefh(sdp, cr);
 403                 break;
 404 
 405         case SMBIOC_SSN_CREATE:
 406         case SMBIOC_SSN_FIND:
 407                 err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
 408                 break;
 409 
 410         case SMBIOC_SSN_KILL:
 411         case SMBIOC_SSN_RELE:
 412                 err = smb_usr_drop_ssn(sdp, cmd);
 413                 break;
 414 
 415         case SMBIOC_TREE_CONNECT:
 416         case SMBIOC_TREE_FIND:
 417                 err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
 418                 break;
 419 
 420         case SMBIOC_TREE_KILL:
 421         case SMBIOC_TREE_RELE:
 422                 err = smb_usr_drop_tree(sdp, cmd);
 423                 break;
 424 
 425         case SMBIOC_IOD_WORK:
 426                 err = smb_usr_iod_work(sdp, arg, flags, cr);
 427                 break;
 428 
 429         case SMBIOC_IOD_IDLE:
 430         case SMBIOC_IOD_RCFAIL:
 431                 err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
 432                 break;
 433 
 434         case SMBIOC_PK_ADD:
 435         case SMBIOC_PK_DEL:
 436         case SMBIOC_PK_CHK:
 437         case SMBIOC_PK_DEL_OWNER:
 438         case SMBIOC_PK_DEL_EVERYONE:
 439                 err = smb_pkey_ioctl(cmd, arg, flags, cr);
 440                 break;
 441 
 442         default:
 443                 err = ENOTTY;
 444                 break;
 445         }
 446 
 447         mutex_enter(&sdp->sd_lock);
 448         sdp->sd_flags &= ~NSMBFL_IOCTL;
 449         mutex_exit(&sdp->sd_lock);
 450 
 451         return (err);
 452 }
 453 
 454 /*
 455  * This does "clone" open, meaning it automatically
 456  * assigns an available minor unit for each open.
 457  */
 458 /*ARGSUSED*/
 459 static int
 460 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
 461 {
 462         smb_dev_t *sdp;
 463         minor_t m;
 464 
 465         mutex_enter(&dev_lck);
 466 
 467         for (m = last_minor + 1; m != last_minor; m++) {
 468                 if (m > NSMB_MAX_MINOR)
 469                         m = NSMB_MIN_MINOR;
 470 


 474                 }
 475         }
 476 
 477         /* No available minor units. */
 478         mutex_exit(&dev_lck);
 479         return (ENXIO);
 480 
 481 found:
 482         /* NB: dev_lck still held */
 483         if (ddi_soft_state_zalloc(statep, m) == DDI_FAILURE) {
 484                 mutex_exit(&dev_lck);
 485                 return (ENXIO);
 486         }
 487         if ((sdp = ddi_get_soft_state(statep, m)) == NULL) {
 488                 mutex_exit(&dev_lck);
 489                 return (ENXIO);
 490         }
 491         *dev = makedevice(nsmb_major, m);
 492         mutex_exit(&dev_lck);
 493 
 494         sdp->sd_smbfid = -1;
 495         sdp->sd_flags |= NSMBFL_OPEN;
 496         sdp->zoneid = crgetzoneid(cr);
 497         mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL);
 498 
 499         return (0);
 500 }
 501 
 502 /*ARGSUSED*/
 503 static int
 504 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
 505 {
 506         minor_t inst = getminor(dev);
 507         smb_dev_t *sdp;
 508         int err;
 509 
 510         /*
 511          * 1. Check the validity of the minor number.
 512          * 2. Release any shares/vc associated  with the connection.
 513          * 3. Can close the minor number.
 514          * 4. Deallocate any resources allocated in open() call.
 515          */
 516 
 517         sdp = ddi_get_soft_state(statep, inst);
 518         if (sdp != NULL)
 519                 err = nsmb_close2(sdp, cr);
 520         else
 521                 err = ENXIO;
 522 
 523         /*
 524          * Free the instance
 525          */
 526         mutex_enter(&dev_lck);
 527         ddi_soft_state_free(statep, inst);
 528         mutex_exit(&dev_lck);
 529         return (err);
 530 }
 531 

 532 static int
 533 nsmb_close2(smb_dev_t *sdp, cred_t *cr)
 534 {
 535         struct smb_vc *vcp;
 536         struct smb_share *ssp;

 537 
 538         if (sdp->sd_smbfid != -1)
 539                 (void) smb_usr_closefh(sdp, cr);

 540 
 541         ssp = sdp->sd_share;
 542         if (ssp != NULL)
 543                 smb_share_rele(ssp);
 544 
 545         vcp = sdp->sd_vc;
 546         if (vcp != NULL) {
 547                 /*
 548                  * If this dev minor was opened by smbiod,
 549                  * mark this VC as "dead" because it now
 550                  * will have no IOD to service it.
 551                  */
 552                 if (sdp->sd_flags & NSMBFL_IOD)
 553                         smb_iod_disconnect(vcp);
 554                 smb_vc_rele(vcp);
 555         }
 556         mutex_destroy(&sdp->sd_lock);
 557 
 558         return (0);
 559 }
 560 
 561 /*
 562  * Helper for SMBIOC_DUP_DEV
 563  * Duplicate state from the FD @arg ("from") onto
 564  * the FD for this device instance.
 565  */
 566 int
 567 smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
 568 {

 569         file_t *fp = NULL;
 570         vnode_t *vp;

 571         smb_dev_t *from_sdp;
 572         dev_t dev;
 573         int32_t ufd;
 574         int err;
 575 
 576         /* Should be no VC */
 577         if (sdp->sd_vc != NULL)
 578                 return (EISCONN);
 579 
 580         /*
 581          * Get from_sdp (what we will duplicate)
 582          */
 583         if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
 584                 return (EFAULT);

 585         if ((fp = getf(ufd)) == NULL)
 586                 return (EBADF);
 587         /* rele fp below */
 588         vp = fp->f_vnode;
 589         dev = vp->v_rdev;






 590         if (dev == 0 || dev == NODEV ||
 591             getmajor(dev) != nsmb_major) {
 592                 err = EINVAL;
 593                 goto out;
 594         }

 595         from_sdp = ddi_get_soft_state(statep, getminor(dev));
 596         if (from_sdp == NULL) {
 597                 err = EINVAL;
 598                 goto out;
 599         }
 600 
 601         /*
 602          * Duplicate VC and share references onto this FD.
 603          */
 604         if ((sdp->sd_vc = from_sdp->sd_vc) != NULL)
 605                 smb_vc_hold(sdp->sd_vc);
 606         if ((sdp->sd_share = from_sdp->sd_share) != NULL)
 607                 smb_share_hold(sdp->sd_share);
 608         sdp->sd_level = from_sdp->sd_level;
 609         err = 0;
 610 
 611 out:

 612         if (fp)
 613                 releasef(ufd);

 614         return (err);
 615 }
 616 
 617 
 618 /*
 619  * Helper used by smbfs_mount
 620  */
 621 int
 622 smb_dev2share(int fd, struct smb_share **sspp)
 623 {

 624         file_t *fp = NULL;
 625         vnode_t *vp;

 626         smb_dev_t *sdp;
 627         smb_share_t *ssp;
 628         dev_t dev;
 629         int err;
 630 

 631         if ((fp = getf(fd)) == NULL)
 632                 return (EBADF);
 633         /* rele fp below */
 634 
 635         vp = fp->f_vnode;
 636         dev = vp->v_rdev;






 637         if (dev == 0 || dev == NODEV ||
 638             getmajor(dev) != nsmb_major) {
 639                 err = EINVAL;
 640                 goto out;
 641         }
 642 
 643         sdp = ddi_get_soft_state(statep, getminor(dev));
 644         if (sdp == NULL) {
 645                 err = EINVAL;
 646                 goto out;
 647         }
 648 
 649         ssp = sdp->sd_share;
 650         if (ssp == NULL) {
 651                 err = ENOTCONN;
 652                 goto out;
 653         }
 654 
 655         /*
 656          * Our caller gains a ref. to this share.
 657          */
 658         *sspp = ssp;
 659         smb_share_hold(ssp);
 660         err = 0;
 661 
 662 out:

 663         if (fp)
 664                 releasef(fd);

 665         return (err);
 666 }


  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  33 /*

  34  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  35  * Use is subject to license terms.
  36  *
  37  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  38  */
  39 
  40 #include <sys/types.h>
  41 #include <sys/param.h>
  42 #include <sys/errno.h>
  43 #include <sys/sysmacros.h>
  44 #include <sys/uio.h>
  45 #include <sys/buf.h>
  46 #include <sys/modctl.h>
  47 #include <sys/open.h>
  48 #include <sys/file.h>
  49 #include <sys/kmem.h>
  50 #include <sys/conf.h>
  51 #include <sys/cmn_err.h>
  52 #include <sys/stat.h>
  53 #include <sys/ddi.h>
  54 #include <sys/sunddi.h>
  55 #include <sys/sunldi.h>
  56 #include <sys/policy.h>
  57 #include <sys/zone.h>
  58 #include <sys/pathname.h>
  59 #include <sys/mount.h>
  60 #include <sys/sdt.h>
  61 #include <fs/fs_subr.h>
  62 #include <sys/modctl.h>
  63 #include <sys/devops.h>
  64 #include <sys/thread.h>
  65 #include <sys/socket.h>
  66 #include <sys/zone.h>
  67 
  68 #include <netsmb/smb_osdep.h>
  69 #include <netsmb/mchain.h>                /* for "htoles()" */
  70 
  71 #include <netsmb/smb.h>
  72 #include <netsmb/smb2.h>
  73 #include <netsmb/smb_conn.h>
  74 #include <netsmb/smb_subr.h>
  75 #include <netsmb/smb_dev.h>
  76 #include <netsmb/smb_pass.h>
  77 
  78 #ifndef _KERNEL
  79 #include <libfknsmb.h>
  80 
  81 #define _init(v)        nsmb_drv_init(v)
  82 #define _fini(v)        nsmb_drv_fini(v)
  83 
  84 #endif  /* _KERNEL */
  85 
  86 #define NSMB_MIN_MINOR  1
  87 #define NSMB_MAX_MINOR  L_MAXMIN32
  88 
  89 /* for version checks */
  90 const uint32_t nsmb_version = NSMB_VERSION;
  91 
  92 /* for smb_nbst_create() */
  93 dev_t nsmb_dev_tcp = NODEV;
  94 dev_t nsmb_dev_tcp6 = NODEV;
  95 
  96 static void *statep;
  97 static major_t nsmb_major;
  98 static minor_t last_minor = NSMB_MIN_MINOR;

  99 static kmutex_t  dev_lck;
 100 





 101 /*
 102  * cb_ops device operations.
 103  */
 104 static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp);
 105 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp);
 106 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
 107                                 cred_t *credp, int *rvalp);
 108 static int nsmb_close2(smb_dev_t *sdp, cred_t *cr);
 109 
 110 #ifdef  _KERNEL
 111 
 112 static dev_info_t *nsmb_dip;
 113 
 114 /* Zone support */
 115 zone_key_t nsmb_zone_key;
 116 extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data);
 117 extern void nsmb_zone_destroy(zoneid_t zoneid, void *data);
 118 
 119 /* smbfs cb_ops */
 120 static struct cb_ops nsmb_cbops = {
 121         nsmb_open,      /* open */
 122         nsmb_close,     /* close */
 123         nodev,          /* strategy */
 124         nodev,          /* print */
 125         nodev,          /* dump */
 126         nodev,          /* read */
 127         nodev,          /* write */
 128         nsmb_ioctl,     /* ioctl */
 129         nodev,          /* devmap */
 130         nodev,          /* mmap */
 131         nodev,          /* segmap */
 132         nochpoll,       /* poll */
 133         ddi_prop_op,    /* prop_op */
 134         NULL,           /* stream */
 135         D_MP,           /* cb_flag */
 136         CB_REV,         /* rev */
 137         nodev,          /* int (*cb_aread)() */
 138         nodev           /* int (*cb_awrite)() */


 160         NULL,           /* power */
 161         ddi_quiesce_not_needed, /* quiesce */
 162 };
 163 
 164 /*
 165  * Module linkage information.
 166  */
 167 
 168 static struct modldrv nsmb_modldrv = {
 169         &mod_driverops,                             /* Driver module */
 170         "SMBFS network driver",
 171         &nsmb_ops                           /* Driver ops */
 172 };
 173 
 174 static struct modlinkage nsmb_modlinkage = {
 175         MODREV_1,
 176         (void *)&nsmb_modldrv,
 177         NULL
 178 };
 179 
 180 #endif  /* _KERNEL */
 181 
 182 int
 183 _init(void)
 184 {
 185 #ifdef  _KERNEL
 186         int error;
 187 #endif  /* _KERNEL */
 188 
 189         (void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1);
 190 
 191         /* Can initialize some mutexes also. */
 192         mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL);
 193 
 194         /* Connection data structures. */
 195         (void) smb_sm_init();
 196 
 197         /* Initialize password Key chain DB. */
 198         smb_pkey_init();
 199 
 200 #ifdef  _KERNEL





 201         zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown,
 202             nsmb_zone_destroy);
 203 
 204         /*
 205          * Install the module.  Do this after other init,
 206          * to prevent entrances before we're ready.
 207          */
 208         if ((error = mod_install((&nsmb_modlinkage))) != 0) {
 209 
 210                 /* Same as 2nd half of _fini */
 211                 (void) zone_key_delete(nsmb_zone_key);
 212                 smb_pkey_fini();
 213                 smb_sm_done();
 214                 mutex_destroy(&dev_lck);
 215                 ddi_soft_state_fini(&statep);
 216 
 217                 return (error);
 218         }
 219 #else   /* _KERNEL */
 220         streams_msg_init();
 221         /* No attach, so need to set major. */
 222         nsmb_major = 1;
 223         /* And these, for smb_nbst_create() */
 224         nsmb_dev_tcp = AF_INET;
 225         nsmb_dev_tcp6 = AF_INET6;
 226 #endif  /* _KERNEL */
 227 
 228         return (0);
 229 }
 230 
 231 int
 232 _fini(void)
 233 {
 234         int status;
 235 
 236         /*
 237          * Prevent unload if we have active VCs
 238          * or stored passwords
 239          */
 240         if ((status = smb_sm_idle()) != 0)
 241                 return (status);
 242         if ((status = smb_pkey_idle()) != 0)
 243                 return (status);
 244 
 245 #ifdef  _KERNEL
 246         /*
 247          * Remove the module.  Do this before destroying things,
 248          * to prevent new entrances while we're destorying.
 249          */
 250         if ((status = mod_remove(&nsmb_modlinkage)) != 0) {
 251                 return (status);
 252         }
 253 
 254         (void) zone_key_delete(nsmb_zone_key);
 255 #endif  /* _KERNEL */
 256 



 257         /* Destroy password Key chain DB. */
 258         smb_pkey_fini();
 259 
 260         smb_sm_done();
 261 
 262         mutex_destroy(&dev_lck);
 263         ddi_soft_state_fini(&statep);
 264 
 265         return (status);
 266 }
 267 
 268 #ifdef  _KERNEL
 269 
 270 int
 271 _info(struct modinfo *modinfop)
 272 {
 273         return (mod_info(&nsmb_modlinkage, modinfop));
 274 }
 275 
 276 /*ARGSUSED*/
 277 static int
 278 nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
 279 {
 280         int ret = DDI_SUCCESS;
 281 
 282         switch (cmd) {
 283         case DDI_INFO_DEVT2DEVINFO:
 284                 *result = nsmb_dip;
 285                 break;
 286         case DDI_INFO_DEVT2INSTANCE:
 287                 *result = NULL;
 288                 break;
 289         default:
 290                 ret = DDI_FAILURE;
 291         }
 292         return (ret);
 293 }
 294 
 295 static int
 296 nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 297 {
 298         major_t tmaj;
 299 
 300         if (cmd != DDI_ATTACH)
 301                 return (DDI_FAILURE);
 302 
 303         /*
 304          * We only support only one "instance".  Note that
 305          * "instances" are different from minor units.
 306          * We get one (unique) minor unit per open.
 307          */
 308         if (ddi_get_instance(dip) > 0)
 309                 return (DDI_FAILURE);
 310 
 311         if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO,
 312             NULL) == DDI_FAILURE) {
 313                 cmn_err(CE_WARN, "nsmb_attach: create minor");
 314                 return (DDI_FAILURE);
 315         }
 316 
 317         /*
 318          * We need the major number a couple places,
 319          * i.e. in smb_dev2share()
 320          */
 321         nsmb_major = ddi_name_to_major(NSMB_NAME);
 322 
 323         /*
 324          * We also need major numbers for t_kopen
 325          */
 326         tmaj = ddi_name_to_major("tcp");
 327         if (tmaj == DDI_MAJOR_T_NONE)
 328                 cmn_err(CE_NOTE, "no tcp major?");
 329         else
 330                 nsmb_dev_tcp = makedevice(tmaj, 0);
 331         tmaj = ddi_name_to_major("tcp6");
 332         if (tmaj == DDI_MAJOR_T_NONE)
 333                 cmn_err(CE_NOTE, "no tcp6 major?");
 334         else
 335                 nsmb_dev_tcp6 = makedevice(tmaj, 0);
 336 
 337         nsmb_dip = dip;
 338         ddi_report_dev(dip);
 339         return (DDI_SUCCESS);
 340 }
 341 
 342 /*ARGSUSED*/
 343 static int
 344 nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 345 {
 346 
 347         if (cmd != DDI_DETACH)
 348                 return (DDI_FAILURE);
 349         if (ddi_get_instance(dip) > 0)
 350                 return (DDI_FAILURE);
 351 
 352         nsmb_dip = NULL;
 353         ddi_remove_minor_node(dip, NULL);
 354 
 355         return (DDI_SUCCESS);
 356 }
 357 
 358 #else   /* _KERNEL */
 359 
 360 /*
 361  * Wrappers for libfknsmb: ioctl, open, close, load
 362  */
 363 
 364 /*ARGSUSED*/
 365 int
 366 nsmb_drv_ioctl(dev32_t dev32, int cmd, intptr_t arg, int flags)
 367 {
 368         dev_t dev = expldev(dev32);
 369         cred_t *cr = CRED();
 370         int err;
 371 
 372         err = nsmb_ioctl(dev, cmd, arg, flags, cr, NULL);
 373         return (err);
 374 }
 375 
 376 /*ARGSUSED*/
 377 int
 378 nsmb_drv_open(dev32_t *dev32p, int flags, int otyp)
 379 {
 380         dev_t dev = expldev(*dev32p);
 381         int err;
 382 
 383         err = nsmb_open(&dev, flags, otyp, CRED());
 384         if (err == 0) {
 385                 /*
 386                  * We have NSMB_MAX_MINOR == L_MAXMIN32
 387                  * therefore cmpldev never fails.
 388                  */
 389                 VERIFY(cmpldev(dev32p, dev) != 0);
 390         }
 391         return (err);
 392 }
 393 
 394 /*ARGSUSED*/
 395 int
 396 nsmb_drv_close(dev32_t dev32, int flags, int otyp)
 397 {
 398         dev_t dev = expldev(dev32);
 399         int err;
 400 
 401         err = nsmb_close(dev, flags, otyp, CRED());
 402         return (err);
 403 }
 404 
 405 /*
 406  * This function intentionally does nothing.  It's used only to
 407  * force libfknsmb to load at program start so one can set
 408  * breakpoints etc. without debugger "force load" tricks.
 409  */
 410 void
 411 nsmb_drv_load(void)
 412 {
 413 }
 414 
 415 #endif  /* _KERNEL */
 416 
 417 /*ARGSUSED*/
 418 static int
 419 nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */
 420     cred_t *cr, int *rvalp)
 421 {
 422         smb_dev_t *sdp;
 423         int err;
 424 
 425         sdp = ddi_get_soft_state(statep, getminor(dev));
 426         if (sdp == NULL) {
 427                 return (EBADF);
 428         }
 429         if ((sdp->sd_flags & NSMBFL_OPEN) == 0) {
 430                 return (EBADF);
 431         }
 432 
 433         /*
 434          * Dont give access if the zone id is not as the same as we
 435          * set in the nsmb_open or dont belong to the global zone.
 436          * Check if the user belongs to this zone..
 437          */
 438         if (sdp->zoneid != getzoneid())
 439                 return (EIO);
 440 
 441         /*
 442          * We have a zone_shutdown call back that kills all the VCs
 443          * in a zone that's shutting down.  That action will cause
 444          * all of these ioctls to fail on such VCs, so no need to
 445          * check the zone status here on every ioctl call.
 446          */
 447 
 448         err = smb_usr_ioctl(sdp, cmd, arg, flags, cr);










 449 


























































































 450         return (err);
 451 }
 452 
 453 /*
 454  * This does "clone" open, meaning it automatically
 455  * assigns an available minor unit for each open.
 456  */
 457 /*ARGSUSED*/
 458 static int
 459 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
 460 {
 461         smb_dev_t *sdp;
 462         minor_t m;
 463 
 464         mutex_enter(&dev_lck);
 465 
 466         for (m = last_minor + 1; m != last_minor; m++) {
 467                 if (m > NSMB_MAX_MINOR)
 468                         m = NSMB_MIN_MINOR;
 469 


 473                 }
 474         }
 475 
 476         /* No available minor units. */
 477         mutex_exit(&dev_lck);
 478         return (ENXIO);
 479 
 480 found:
 481         /* NB: dev_lck still held */
 482         if (ddi_soft_state_zalloc(statep, m) == DDI_FAILURE) {
 483                 mutex_exit(&dev_lck);
 484                 return (ENXIO);
 485         }
 486         if ((sdp = ddi_get_soft_state(statep, m)) == NULL) {
 487                 mutex_exit(&dev_lck);
 488                 return (ENXIO);
 489         }
 490         *dev = makedevice(nsmb_major, m);
 491         mutex_exit(&dev_lck);
 492 

 493         sdp->sd_flags |= NSMBFL_OPEN;
 494         sdp->zoneid = crgetzoneid(cr);
 495         mutex_init(&sdp->sd_lock, NULL, MUTEX_DRIVER, NULL);
 496 
 497         return (0);
 498 }
 499 
 500 /*ARGSUSED*/
 501 static int
 502 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
 503 {
 504         minor_t inst = getminor(dev);
 505         smb_dev_t *sdp;
 506         int err;
 507 
 508         /*
 509          * 1. Check the validity of the minor number.
 510          * 2. Release any shares/vc associated  with the connection.
 511          * 3. Can close the minor number.
 512          * 4. Deallocate any resources allocated in open() call.
 513          */
 514 
 515         sdp = ddi_get_soft_state(statep, inst);
 516         if (sdp != NULL)
 517                 err = nsmb_close2(sdp, cr);
 518         else
 519                 err = ENXIO;
 520 
 521         /*
 522          * Free the instance
 523          */
 524         mutex_enter(&dev_lck);
 525         ddi_soft_state_free(statep, inst);
 526         mutex_exit(&dev_lck);
 527         return (err);
 528 }
 529 
 530 /*ARGSUSED*/
 531 static int
 532 nsmb_close2(smb_dev_t *sdp, cred_t *cr)
 533 {
 534         struct smb_vc *vcp;
 535         struct smb_share *ssp;
 536         struct smb_fh *fhp;
 537 
 538         fhp = sdp->sd_fh;
 539         if (fhp != NULL)
 540                 smb_fh_rele(fhp);
 541 
 542         ssp = sdp->sd_share;
 543         if (ssp != NULL)
 544                 smb_share_rele(ssp);
 545 
 546         vcp = sdp->sd_vc;
 547         if (vcp != NULL) {
 548                 /*
 549                  * If this dev minor was opened by smbiod,
 550                  * mark this VC as "dead" because it now
 551                  * will have no IOD to service it.
 552                  */
 553                 if (sdp->sd_flags & NSMBFL_IOD)
 554                         smb_iod_disconnect(vcp);
 555                 smb_vc_rele(vcp);
 556         }
 557         mutex_destroy(&sdp->sd_lock);
 558 
 559         return (0);
 560 }
 561 
 562 /*
 563  * Helper for SMBIOC_DUP_DEV
 564  * Duplicate state from the FD @arg ("from") onto
 565  * the FD for this device instance.
 566  */
 567 int
 568 smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
 569 {
 570 #ifdef  _KERNEL
 571         file_t *fp = NULL;
 572         vnode_t *vp;
 573 #endif  /* _KERNEL */
 574         smb_dev_t *from_sdp;
 575         dev_t dev;
 576         int32_t ufd;
 577         int err;
 578 
 579         /* Should be no VC */
 580         if (sdp->sd_vc != NULL)
 581                 return (EISCONN);
 582 
 583         /*
 584          * Get from_sdp (what we will duplicate)
 585          */
 586         if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
 587                 return (EFAULT);
 588 #ifdef  _KERNEL
 589         if ((fp = getf(ufd)) == NULL)
 590                 return (EBADF);
 591         /* rele fp below */
 592         vp = fp->f_vnode;
 593         dev = vp->v_rdev;
 594 #else   /* _KERNEL */
 595         /*
 596          * No getf(ufd) -- ufd is really a dev32_t
 597          */
 598         dev = expldev((dev32_t)ufd);
 599 #endif  /* _KERNEL */
 600         if (dev == 0 || dev == NODEV ||
 601             getmajor(dev) != nsmb_major) {
 602                 err = EINVAL;
 603                 goto out;
 604         }
 605 
 606         from_sdp = ddi_get_soft_state(statep, getminor(dev));
 607         if (from_sdp == NULL) {
 608                 err = EINVAL;
 609                 goto out;
 610         }
 611 
 612         /*
 613          * Duplicate VC and share references onto this FD.
 614          */
 615         if ((sdp->sd_vc = from_sdp->sd_vc) != NULL)
 616                 smb_vc_hold(sdp->sd_vc);
 617         if ((sdp->sd_share = from_sdp->sd_share) != NULL)
 618                 smb_share_hold(sdp->sd_share);
 619         sdp->sd_level = from_sdp->sd_level;
 620         err = 0;
 621 
 622 out:
 623 #ifdef  _KERNEL
 624         if (fp)
 625                 releasef(ufd);
 626 #endif  /* _KERNEL */
 627         return (err);
 628 }
 629 
 630 
 631 /*
 632  * Helper used by smbfs_mount
 633  */
 634 int
 635 smb_dev2share(int fd, struct smb_share **sspp)
 636 {
 637 #ifdef  _KERNEL
 638         file_t *fp = NULL;
 639         vnode_t *vp;
 640 #endif  /* _KERNEL */
 641         smb_dev_t *sdp;
 642         smb_share_t *ssp;
 643         dev_t dev;
 644         int err;
 645 
 646 #ifdef  _KERNEL
 647         if ((fp = getf(fd)) == NULL)
 648                 return (EBADF);
 649         /* rele fp below */

 650         vp = fp->f_vnode;
 651         dev = vp->v_rdev;
 652 #else   /* _KERNEL */
 653         /*
 654          * No getf(ufd) -- fd is really a dev32_t
 655          */
 656         dev = expldev((dev32_t)fd);
 657 #endif  /* _KERNEL */
 658         if (dev == 0 || dev == NODEV ||
 659             getmajor(dev) != nsmb_major) {
 660                 err = EINVAL;
 661                 goto out;
 662         }
 663 
 664         sdp = ddi_get_soft_state(statep, getminor(dev));
 665         if (sdp == NULL) {
 666                 err = EINVAL;
 667                 goto out;
 668         }
 669 
 670         ssp = sdp->sd_share;
 671         if (ssp == NULL) {
 672                 err = ENOTCONN;
 673                 goto out;
 674         }
 675 
 676         /*
 677          * Our caller gains a ref. to this share.
 678          */
 679         *sspp = ssp;
 680         smb_share_hold(ssp);
 681         err = 0;
 682 
 683 out:
 684 #ifdef  _KERNEL
 685         if (fp)
 686                 releasef(fd);
 687 #endif  /* _KERNEL */
 688         return (err);
 689 }