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 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)() */ 139 }; 140 141 /* 142 * Device options 143 */ 144 static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 145 static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 146 static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 147 void *arg, void **result); 148 149 static struct dev_ops nsmb_ops = { 150 DEVO_REV, /* devo_rev, */ 151 0, /* refcnt */ 152 nsmb_getinfo, /* info */ 153 nulldev, /* identify */ 154 nulldev, /* probe */ 155 nsmb_attach, /* attach */ 156 nsmb_detach, /* detach */ 157 nodev, /* reset */ 158 &nsmb_cbops, /* driver ops - devctl interfaces */ 159 NULL, /* bus operations */ 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 470 if (ddi_get_soft_state(statep, m) == NULL) { 471 last_minor = m; 472 goto found; 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 } 690