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 /* 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 471 if (ddi_get_soft_state(statep, m) == NULL) { 472 last_minor = m; 473 goto found; 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 } 667