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 * $Id: smb_dev.c,v 1.21 2004/12/13 00:25:18 lindak Exp $ 33 */ 34 35 /* 36 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 37 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 38 * Use is subject to license terms. 39 */ 40 41 #include <sys/types.h> 42 #include <sys/param.h> 43 #include <sys/errno.h> 44 #include <sys/sysmacros.h> 45 #include <sys/uio.h> 46 #include <sys/buf.h> 47 #include <sys/modctl.h> 48 #include <sys/open.h> 49 #include <sys/file.h> 50 #include <sys/kmem.h> 51 #include <sys/conf.h> 52 #include <sys/cmn_err.h> 53 #include <sys/stat.h> 54 #include <sys/ddi.h> 55 #include <sys/sunddi.h> 56 #include <sys/sunldi.h> 57 #include <sys/policy.h> 58 #include <sys/zone.h> 59 #include <sys/pathname.h> 60 #include <sys/mount.h> 61 #include <sys/sdt.h> 62 #include <fs/fs_subr.h> 63 #include <sys/modctl.h> 64 #include <sys/devops.h> 65 #include <sys/thread.h> 66 #include <sys/mkdev.h> 67 #include <sys/types.h> 68 #include <sys/zone.h> 69 70 #include <netsmb/smb_osdep.h> 71 #include <netsmb/mchain.h> /* for "htoles()" */ 72 73 #include <netsmb/smb.h> 74 #include <netsmb/smb_conn.h> 75 #include <netsmb/smb_subr.h> 76 #include <netsmb/smb_dev.h> 77 #include <netsmb/smb_pass.h> 78 79 /* for version checks */ 80 const uint32_t nsmb_version = NSMB_VERSION; 81 82 /* 83 * Userland code loops through minor #s 0 to 1023, looking for one which opens. 84 * Intially we create minor 0 and leave it for anyone. Minor zero will never 85 * actually get used - opening triggers creation of another (but private) minor, 86 * which userland code will get to and mark busy. 87 */ 88 #define SMBMINORS 1024 89 static void *statep; 90 static major_t nsmb_major; 91 static minor_t nsmb_minor = 1; 92 93 #define NSMB_MAX_MINOR (1 << 8) 94 #define NSMB_MIN_MINOR (NSMB_MAX_MINOR + 1) 95 96 #define ILP32 1 97 #define LP64 2 98 99 static kmutex_t dev_lck; 100 101 /* Zone support */ 102 zone_key_t nsmb_zone_key; 103 extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data); 104 extern void nsmb_zone_destroy(zoneid_t zoneid, void *data); 105 106 /* 107 * cb_ops device operations. 108 */ 109 static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp); 110 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp); 111 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 112 cred_t *credp, int *rvalp); 113 static int nsmb_close2(smb_dev_t *sdp, cred_t *cr); 114 115 /* smbfs cb_ops */ 116 static struct cb_ops nsmb_cbops = { 117 nsmb_open, /* open */ 118 nsmb_close, /* close */ 119 nodev, /* strategy */ 120 nodev, /* print */ 121 nodev, /* dump */ 122 nodev, /* read */ 123 nodev, /* write */ 124 nsmb_ioctl, /* ioctl */ 125 nodev, /* devmap */ 126 nodev, /* mmap */ 127 nodev, /* segmap */ 128 nochpoll, /* poll */ 129 ddi_prop_op, /* prop_op */ 130 NULL, /* stream */ 131 D_MP, /* cb_flag */ 132 CB_REV, /* rev */ 133 nodev, /* int (*cb_aread)() */ 134 nodev /* int (*cb_awrite)() */ 135 }; 136 137 /* 138 * Device options 139 */ 140 static int nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 141 static int nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 142 static int nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 143 void *arg, void **result); 144 145 static struct dev_ops nsmb_ops = { 146 DEVO_REV, /* devo_rev, */ 147 0, /* refcnt */ 148 nsmb_getinfo, /* info */ 149 nulldev, /* identify */ 150 nulldev, /* probe */ 151 nsmb_attach, /* attach */ 152 nsmb_detach, /* detach */ 153 nodev, /* reset */ 154 &nsmb_cbops, /* driver ops - devctl interfaces */ 155 NULL, /* bus operations */ 156 NULL, /* power */ 157 ddi_quiesce_not_needed, /* quiesce */ 158 }; 159 160 /* 161 * Module linkage information. 162 */ 163 164 static struct modldrv nsmb_modldrv = { 165 &mod_driverops, /* Driver module */ 166 "SMBFS network driver", 167 &nsmb_ops /* Driver ops */ 168 }; 169 170 static struct modlinkage nsmb_modlinkage = { 171 MODREV_1, 172 (void *)&nsmb_modldrv, 173 NULL 174 }; 175 176 int 177 _init(void) 178 { 179 int error; 180 181 (void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1); 182 183 /* Can initialize some mutexes also. */ 184 mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL); 185 /* 186 * Create a major name and number. 187 */ 188 nsmb_major = ddi_name_to_major(NSMB_NAME); 189 nsmb_minor = 0; 190 191 /* Connection data structures. */ 192 (void) smb_sm_init(); 193 194 /* Initialize password Key chain DB. */ 195 smb_pkey_init(); 196 197 /* Time conversion stuff. */ 198 smb_time_init(); 199 200 /* Initialize crypto mechanisms. */ 201 smb_crypto_mech_init(); 202 203 zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown, 204 nsmb_zone_destroy); 205 206 /* 207 * Install the module. Do this after other init, 208 * to prevent entrances before we're ready. 209 */ 210 if ((error = mod_install((&nsmb_modlinkage))) != 0) { 211 212 /* Same as 2nd half of _fini */ 213 (void) zone_key_delete(nsmb_zone_key); 214 smb_pkey_fini(); 215 smb_sm_done(); 216 mutex_destroy(&dev_lck); 217 ddi_soft_state_fini(&statep); 218 219 return (error); 220 } 221 222 return (0); 223 } 224 225 int 226 _fini(void) 227 { 228 int status; 229 230 /* 231 * Prevent unload if we have active VCs 232 * or stored passwords 233 */ 234 if ((status = smb_sm_idle()) != 0) 235 return (status); 236 if ((status = smb_pkey_idle()) != 0) 237 return (status); 238 239 /* 240 * Remove the module. Do this before destroying things, 241 * to prevent new entrances while we're destorying. 242 */ 243 if ((status = mod_remove(&nsmb_modlinkage)) != 0) { 244 return (status); 245 } 246 247 (void) zone_key_delete(nsmb_zone_key); 248 249 /* Time conversion stuff. */ 250 smb_time_fini(); 251 252 /* Destroy password Key chain DB. */ 253 smb_pkey_fini(); 254 255 smb_sm_done(); 256 257 mutex_destroy(&dev_lck); 258 ddi_soft_state_fini(&statep); 259 260 return (status); 261 } 262 263 int 264 _info(struct modinfo *modinfop) 265 { 266 return (mod_info(&nsmb_modlinkage, modinfop)); 267 } 268 269 /*ARGSUSED*/ 270 static int 271 nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 272 { 273 int ret = DDI_SUCCESS; 274 275 switch (cmd) { 276 case DDI_INFO_DEVT2DEVINFO: 277 *result = 0; 278 break; 279 case DDI_INFO_DEVT2INSTANCE: 280 *result = 0; 281 break; 282 default: 283 ret = DDI_FAILURE; 284 } 285 return (ret); 286 } 287 288 static int 289 nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 290 { 291 smb_dev_t *sdp; 292 293 if (cmd != DDI_ATTACH) 294 return (DDI_FAILURE); 295 /* 296 * only one instance - but we clone using the open routine 297 */ 298 if (ddi_get_instance(dip) > 0) 299 return (DDI_FAILURE); 300 301 mutex_enter(&dev_lck); 302 303 /* 304 * This is the Zero'th minor device which is created. 305 */ 306 if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) { 307 cmn_err(CE_WARN, "nsmb_attach: soft state alloc"); 308 goto attach_failed; 309 } 310 if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO, 311 NULL) == DDI_FAILURE) { 312 cmn_err(CE_WARN, "nsmb_attach: create minor"); 313 goto attach_failed; 314 } 315 if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) { 316 cmn_err(CE_WARN, "nsmb_attach: get soft state"); 317 ddi_remove_minor_node(dip, NULL); 318 goto attach_failed; 319 } 320 321 sdp->sd_dip = dip; 322 sdp->sd_seq = 0; 323 sdp->sd_smbfid = -1; 324 mutex_exit(&dev_lck); 325 ddi_report_dev(dip); 326 return (DDI_SUCCESS); 327 328 attach_failed: 329 ddi_soft_state_free(statep, 0); 330 mutex_exit(&dev_lck); 331 return (DDI_FAILURE); 332 } 333 334 /*ARGSUSED*/ 335 static int 336 nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 337 { 338 339 if (cmd != DDI_DETACH) 340 return (DDI_FAILURE); 341 if (ddi_get_instance(dip) > 0) 342 return (DDI_FAILURE); 343 344 ddi_soft_state_free(statep, 0); 345 ddi_remove_minor_node(dip, NULL); 346 347 return (DDI_SUCCESS); 348 } 349 350 /*ARGSUSED*/ 351 static int 352 nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */ 353 cred_t *cr, int *rvalp) 354 { 355 smb_dev_t *sdp; 356 int err; 357 358 sdp = ddi_get_soft_state(statep, getminor(dev)); 359 if (sdp == NULL) { 360 return (DDI_FAILURE); 361 } 362 if ((sdp->sd_flags & NSMBFL_OPEN) == 0) { 363 return (EBADF); 364 } 365 366 /* 367 * Dont give access if the zone id is not as the same as we 368 * set in the nsmb_open or dont belong to the global zone. 369 * Check if the user belongs to this zone.. 370 */ 371 if (sdp->zoneid != getzoneid()) 372 return (EIO); 373 374 /* 375 * We have a zone_shutdown call back that kills all the VCs 376 * in a zone that's shutting down. That action will cause 377 * all of these ioctls to fail on such VCs, so no need to 378 * check the zone status here on every ioctl call. 379 */ 380 381 err = 0; 382 switch (cmd) { 383 case SMBIOC_GETVERS: 384 (void) ddi_copyout(&nsmb_version, (void *)arg, 385 sizeof (nsmb_version), flags); 386 break; 387 388 case SMBIOC_FLAGS2: 389 err = smb_usr_get_flags2(sdp, arg, flags); 390 break; 391 392 case SMBIOC_GETSSNKEY: 393 err = smb_usr_get_ssnkey(sdp, arg, flags); 394 break; 395 396 case SMBIOC_DUP_DEV: 397 err = smb_usr_dup_dev(sdp, arg, flags); 398 break; 399 400 case SMBIOC_REQUEST: 401 err = smb_usr_simplerq(sdp, arg, flags, cr); 402 break; 403 404 case SMBIOC_T2RQ: 405 err = smb_usr_t2request(sdp, arg, flags, cr); 406 break; 407 408 case SMBIOC_READ: 409 case SMBIOC_WRITE: 410 err = smb_usr_rw(sdp, cmd, arg, flags, cr); 411 break; 412 413 case SMBIOC_NTCREATE: 414 err = smb_usr_ntcreate(sdp, arg, flags, cr); 415 break; 416 417 case SMBIOC_PRINTJOB: 418 err = smb_usr_printjob(sdp, arg, flags, cr); 419 break; 420 421 case SMBIOC_CLOSEFH: 422 err = smb_usr_closefh(sdp, cr); 423 break; 424 425 case SMBIOC_SSN_CREATE: 426 case SMBIOC_SSN_FIND: 427 err = smb_usr_get_ssn(sdp, cmd, arg, flags, cr); 428 break; 429 430 case SMBIOC_SSN_KILL: 431 case SMBIOC_SSN_RELE: 432 err = smb_usr_drop_ssn(sdp, cmd); 433 break; 434 435 case SMBIOC_TREE_CONNECT: 436 case SMBIOC_TREE_FIND: 437 err = smb_usr_get_tree(sdp, cmd, arg, flags, cr); 438 break; 439 440 case SMBIOC_TREE_KILL: 441 case SMBIOC_TREE_RELE: 442 err = smb_usr_drop_tree(sdp, cmd); 443 break; 444 445 case SMBIOC_IOD_WORK: 446 err = smb_usr_iod_work(sdp, arg, flags, cr); 447 break; 448 449 case SMBIOC_IOD_IDLE: 450 case SMBIOC_IOD_RCFAIL: 451 err = smb_usr_iod_ioctl(sdp, cmd, arg, flags); 452 break; 453 454 case SMBIOC_PK_ADD: 455 case SMBIOC_PK_DEL: 456 case SMBIOC_PK_CHK: 457 case SMBIOC_PK_DEL_OWNER: 458 case SMBIOC_PK_DEL_EVERYONE: 459 err = smb_pkey_ioctl(cmd, arg, flags, cr); 460 break; 461 462 default: 463 err = ENOTTY; 464 break; 465 } 466 467 return (err); 468 } 469 470 /*ARGSUSED*/ 471 static int 472 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr) 473 { 474 major_t new_major; 475 smb_dev_t *sdp, *sdv; 476 477 mutex_enter(&dev_lck); 478 for (; ; ) { 479 minor_t start = nsmb_minor; 480 do { 481 if (nsmb_minor >= MAXMIN32) { 482 if (nsmb_major == getmajor(*dev)) 483 nsmb_minor = NSMB_MIN_MINOR; 484 else 485 nsmb_minor = 0; 486 } else { 487 nsmb_minor++; 488 } 489 sdv = ddi_get_soft_state(statep, nsmb_minor); 490 } while ((sdv != NULL) && (nsmb_minor != start)); 491 if (nsmb_minor == start) { 492 /* 493 * The condition we need to solve here is all the 494 * MAXMIN32(~262000) minors numbers are reached. We 495 * need to create a new major number. 496 * zfs uses getudev() to create a new major number. 497 */ 498 if ((new_major = getudev()) == (major_t)-1) { 499 cmn_err(CE_WARN, 500 "nsmb: Can't get unique major " 501 "device number."); 502 mutex_exit(&dev_lck); 503 return (-1); 504 } 505 nsmb_major = new_major; 506 nsmb_minor = 0; 507 } else { 508 break; 509 } 510 } 511 512 /* 513 * This is called by mount or open call. 514 * The open() routine is passed a pointer to a device number so 515 * that the driver can change the minor number. This allows 516 * drivers to dynamically create minor instances of the dev- 517 * ice. An example of this might be a pseudo-terminal driver 518 * that creates a new pseudo-terminal whenever it is opened. 519 * A driver that chooses the minor number dynamically, normally 520 * creates only one minor device node in attach(9E) with 521 * ddi_create_minor_node(9F) then changes the minor number com- 522 * ponent of *devp using makedevice(9F) and getmajor(9F) The 523 * driver needs to keep track of available minor numbers inter- 524 * nally. 525 * Stuff the structure smb_dev. 526 * return. 527 */ 528 529 if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) { 530 mutex_exit(&dev_lck); 531 return (ENXIO); 532 } 533 if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) { 534 mutex_exit(&dev_lck); 535 return (ENXIO); 536 } 537 538 sdp->sd_seq = nsmb_minor; 539 sdp->sd_cred = cr; 540 sdp->sd_smbfid = -1; 541 sdp->sd_flags |= NSMBFL_OPEN; 542 sdp->zoneid = crgetzoneid(cr); 543 mutex_exit(&dev_lck); 544 545 *dev = makedevice(nsmb_major, nsmb_minor); 546 547 return (0); 548 } 549 550 /*ARGSUSED*/ 551 static int 552 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr) 553 { 554 minor_t inst = getminor(dev); 555 smb_dev_t *sdp; 556 int err; 557 558 mutex_enter(&dev_lck); 559 /* 560 * 1. Check the validity of the minor number. 561 * 2. Release any shares/vc associated with the connection. 562 * 3. Can close the minor number. 563 * 4. Deallocate any resources allocated in open() call. 564 */ 565 566 sdp = ddi_get_soft_state(statep, inst); 567 if (sdp != NULL) 568 err = nsmb_close2(sdp, cr); 569 else 570 err = ENXIO; 571 572 /* 573 * Free the instance 574 */ 575 ddi_soft_state_free(statep, inst); 576 mutex_exit(&dev_lck); 577 return (err); 578 } 579 580 static int 581 nsmb_close2(smb_dev_t *sdp, cred_t *cr) 582 { 583 struct smb_vc *vcp; 584 struct smb_share *ssp; 585 586 if (sdp->sd_smbfid != -1) 587 (void) smb_usr_closefh(sdp, cr); 588 589 ssp = sdp->sd_share; 590 if (ssp != NULL) 591 smb_share_rele(ssp); 592 593 vcp = sdp->sd_vc; 594 if (vcp != NULL) { 595 /* 596 * If this dev minor was opened by smbiod, 597 * mark this VC as "dead" because it now 598 * will have no IOD to service it. 599 */ 600 if (sdp->sd_flags & NSMBFL_IOD) 601 smb_iod_disconnect(vcp); 602 smb_vc_rele(vcp); 603 } 604 605 return (0); 606 } 607 608 /* 609 * Helper for SMBIOC_DUP_DEV 610 * Duplicate state from the FD @arg ("from") onto 611 * the FD for this device instance. 612 */ 613 int 614 smb_usr_dup_dev(smb_dev_t *sdp, intptr_t arg, int flags) 615 { 616 file_t *fp = NULL; 617 vnode_t *vp; 618 smb_dev_t *from_sdp; 619 dev_t dev; 620 int32_t ufd; 621 int err; 622 623 /* Should be no VC */ 624 if (sdp->sd_vc != NULL) 625 return (EISCONN); 626 627 /* 628 * Get from_sdp (what we will duplicate) 629 */ 630 if (ddi_copyin((void *) arg, &ufd, sizeof (ufd), flags)) 631 return (EFAULT); 632 if ((fp = getf(ufd)) == NULL) 633 return (EBADF); 634 /* rele fp below */ 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 from_sdp = ddi_get_soft_state(statep, getminor(dev)); 643 if (from_sdp == NULL) { 644 err = EINVAL; 645 goto out; 646 } 647 648 /* 649 * Duplicate VC and share references onto this FD. 650 */ 651 if ((sdp->sd_vc = from_sdp->sd_vc) != NULL) 652 smb_vc_hold(sdp->sd_vc); 653 if ((sdp->sd_share = from_sdp->sd_share) != NULL) 654 smb_share_hold(sdp->sd_share); 655 sdp->sd_level = from_sdp->sd_level; 656 err = 0; 657 658 out: 659 if (fp) 660 releasef(ufd); 661 return (err); 662 } 663 664 665 /* 666 * Helper used by smbfs_mount 667 */ 668 int 669 smb_dev2share(int fd, struct smb_share **sspp) 670 { 671 file_t *fp = NULL; 672 vnode_t *vp; 673 smb_dev_t *sdp; 674 smb_share_t *ssp; 675 dev_t dev; 676 int err; 677 678 if ((fp = getf(fd)) == NULL) 679 return (EBADF); 680 /* rele fp below */ 681 682 vp = fp->f_vnode; 683 dev = vp->v_rdev; 684 if (dev == 0 || dev == NODEV || 685 getmajor(dev) != nsmb_major) { 686 err = EINVAL; 687 goto out; 688 } 689 690 sdp = ddi_get_soft_state(statep, getminor(dev)); 691 if (sdp == NULL) { 692 err = EINVAL; 693 goto out; 694 } 695 696 ssp = sdp->sd_share; 697 if (ssp == NULL) { 698 err = ENOTCONN; 699 goto out; 700 } 701 702 /* 703 * Our caller gains a ref. to this share. 704 */ 705 *sspp = ssp; 706 smb_share_hold(ssp); 707 err = 0; 708 709 out: 710 if (fp) 711 releasef(fd); 712 return (err); 713 } 714