1 /*
   2  * Copyright (c) 2000-2001 Boris Popov
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. All advertising materials mentioning features or use of this software
  14  *    must display the following acknowledgement:
  15  *    This product includes software developed by Boris Popov.
  16  * 4. Neither the name of the author nor the names of any co-contributors
  17  *    may be used to endorse or promote products derived from this software
  18  *    without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30  * SUCH DAMAGE.
  31  */
  32 
  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)() */
 122 };
 123 
 124 /*
 125  * Device options
 126  */
 127 static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
 128 static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
 129 static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
 130         void *arg, void **result);
 131 
 132 static struct dev_ops nsmb_ops = {
 133         DEVO_REV,       /* devo_rev, */
 134         0,              /* refcnt  */
 135         nsmb_getinfo,   /* info */
 136         nulldev,        /* identify */
 137         nulldev,        /* probe */
 138         nsmb_attach,    /* attach */
 139         nsmb_detach,    /* detach */
 140         nodev,          /* reset */
 141         &nsmb_cbops,        /* driver ops - devctl interfaces */
 142         NULL,           /* bus operations */
 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         err = 0;
 350         switch (cmd) {
 351         case SMBIOC_GETVERS:
 352                 (void) ddi_copyout(&nsmb_version, (void *)arg,
 353                     sizeof (nsmb_version), flags);
 354                 break;
 355 
 356         case SMBIOC_FLAGS2:
 357                 err = smb_usr_get_flags2(sdp, arg, flags);
 358                 break;
 359 
 360         case SMBIOC_GETSSNKEY:
 361                 err = smb_usr_get_ssnkey(sdp, arg, flags);
 362                 break;
 363 
 364         case SMBIOC_DUP_DEV:
 365                 err = smb_usr_dup_dev(sdp, arg, flags);
 366                 break;
 367 
 368         case SMBIOC_REQUEST:
 369                 err = smb_usr_simplerq(sdp, arg, flags, cr);
 370                 break;
 371 
 372         case SMBIOC_T2RQ:
 373                 err = smb_usr_t2request(sdp, arg, flags, cr);
 374                 break;
 375 
 376         case SMBIOC_READ:
 377         case SMBIOC_WRITE:
 378                 err = smb_usr_rw(sdp, cmd, arg, flags, cr);
 379                 break;
 380 
 381         case SMBIOC_NTCREATE:
 382                 err = smb_usr_ntcreate(sdp, arg, flags, cr);
 383                 break;
 384 
 385         case SMBIOC_PRINTJOB:
 386                 err = smb_usr_printjob(sdp, arg, flags, cr);
 387                 break;
 388 
 389         case SMBIOC_CLOSEFH:
 390                 err = smb_usr_closefh(sdp, cr);
 391                 break;
 392 
 393         case SMBIOC_SSN_CREATE:
 394         case SMBIOC_SSN_FIND:
 395                 err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr);
 396                 break;
 397 
 398         case SMBIOC_SSN_KILL:
 399         case SMBIOC_SSN_RELE:
 400                 err = smb_usr_drop_ssn(sdp, cmd);
 401                 break;
 402 
 403         case SMBIOC_TREE_CONNECT:
 404         case SMBIOC_TREE_FIND:
 405                 err = smb_usr_get_tree(sdp, cmd, arg, flags, cr);
 406                 break;
 407 
 408         case SMBIOC_TREE_KILL:
 409         case SMBIOC_TREE_RELE:
 410                 err = smb_usr_drop_tree(sdp, cmd);
 411                 break;
 412 
 413         case SMBIOC_IOD_WORK:
 414                 err = smb_usr_iod_work(sdp, arg, flags, cr);
 415                 break;
 416 
 417         case SMBIOC_IOD_IDLE:
 418         case SMBIOC_IOD_RCFAIL:
 419                 err = smb_usr_iod_ioctl(sdp, cmd, arg, flags);
 420                 break;
 421 
 422         case SMBIOC_PK_ADD:
 423         case SMBIOC_PK_DEL:
 424         case SMBIOC_PK_CHK:
 425         case SMBIOC_PK_DEL_OWNER:
 426         case SMBIOC_PK_DEL_EVERYONE:
 427                 err = smb_pkey_ioctl(cmd, arg, flags, cr);
 428                 break;
 429 
 430         default:
 431                 err = ENOTTY;
 432                 break;
 433         }
 434 
 435         return (err);
 436 }
 437 
 438 /*
 439  * This does "clone" open, meaning it automatically
 440  * assigns an available minor unit for each open.
 441  */
 442 /*ARGSUSED*/
 443 static int
 444 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr)
 445 {
 446         smb_dev_t *sdp;
 447         minor_t m;
 448 
 449         mutex_enter(&dev_lck);
 450 
 451         for (m = last_minor + 1; m != last_minor; m++) {
 452                 if (m > NSMB_MAX_MINOR)
 453                         m = NSMB_MIN_MINOR;
 454 
 455                 if (ddi_get_soft_state(statep, m) == NULL) {
 456                         last_minor = m;
 457                         goto found;
 458                 }
 459         }
 460 
 461         /* No available minor units. */
 462         mutex_exit(&dev_lck);
 463         return (ENXIO);
 464 
 465 found:
 466         /* NB: dev_lck still held */
 467         if (ddi_soft_state_zalloc(statep, m) == DDI_FAILURE) {
 468                 mutex_exit(&dev_lck);
 469                 return (ENXIO);
 470         }
 471         if ((sdp = ddi_get_soft_state(statep, m)) == NULL) {
 472                 mutex_exit(&dev_lck);
 473                 return (ENXIO);
 474         }
 475         *dev = makedevice(nsmb_major, m);
 476         mutex_exit(&dev_lck);
 477 
 478         sdp->sd_cred = cr;
 479         sdp->sd_smbfid = -1;
 480         sdp->sd_flags |= NSMBFL_OPEN;
 481         sdp->zoneid = crgetzoneid(cr);
 482 
 483         return (0);
 484 }
 485 
 486 /*ARGSUSED*/
 487 static int
 488 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr)
 489 {
 490         minor_t inst = getminor(dev);
 491         smb_dev_t *sdp;
 492         int err;
 493 
 494         /*
 495          * 1. Check the validity of the minor number.
 496          * 2. Release any shares/vc associated  with the connection.
 497          * 3. Can close the minor number.
 498          * 4. Deallocate any resources allocated in open() call.
 499          */
 500 
 501         sdp = ddi_get_soft_state(statep, inst);
 502         if (sdp != NULL)
 503                 err = nsmb_close2(sdp, cr);
 504         else
 505                 err = ENXIO;
 506 
 507         /*
 508          * Free the instance
 509          */
 510         mutex_enter(&dev_lck);
 511         ddi_soft_state_free(statep, inst);
 512         mutex_exit(&dev_lck);
 513         return (err);
 514 }
 515 
 516 static int
 517 nsmb_close2(smb_dev_t *sdp, cred_t *cr)
 518 {
 519         struct smb_vc *vcp;
 520         struct smb_share *ssp;
 521 
 522         if (sdp->sd_smbfid != -1)
 523                 (void) smb_usr_closefh(sdp, cr);
 524 
 525         ssp = sdp->sd_share;
 526         if (ssp != NULL)
 527                 smb_share_rele(ssp);
 528 
 529         vcp = sdp->sd_vc;
 530         if (vcp != NULL) {
 531                 /*
 532                  * If this dev minor was opened by smbiod,
 533                  * mark this VC as "dead" because it now
 534                  * will have no IOD to service it.
 535                  */
 536                 if (sdp->sd_flags & NSMBFL_IOD)
 537                         smb_iod_disconnect(vcp);
 538                 smb_vc_rele(vcp);
 539         }
 540 
 541         return (0);
 542 }
 543 
 544 /*
 545  * Helper for SMBIOC_DUP_DEV
 546  * Duplicate state from the FD @arg ("from") onto
 547  * the FD for this device instance.
 548  */
 549 int
 550 smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags)
 551 {
 552         file_t *fp = NULL;
 553         vnode_t *vp;
 554         smb_dev_t *from_sdp;
 555         dev_t dev;
 556         int32_t ufd;
 557         int err;
 558 
 559         /* Should be no VC */
 560         if (sdp->sd_vc != NULL)
 561                 return (EISCONN);
 562 
 563         /*
 564          * Get from_sdp (what we will duplicate)
 565          */
 566         if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags))
 567                 return (EFAULT);
 568         if ((fp = getf(ufd)) == NULL)
 569                 return (EBADF);
 570         /* rele fp below */
 571         vp = fp->f_vnode;
 572         dev = vp->v_rdev;
 573         if (dev == 0 || dev == NODEV ||
 574             getmajor(dev) != nsmb_major) {
 575                 err = EINVAL;
 576                 goto out;
 577         }
 578         from_sdp = ddi_get_soft_state(statep, getminor(dev));
 579         if (from_sdp == NULL) {
 580                 err = EINVAL;
 581                 goto out;
 582         }
 583 
 584         /*
 585          * Duplicate VC and share references onto this FD.
 586          */
 587         if ((sdp->sd_vc = from_sdp->sd_vc) != NULL)
 588                 smb_vc_hold(sdp->sd_vc);
 589         if ((sdp->sd_share = from_sdp->sd_share) != NULL)
 590                 smb_share_hold(sdp->sd_share);
 591         sdp->sd_level = from_sdp->sd_level;
 592         err = 0;
 593 
 594 out:
 595         if (fp)
 596                 releasef(ufd);
 597         return (err);
 598 }
 599 
 600 
 601 /*
 602  * Helper used by smbfs_mount
 603  */
 604 int
 605 smb_dev2share(int fd, struct smb_share **sspp)
 606 {
 607         file_t *fp = NULL;
 608         vnode_t *vp;
 609         smb_dev_t *sdp;
 610         smb_share_t *ssp;
 611         dev_t dev;
 612         int err;
 613 
 614         if ((fp = getf(fd)) == NULL)
 615                 return (EBADF);
 616         /* rele fp below */
 617 
 618         vp = fp->f_vnode;
 619         dev = vp->v_rdev;
 620         if (dev == 0 || dev == NODEV ||
 621             getmajor(dev) != nsmb_major) {
 622                 err = EINVAL;
 623                 goto out;
 624         }
 625 
 626         sdp = ddi_get_soft_state(statep, getminor(dev));
 627         if (sdp == NULL) {
 628                 err = EINVAL;
 629                 goto out;
 630         }
 631 
 632         ssp = sdp->sd_share;
 633         if (ssp == NULL) {
 634                 err = ENOTCONN;
 635                 goto out;
 636         }
 637 
 638         /*
 639          * Our caller gains a ref. to this share.
 640          */
 641         *sspp = ssp;
 642         smb_share_hold(ssp);
 643         err = 0;
 644 
 645 out:
 646         if (fp)
 647                 releasef(fd);
 648         return (err);
 649 }