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 2008 Sun Microsystems, Inc. All rights reserved. 37 * Use is subject to license terms. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 #include <sys/types.h> 43 #include <sys/param.h> 44 #include <sys/errno.h> 45 #include <sys/sysmacros.h> 46 #include <sys/uio.h> 47 #include <sys/buf.h> 48 #include <sys/modctl.h> 49 #include <sys/open.h> 50 #include <sys/file.h> 51 #include <sys/kmem.h> 52 #include <sys/conf.h> 53 #include <sys/cmn_err.h> 54 #include <sys/stat.h> 55 #include <sys/ddi.h> 56 #include <sys/sunddi.h> 57 #include <sys/sunldi.h> 58 #include <sys/policy.h> 59 #include <sys/zone.h> 60 #include <sys/pathname.h> 61 #include <sys/mount.h> 62 #include <sys/sdt.h> 63 #include <fs/fs_subr.h> 64 #include <sys/modctl.h> 65 #include <sys/devops.h> 66 #include <sys/thread.h> 67 #include <sys/mkdev.h> 68 #include <sys/types.h> 69 #include <sys/zone.h> 70 71 #ifdef APPLE 72 #include <sys/smb_apple.h> 73 #else 74 #include <netsmb/smb_osdep.h> 75 #endif 76 77 #include <netsmb/mchain.h> /* for "htoles()" */ 78 79 #include <netsmb/smb.h> 80 #include <netsmb/smb_conn.h> 81 #include <netsmb/smb_subr.h> 82 #include <netsmb/smb_dev.h> 83 #include <netsmb/smb_pass.h> 84 85 /* for version checks */ 86 const uint32_t nsmb_version = NSMB_VERSION; 87 88 /* 89 * Userland code loops through minor #s 0 to 1023, looking for one which opens. 90 * Intially we create minor 0 and leave it for anyone. Minor zero will never 91 * actually get used - opening triggers creation of another (but private) minor, 92 * which userland code will get to and mark busy. 93 */ 94 #define SMBMINORS 1024 95 static void *statep; 96 static major_t nsmb_major; 97 static minor_t nsmb_minor = 1; 98 99 #define NSMB_MAX_MINOR (1 << 8) 100 #define NSMB_MIN_MINOR (NSMB_MAX_MINOR + 1) 101 102 #define ILP32 1 103 #define LP64 2 104 105 static kmutex_t dev_lck; 106 107 /* Zone support */ 108 zone_key_t nsmb_zone_key; 109 extern void nsmb_zone_shutdown(zoneid_t zoneid, void *data); 110 extern void nsmb_zone_destroy(zoneid_t zoneid, void *data); 111 112 /* 113 * cb_ops device operations. 114 */ 115 static int nsmb_open(dev_t *devp, int flag, int otyp, cred_t *credp); 116 static int nsmb_close(dev_t dev, int flag, int otyp, cred_t *credp); 117 static int nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 118 cred_t *credp, int *rvalp); 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 }; 162 163 /* 164 * Module linkage information. 165 */ 166 167 static struct modldrv nsmb_modldrv = { 168 &mod_driverops, /* Driver module */ 169 "SMBFS network driver v" NSMB_VER_STR, 170 &nsmb_ops /* Driver ops */ 171 }; 172 173 static struct modlinkage nsmb_modlinkage = { 174 MODREV_1, 175 (void *)&nsmb_modldrv, 176 NULL 177 }; 178 179 int 180 _init(void) 181 { 182 int error; 183 184 ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1); 185 186 /* Can initialize some mutexes also. */ 187 mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL); 188 /* 189 * Create a major name and number. 190 */ 191 nsmb_major = ddi_name_to_major(NSMB_NAME); 192 nsmb_minor = 0; 193 194 /* Connection data structures. */ 195 (void) smb_sm_init(); 196 197 /* Initialize password Key chain DB. */ 198 smb_pkey_init(); 199 200 zone_key_create(&nsmb_zone_key, NULL, nsmb_zone_shutdown, 201 nsmb_zone_destroy); 202 203 /* 204 * Install the module. Do this after other init, 205 * to prevent entrances before we're ready. 206 */ 207 if ((error = mod_install((&nsmb_modlinkage))) != 0) { 208 209 /* Same as 2nd half of _fini */ 210 (void) zone_key_delete(nsmb_zone_key); 211 smb_pkey_fini(); 212 smb_sm_done(); 213 mutex_destroy(&dev_lck); 214 ddi_soft_state_fini(&statep); 215 216 return (error); 217 } 218 219 return (0); 220 } 221 222 int 223 _fini(void) 224 { 225 int status; 226 227 /* 228 * Prevent unload if we have active VCs 229 * or stored passwords 230 */ 231 if ((status = smb_sm_idle()) != 0) 232 return (status); 233 if ((status = smb_pkey_idle()) != 0) 234 return (status); 235 236 /* 237 * Remove the module. Do this before destroying things, 238 * to prevent new entrances while we're destorying. 239 */ 240 if ((status = mod_remove(&nsmb_modlinkage)) != 0) { 241 return (status); 242 } 243 244 (void) zone_key_delete(nsmb_zone_key); 245 246 /* Destroy password Key chain DB. */ 247 smb_pkey_fini(); 248 249 smb_sm_done(); 250 251 mutex_destroy(&dev_lck); 252 ddi_soft_state_fini(&statep); 253 254 return (status); 255 } 256 257 int 258 _info(struct modinfo *modinfop) 259 { 260 return (mod_info(&nsmb_modlinkage, modinfop)); 261 } 262 263 /*ARGSUSED*/ 264 static int 265 nsmb_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 266 { 267 int ret = DDI_SUCCESS; 268 269 switch (cmd) { 270 case DDI_INFO_DEVT2DEVINFO: 271 *result = 0; 272 break; 273 case DDI_INFO_DEVT2INSTANCE: 274 *result = 0; 275 break; 276 default: 277 ret = DDI_FAILURE; 278 } 279 return (ret); 280 } 281 282 static int 283 nsmb_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 284 { 285 smb_dev_t *sdp; 286 287 if (cmd != DDI_ATTACH) 288 return (DDI_FAILURE); 289 /* 290 * only one instance - but we clone using the open routine 291 */ 292 if (ddi_get_instance(dip) > 0) 293 return (DDI_FAILURE); 294 295 mutex_enter(&dev_lck); 296 297 /* 298 * This is the Zero'th minor device which is created. 299 */ 300 if (ddi_soft_state_zalloc(statep, 0) == DDI_FAILURE) { 301 cmn_err(CE_WARN, "nsmb_attach: soft state alloc"); 302 goto attach_failed; 303 } 304 if (ddi_create_minor_node(dip, "nsmb", S_IFCHR, 0, DDI_PSEUDO, 305 NULL) == DDI_FAILURE) { 306 cmn_err(CE_WARN, "nsmb_attach: create minor"); 307 goto attach_failed; 308 } 309 if ((sdp = ddi_get_soft_state(statep, 0)) == NULL) { 310 cmn_err(CE_WARN, "nsmb_attach: get soft state"); 311 ddi_remove_minor_node(dip, NULL); 312 goto attach_failed; 313 } 314 315 /* 316 * Need to see if this field is required. 317 * REVISIT 318 */ 319 sdp->smb_dip = dip; 320 sdp->sd_seq = 0; 321 sdp->sd_opened = 1; 322 323 mutex_exit(&dev_lck); 324 ddi_report_dev(dip); 325 return (DDI_SUCCESS); 326 327 attach_failed: 328 ddi_soft_state_free(statep, 0); 329 mutex_exit(&dev_lck); 330 return (DDI_FAILURE); 331 } 332 333 /*ARGSUSED*/ 334 static int 335 nsmb_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 336 { 337 338 if (cmd != DDI_DETACH) 339 return (DDI_FAILURE); 340 if (ddi_get_instance(dip) > 0) 341 return (DDI_FAILURE); 342 343 ddi_soft_state_free(statep, 0); 344 ddi_remove_minor_node(dip, NULL); 345 346 return (DDI_SUCCESS); 347 } 348 349 /*ARGSUSED*/ 350 static int 351 nsmb_ioctl(dev_t dev, 352 int cmd, 353 intptr_t arg, 354 int mode, 355 cred_t *credp, 356 int *rvalp) 357 { 358 smb_dev_t *sdp; 359 struct smb_vc *vcp = NULL; 360 struct smb_share *ssp = NULL; 361 struct smb_cred scred; 362 int err, error; 363 uid_t uid; 364 365 /* Free any+all of these at end of switch. */ 366 smbioc_lookup_t *sioc = NULL; 367 smbioc_rq_t *srq = NULL; 368 smbioc_rw_t *rwrq = NULL; 369 smbioc_t2rq_t *strq = NULL; 370 smbioc_pk_t *pk = NULL; 371 372 sdp = ddi_get_soft_state(statep, getminor(dev)); 373 if (sdp == NULL) { 374 return (DDI_FAILURE); 375 } 376 if ((sdp->sd_flags & NSMBFL_OPEN) == 0) { 377 return (EBADF); 378 } 379 380 /* 381 * Dont give access if the zone id is not as the same as we 382 * set in the nsmb_open or dont belong to the global zone. 383 * Check if the user belongs to this zone.. 384 */ 385 if (sdp->zoneid != getzoneid()) 386 return (EIO); 387 if (cmd != SMBIOC_TDIS && 388 zone_status_get(curproc->p_zone) >= ZONE_IS_SHUTTING_DOWN) 389 return (EIO); 390 391 392 error = 0; 393 smb_credinit(&scred, curproc, credp); 394 switch (cmd) { 395 case SMBIOC_GETVERS: 396 ddi_copyout(&nsmb_version, (void *)arg, 397 sizeof (nsmb_version), mode); 398 break; 399 400 case SMBIOC_REQUEST: 401 if (sdp->sd_share == NULL) { 402 error = ENOTCONN; 403 break; 404 } 405 srq = kmem_alloc(sizeof (*srq), KM_SLEEP); 406 if (ddi_copyin((void *) arg, srq, 407 sizeof (*srq), mode)) { 408 error = EFAULT; 409 break; 410 } 411 error = smb_usr_simplerequest(sdp->sd_share, 412 srq, &scred); 413 ddi_copyout(srq, (void *)arg, 414 SMBIOC_RQ_COPYOUT_SIZE, mode); 415 break; 416 417 case SMBIOC_T2RQ: 418 if (sdp->sd_share == NULL) { 419 error = ENOTCONN; 420 break; 421 } 422 strq = kmem_alloc(sizeof (*strq), KM_SLEEP); 423 if (ddi_copyin((void *)arg, strq, 424 sizeof (*strq), mode)) { 425 error = EFAULT; 426 break; 427 } 428 error = smb_usr_t2request(sdp->sd_share, strq, &scred); 429 ddi_copyout(strq, (void *)arg, 430 SMBIOC_T2RQ_COPYOUT_SIZE, mode); 431 break; 432 433 case SMBIOC_READ: 434 case SMBIOC_WRITE: 435 if ((ssp = sdp->sd_share) == NULL) { 436 error = ENOTCONN; 437 break; 438 } 439 rwrq = kmem_alloc(sizeof (*rwrq), KM_SLEEP); 440 if (ddi_copyin((void *)arg, rwrq, 441 sizeof (*rwrq), mode)) { 442 error = EFAULT; 443 break; 444 } 445 error = smb_usr_rw(ssp, rwrq, cmd, &scred); 446 ddi_copyout(rwrq, (void *)arg, 447 SMBIOC_RW_COPYOUT_SIZE, mode); 448 break; 449 450 case SMBIOC_NEGOTIATE: 451 /* Should be no VC (and no share) */ 452 if (sdp->sd_vc || sdp->sd_share) { 453 error = EISCONN; 454 break; 455 } 456 sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); 457 if (ddi_copyin((void *)arg, sioc, 458 sizeof (*sioc), mode)) { 459 error = EFAULT; 460 break; 461 } 462 vcp = NULL; 463 ssp = NULL; 464 error = smb_usr_negotiate(sioc, &scred, &vcp); 465 if (error) 466 break; 467 if (vcp) { 468 /* 469 * The VC has a hold from _negotiate 470 * which we keep until nsmb_close(). 471 */ 472 sdp->sd_level = SMBL_VC; 473 sdp->sd_vc = vcp; 474 /* 475 * If we just created this VC, and 476 * this minor is doing the setup, 477 * keep track of that fact here. 478 */ 479 if (vcp->vc_state < SMBIOD_ST_VCACTIVE) 480 sdp->sd_flags |= NSMBFL_NEWVC; 481 482 } 483 /* 484 * Copyout the "out token" (security blob). 485 * 486 * This code used to be near the end of 487 * smb_usr_negotiate(). Moved the copyout 488 * calls here so we know the "mode" 489 */ 490 if (vcp->vc_outtok) { 491 /* 492 * Note: will copyout sioc below 493 * including sioc.vc_outtoklen, 494 * so we no longer put the length 495 * at the start of the outtok data. 496 */ 497 sioc->ioc_ssn.ioc_outtoklen = 498 vcp->vc_outtoklen; 499 err = ddi_copyout( 500 vcp->vc_outtok, 501 sioc->ioc_ssn.ioc_outtok, 502 vcp->vc_outtoklen, mode); 503 if (err) { 504 error = EFAULT; 505 break; 506 } 507 /* 508 * Save this blob in vc_negtok. 509 * We need it in case we have to 510 * reconnect. 511 * 512 * Set vc_negtok = vc_outtok 513 * but free vc_negtok first. 514 */ 515 if (vcp->vc_negtok) { 516 kmem_free( 517 vcp->vc_negtok, 518 vcp->vc_negtoklen); 519 vcp->vc_negtok = NULL; 520 vcp->vc_negtoklen = 0; 521 } 522 vcp->vc_negtok = vcp->vc_outtok; 523 vcp->vc_negtoklen = vcp->vc_outtoklen; 524 vcp->vc_outtok = NULL; 525 vcp->vc_outtoklen = 0; 526 } 527 /* 528 * Added copyout here of (almost) 529 * the whole struct, even though 530 * the lib only needs _outtoklen. 531 * We may put other things in this 532 * struct that user-land needs. 533 */ 534 err = ddi_copyout(sioc, (void *)arg, 535 SMBIOC_LOOK_COPYOUT_SIZE, mode); 536 if (err) 537 error = EFAULT; 538 break; 539 540 case SMBIOC_SSNSETUP: 541 /* Must have a VC, but no share. */ 542 if (sdp->sd_share) { 543 error = EISCONN; 544 break; 545 } 546 if (!sdp->sd_vc) { 547 error = ENOTCONN; 548 break; 549 } 550 sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); 551 if (ddi_copyin((void *)arg, sioc, 552 sizeof (*sioc), mode)) { 553 error = EFAULT; 554 break; 555 } 556 vcp = sdp->sd_vc; 557 ssp = NULL; 558 error = smb_usr_ssnsetup(sioc, &scred, vcp); 559 if (error) 560 break; 561 /* 562 * If this minor has finished ssn setup, 563 * turn off the NEWVC flag, otherwise we 564 * will kill this VC when we close. 565 */ 566 if (vcp->vc_state == SMBIOD_ST_VCACTIVE) 567 sdp->sd_flags &= ~NSMBFL_NEWVC; 568 /* 569 * Copyout the "out token" (security blob). 570 * 571 * This code used to be near the end of 572 * smb_usr_ssnsetup(). Moved the copyout 573 * calls here so we know the "mode" 574 */ 575 if (vcp->vc_outtok) { 576 /* 577 * Note: will copyout sioc below 578 * including sioc.vc_outtoklen, 579 * so we no longer put the length 580 * at the start of the outtok data. 581 */ 582 sioc->ioc_ssn.ioc_outtoklen = 583 vcp->vc_outtoklen; 584 err = ddi_copyout( 585 vcp->vc_outtok, 586 sioc->ioc_ssn.ioc_outtok, 587 vcp->vc_outtoklen, mode); 588 if (err) { 589 error = EFAULT; 590 break; 591 } 592 /* 593 * Done with vc_outtok. Similar, 594 * but NOT the same as after the 595 * smb_usr_negotiate call above. 596 */ 597 kmem_free( 598 vcp->vc_outtok, 599 vcp->vc_outtoklen); 600 vcp->vc_outtok = NULL; 601 vcp->vc_outtoklen = 0; 602 } 603 /* Added copyout here... (see above) */ 604 err = ddi_copyout(sioc, (void *)arg, 605 SMBIOC_LOOK_COPYOUT_SIZE, mode); 606 if (err) 607 error = EFAULT; 608 break; 609 610 case SMBIOC_TCON: 611 /* Must have a VC, but no share. */ 612 if (sdp->sd_share) { 613 error = EISCONN; 614 break; 615 } 616 if (!sdp->sd_vc) { 617 error = ENOTCONN; 618 break; 619 } 620 sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); 621 if (ddi_copyin((void *)arg, sioc, 622 sizeof (*sioc), mode)) { 623 error = EFAULT; 624 break; 625 } 626 vcp = sdp->sd_vc; 627 ssp = NULL; 628 error = smb_usr_tcon(sioc, &scred, vcp, &ssp); 629 if (error) 630 break; 631 if (ssp) { 632 /* 633 * The share has a hold from _tcon 634 * which we keep until nsmb_close() 635 * or the SMBIOC_TDIS below. 636 */ 637 sdp->sd_share = ssp; 638 sdp->sd_level = SMBL_SHARE; 639 } 640 /* No need for copyout here. */ 641 break; 642 643 case SMBIOC_TDIS: 644 if (sdp->sd_share == NULL) { 645 error = ENOTCONN; 646 break; 647 } 648 smb_share_rele(sdp->sd_share); 649 sdp->sd_share = NULL; 650 sdp->sd_level = SMBL_VC; 651 break; 652 case SMBIOC_FLAGS2: 653 if (sdp->sd_share == NULL) { 654 error = ENOTCONN; 655 break; 656 } 657 if (!sdp->sd_vc) { 658 error = ENOTCONN; 659 break; 660 } 661 vcp = sdp->sd_vc; 662 /* 663 * Return the flags2 value. 664 */ 665 ddi_copyout(&vcp->vc_hflags2, (void *)arg, 666 sizeof (u_int16_t), mode); 667 break; 668 669 case SMBIOC_PK_ADD: 670 pk = kmem_alloc(sizeof (*pk), KM_SLEEP); 671 if (ddi_copyin((void *)arg, pk, 672 sizeof (*pk), mode)) { 673 error = EFAULT; 674 break; 675 } 676 error = smb_pkey_add(pk, credp); 677 break; 678 679 case SMBIOC_PK_DEL: 680 pk = kmem_alloc(sizeof (*pk), KM_SLEEP); 681 if (ddi_copyin((void *)arg, pk, 682 sizeof (*pk), mode)) { 683 error = EFAULT; 684 break; 685 } 686 error = smb_pkey_del(pk, credp); 687 break; 688 689 case SMBIOC_PK_CHK: 690 pk = kmem_alloc(sizeof (*pk), KM_SLEEP); 691 if (ddi_copyin((void *)arg, pk, 692 sizeof (*pk), mode)) { 693 error = EFAULT; 694 break; 695 } 696 error = smb_pkey_check(pk, credp); 697 /* 698 * Note: Intentionally DO NOT copyout 699 * the pasword here. It can only be 700 * retrieved by internal calls. This 701 * ioctl only tells the caller if the 702 * keychain entry exists. 703 */ 704 break; 705 706 case SMBIOC_PK_DEL_OWNER: 707 uid = crgetruid(credp); 708 error = smb_pkey_deluid(uid, credp); 709 break; 710 711 case SMBIOC_PK_DEL_EVERYONE: 712 uid = (uid_t)-1; 713 error = smb_pkey_deluid(uid, credp); 714 break; 715 716 default: 717 error = ENODEV; 718 } 719 720 /* 721 * Let's just do all the kmem_free stuff HERE, 722 * instead of at every switch break. 723 */ 724 725 /* SMBIOC_REQUEST */ 726 if (srq) 727 kmem_free(srq, sizeof (*srq)); 728 729 /* SMBIOC_T2RQ */ 730 if (strq) 731 kmem_free(strq, sizeof (*strq)); 732 733 /* SMBIOC_READ */ 734 /* SMBIOC_WRITE */ 735 if (rwrq) 736 kmem_free(rwrq, sizeof (*rwrq)); 737 738 /* SMBIOC_NEGOTIATE */ 739 /* SMBIOC_SSNSETUP */ 740 /* SMBIOC_TCON */ 741 if (sioc) { 742 /* 743 * This data structure may contain 744 * cleartext passwords, so zap it. 745 */ 746 bzero(sioc, sizeof (*sioc)); 747 kmem_free(sioc, sizeof (*sioc)); 748 } 749 750 /* SMBIOC_PK_... */ 751 if (pk) { 752 /* 753 * This data structure may contain 754 * cleartext passwords, so zap it. 755 */ 756 bzero(pk, sizeof (*pk)); 757 kmem_free(pk, sizeof (*pk)); 758 } 759 760 smb_credrele(&scred); 761 762 return (error); 763 } 764 765 /*ARGSUSED*/ 766 static int 767 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr) 768 { 769 major_t new_major; 770 smb_dev_t *sdp, *sdv; 771 772 mutex_enter(&dev_lck); 773 for (; ; ) { 774 minor_t start = nsmb_minor; 775 do { 776 if (nsmb_minor >= MAXMIN32) { 777 if (nsmb_major == getmajor(*dev)) 778 nsmb_minor = NSMB_MIN_MINOR; 779 else 780 nsmb_minor = 0; 781 } else { 782 nsmb_minor++; 783 } 784 sdv = ddi_get_soft_state(statep, nsmb_minor); 785 } while ((sdv != NULL) && (nsmb_minor != start)); 786 if (nsmb_minor == start) { 787 /* 788 * The condition we need to solve here is all the 789 * MAXMIN32(~262000) minors numbers are reached. We 790 * need to create a new major number. 791 * zfs uses getudev() to create a new major number. 792 */ 793 if ((new_major = getudev()) == (major_t)-1) { 794 cmn_err(CE_WARN, 795 "nsmb: Can't get unique major " 796 "device number."); 797 mutex_exit(&dev_lck); 798 return (-1); 799 } 800 nsmb_major = new_major; 801 nsmb_minor = 0; 802 } else { 803 break; 804 } 805 } 806 807 /* 808 * This is called by mount or open call. 809 * The open() routine is passed a pointer to a device number so 810 * that the driver can change the minor number. This allows 811 * drivers to dynamically create minor instances of the dev- 812 * ice. An example of this might be a pseudo-terminal driver 813 * that creates a new pseudo-terminal whenever it is opened. 814 * A driver that chooses the minor number dynamically, normally 815 * creates only one minor device node in attach(9E) with 816 * ddi_create_minor_node(9F) then changes the minor number com- 817 * ponent of *devp using makedevice(9F) and getmajor(9F) The 818 * driver needs to keep track of available minor numbers inter- 819 * nally. 820 * Stuff the structure smb_dev. 821 * return. 822 */ 823 824 if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) { 825 mutex_exit(&dev_lck); 826 return (ENXIO); 827 } 828 if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) { 829 mutex_exit(&dev_lck); 830 return (ENXIO); 831 } 832 833 sdp->sd_opened = 1; 834 sdp->sd_seq = nsmb_minor; 835 sdp->smb_cred = cr; 836 sdp->sd_flags |= NSMBFL_OPEN; 837 sdp->zoneid = crgetzoneid(cr); 838 mutex_exit(&dev_lck); 839 840 *dev = makedevice(nsmb_major, nsmb_minor); 841 842 return (0); 843 } 844 845 /*ARGSUSED*/ 846 static int 847 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr) 848 { 849 struct smb_vc *vcp; 850 struct smb_share *ssp; 851 struct smb_cred scred; 852 minor_t inst = getminor(dev); 853 smb_dev_t *sdp; 854 855 mutex_enter(&dev_lck); 856 /* 857 * 1. Check the validity of the minor number. 858 * 2. Release any shares/vc associated with the connection. 859 * 3. Can close the minor number. 860 * 4. Deallocate any resources allocated in open() call. 861 */ 862 smb_credinit(&scred, curproc, cr); 863 864 sdp = ddi_get_soft_state(statep, inst); 865 866 /* 867 * time to call ddi_get_soft_state() 868 */ 869 ssp = sdp->sd_share; 870 if (ssp != NULL) 871 smb_share_rele(ssp); 872 vcp = sdp->sd_vc; 873 if (vcp != NULL) { 874 /* 875 * If this dev minor was doing session setup 876 * and failed to authenticate (or whatever) 877 * then we need to "kill" the VC here so any 878 * other threads waiting for the VC setup to 879 * finish will drop their references. 880 */ 881 if (sdp->sd_flags & NSMBFL_NEWVC) 882 smb_vc_kill(vcp); 883 smb_vc_rele(vcp); 884 } 885 smb_credrele(&scred); 886 887 /* 888 * Free the instance 889 */ 890 ddi_soft_state_free(statep, inst); 891 mutex_exit(&dev_lck); 892 return (0); 893 } 894 895 int 896 smb_dev2share(int fd, struct smb_share **sspp) 897 { 898 register vnode_t *vp; 899 smb_dev_t *sdp; 900 struct smb_share *ssp; 901 dev_t dev; 902 file_t *fp; 903 904 if ((fp = getf(fd)) == NULL) 905 return (set_errno(EBADF)); 906 vp = fp->f_vnode; 907 dev = vp->v_rdev; 908 if (dev == NULL) { 909 releasef(fd); 910 return (EBADF); 911 } 912 sdp = ddi_get_soft_state(statep, getminor(dev)); 913 if (sdp == NULL) { 914 releasef(fd); 915 return (DDI_FAILURE); 916 } 917 ssp = sdp->sd_share; 918 if (ssp == NULL) { 919 releasef(fd); 920 return (ENOTCONN); 921 } 922 /* 923 * The share is already locked and referenced by the TCON ioctl 924 * We NULL to hand off share to caller (mount) 925 * This allows further ioctls against connection, for instance 926 * another tree connect and mount, in the automounter case 927 * 928 * We're effectively giving our reference to the mount. 929 * 930 * XXX: I'm not sure I like this. I'd rather see the ioctl 931 * caller do something explicit to give up this reference, 932 * (i.e. SMBIOC_TDIS above) and increment the hold here. 933 */ 934 sdp->sd_share = NULL; 935 releasef(fd); 936 *sspp = ssp; 937 return (0); 938 } 939