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_FINDVC: 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_findvc(sioc, &scred, &vcp); 465 if (error) 466 break; 467 if (vcp) { 468 /* 469 * The VC has a hold from _findvc 470 * which we keep until nsmb_close(). 471 */ 472 sdp->sd_level = SMBL_VC; 473 sdp->sd_vc = vcp; 474 } 475 (void) ddi_copyout(sioc, (void *)arg, 476 SMBIOC_LOOK_COPYOUT_SIZE, mode); 477 478 break; 479 480 case SMBIOC_NEGOTIATE: 481 /* Should be no VC (and no share) */ 482 if (sdp->sd_vc || sdp->sd_share) { 483 error = EISCONN; 484 break; 485 } 486 sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); 487 if (ddi_copyin((void *)arg, sioc, 488 sizeof (*sioc), mode)) { 489 error = EFAULT; 490 break; 491 } 492 vcp = NULL; 493 ssp = NULL; 494 error = smb_usr_negotiate(sioc, &scred, &vcp); 495 if (error) 496 break; 497 if (vcp) { 498 /* 499 * The VC has a hold from _negotiate 500 * which we keep until nsmb_close(). 501 */ 502 sdp->sd_level = SMBL_VC; 503 sdp->sd_vc = vcp; 504 /* 505 * If we just created this VC, and 506 * this minor is doing the setup, 507 * keep track of that fact here. 508 */ 509 if (vcp->vc_state < SMBIOD_ST_VCACTIVE) 510 sdp->sd_flags |= NSMBFL_NEWVC; 511 512 } 513 /* 514 * Copyout the "out token" (security blob). 515 * 516 * This code used to be near the end of 517 * smb_usr_negotiate(). Moved the copyout 518 * calls here so we know the "mode" 519 */ 520 if (vcp->vc_outtok) { 521 /* 522 * Note: will copyout sioc below 523 * including sioc.vc_outtoklen, 524 * so we no longer put the length 525 * at the start of the outtok data. 526 */ 527 sioc->ioc_ssn.ioc_outtoklen = 528 vcp->vc_outtoklen; 529 err = ddi_copyout( 530 vcp->vc_outtok, 531 sioc->ioc_ssn.ioc_outtok, 532 vcp->vc_outtoklen, mode); 533 if (err) { 534 error = EFAULT; 535 break; 536 } 537 /* 538 * Save this blob in vc_negtok. 539 * We need it in case we have to 540 * reconnect. 541 * 542 * Set vc_negtok = vc_outtok 543 * but free vc_negtok first. 544 */ 545 if (vcp->vc_negtok) { 546 kmem_free( 547 vcp->vc_negtok, 548 vcp->vc_negtoklen); 549 vcp->vc_negtok = NULL; 550 vcp->vc_negtoklen = 0; 551 } 552 vcp->vc_negtok = vcp->vc_outtok; 553 vcp->vc_negtoklen = vcp->vc_outtoklen; 554 vcp->vc_outtok = NULL; 555 vcp->vc_outtoklen = 0; 556 } 557 /* 558 * Added copyout here of (almost) 559 * the whole struct, even though 560 * the lib only needs _outtoklen. 561 * We may put other things in this 562 * struct that user-land needs. 563 */ 564 err = ddi_copyout(sioc, (void *)arg, 565 SMBIOC_LOOK_COPYOUT_SIZE, mode); 566 if (err) 567 error = EFAULT; 568 break; 569 570 case SMBIOC_SSNSETUP: 571 /* Must have a VC, but no share. */ 572 if (sdp->sd_share) { 573 error = EISCONN; 574 break; 575 } 576 if (!sdp->sd_vc) { 577 error = ENOTCONN; 578 break; 579 } 580 sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); 581 if (ddi_copyin((void *)arg, sioc, 582 sizeof (*sioc), mode)) { 583 error = EFAULT; 584 break; 585 } 586 vcp = sdp->sd_vc; 587 ssp = NULL; 588 error = smb_usr_ssnsetup(sioc, &scred, vcp); 589 if (error) 590 break; 591 /* 592 * If this minor has finished ssn setup, 593 * turn off the NEWVC flag, otherwise we 594 * will kill this VC when we close. 595 */ 596 if (vcp->vc_state == SMBIOD_ST_VCACTIVE) 597 sdp->sd_flags &= ~NSMBFL_NEWVC; 598 /* 599 * Copyout the "out token" (security blob). 600 * 601 * This code used to be near the end of 602 * smb_usr_ssnsetup(). Moved the copyout 603 * calls here so we know the "mode" 604 */ 605 if (vcp->vc_outtok) { 606 /* 607 * Note: will copyout sioc below 608 * including sioc.vc_outtoklen, 609 * so we no longer put the length 610 * at the start of the outtok data. 611 */ 612 sioc->ioc_ssn.ioc_outtoklen = 613 vcp->vc_outtoklen; 614 err = ddi_copyout( 615 vcp->vc_outtok, 616 sioc->ioc_ssn.ioc_outtok, 617 vcp->vc_outtoklen, mode); 618 if (err) { 619 error = EFAULT; 620 break; 621 } 622 /* 623 * Done with vc_outtok. Similar, 624 * but NOT the same as after the 625 * smb_usr_negotiate call above. 626 */ 627 kmem_free( 628 vcp->vc_outtok, 629 vcp->vc_outtoklen); 630 vcp->vc_outtok = NULL; 631 vcp->vc_outtoklen = 0; 632 } 633 /* Added copyout here... (see above) */ 634 err = ddi_copyout(sioc, (void *)arg, 635 SMBIOC_LOOK_COPYOUT_SIZE, mode); 636 if (err) 637 error = EFAULT; 638 break; 639 640 case SMBIOC_TCON: 641 /* Must have a VC, but no share. */ 642 if (sdp->sd_share) { 643 error = EISCONN; 644 break; 645 } 646 if (!sdp->sd_vc) { 647 error = ENOTCONN; 648 break; 649 } 650 sioc = kmem_alloc(sizeof (*sioc), KM_SLEEP); 651 if (ddi_copyin((void *)arg, sioc, 652 sizeof (*sioc), mode)) { 653 error = EFAULT; 654 break; 655 } 656 vcp = sdp->sd_vc; 657 ssp = NULL; 658 error = smb_usr_tcon(sioc, &scred, vcp, &ssp); 659 if (error) 660 break; 661 if (ssp) { 662 /* 663 * The share has a hold from _tcon 664 * which we keep until nsmb_close() 665 * or the SMBIOC_TDIS below. 666 */ 667 sdp->sd_share = ssp; 668 sdp->sd_level = SMBL_SHARE; 669 } 670 /* No need for copyout here. */ 671 break; 672 673 case SMBIOC_TDIS: 674 if (sdp->sd_share == NULL) { 675 error = ENOTCONN; 676 break; 677 } 678 smb_share_rele(sdp->sd_share); 679 sdp->sd_share = NULL; 680 sdp->sd_level = SMBL_VC; 681 break; 682 case SMBIOC_FLAGS2: 683 if (sdp->sd_share == NULL) { 684 error = ENOTCONN; 685 break; 686 } 687 if (!sdp->sd_vc) { 688 error = ENOTCONN; 689 break; 690 } 691 vcp = sdp->sd_vc; 692 /* 693 * Return the flags2 value. 694 */ 695 ddi_copyout(&vcp->vc_hflags2, (void *)arg, 696 sizeof (u_int16_t), mode); 697 break; 698 699 case SMBIOC_PK_ADD: 700 pk = kmem_alloc(sizeof (*pk), KM_SLEEP); 701 if (ddi_copyin((void *)arg, pk, 702 sizeof (*pk), mode)) { 703 error = EFAULT; 704 break; 705 } 706 error = smb_pkey_add(pk, credp); 707 break; 708 709 case SMBIOC_PK_DEL: 710 pk = kmem_alloc(sizeof (*pk), KM_SLEEP); 711 if (ddi_copyin((void *)arg, pk, 712 sizeof (*pk), mode)) { 713 error = EFAULT; 714 break; 715 } 716 error = smb_pkey_del(pk, credp); 717 break; 718 719 case SMBIOC_PK_CHK: 720 pk = kmem_alloc(sizeof (*pk), KM_SLEEP); 721 if (ddi_copyin((void *)arg, pk, 722 sizeof (*pk), mode)) { 723 error = EFAULT; 724 break; 725 } 726 error = smb_pkey_check(pk, credp); 727 /* 728 * Note: Intentionally DO NOT copyout 729 * the pasword here. It can only be 730 * retrieved by internal calls. This 731 * ioctl only tells the caller if the 732 * keychain entry exists. 733 */ 734 break; 735 736 case SMBIOC_PK_DEL_OWNER: 737 uid = crgetruid(credp); 738 error = smb_pkey_deluid(uid, credp); 739 break; 740 741 case SMBIOC_PK_DEL_EVERYONE: 742 uid = (uid_t)-1; 743 error = smb_pkey_deluid(uid, credp); 744 break; 745 746 default: 747 error = ENODEV; 748 } 749 750 /* 751 * Let's just do all the kmem_free stuff HERE, 752 * instead of at every switch break. 753 */ 754 755 /* SMBIOC_REQUEST */ 756 if (srq) 757 kmem_free(srq, sizeof (*srq)); 758 759 /* SMBIOC_T2RQ */ 760 if (strq) 761 kmem_free(strq, sizeof (*strq)); 762 763 /* SMBIOC_READ */ 764 /* SMBIOC_WRITE */ 765 if (rwrq) 766 kmem_free(rwrq, sizeof (*rwrq)); 767 768 /* SMBIOC_FINDVC */ 769 /* SMBIOC_NEGOTIATE */ 770 /* SMBIOC_SSNSETUP */ 771 /* SMBIOC_TCON */ 772 if (sioc) { 773 /* 774 * This data structure may contain 775 * cleartext passwords, so zap it. 776 */ 777 bzero(sioc, sizeof (*sioc)); 778 kmem_free(sioc, sizeof (*sioc)); 779 } 780 781 /* SMBIOC_PK_... */ 782 if (pk) { 783 /* 784 * This data structure may contain 785 * cleartext passwords, so zap it. 786 */ 787 bzero(pk, sizeof (*pk)); 788 kmem_free(pk, sizeof (*pk)); 789 } 790 791 smb_credrele(&scred); 792 793 return (error); 794 } 795 796 /*ARGSUSED*/ 797 static int 798 nsmb_open(dev_t *dev, int flags, int otyp, cred_t *cr) 799 { 800 major_t new_major; 801 smb_dev_t *sdp, *sdv; 802 803 mutex_enter(&dev_lck); 804 for (; ; ) { 805 minor_t start = nsmb_minor; 806 do { 807 if (nsmb_minor >= MAXMIN32) { 808 if (nsmb_major == getmajor(*dev)) 809 nsmb_minor = NSMB_MIN_MINOR; 810 else 811 nsmb_minor = 0; 812 } else { 813 nsmb_minor++; 814 } 815 sdv = ddi_get_soft_state(statep, nsmb_minor); 816 } while ((sdv != NULL) && (nsmb_minor != start)); 817 if (nsmb_minor == start) { 818 /* 819 * The condition we need to solve here is all the 820 * MAXMIN32(~262000) minors numbers are reached. We 821 * need to create a new major number. 822 * zfs uses getudev() to create a new major number. 823 */ 824 if ((new_major = getudev()) == (major_t)-1) { 825 cmn_err(CE_WARN, 826 "nsmb: Can't get unique major " 827 "device number."); 828 mutex_exit(&dev_lck); 829 return (-1); 830 } 831 nsmb_major = new_major; 832 nsmb_minor = 0; 833 } else { 834 break; 835 } 836 } 837 838 /* 839 * This is called by mount or open call. 840 * The open() routine is passed a pointer to a device number so 841 * that the driver can change the minor number. This allows 842 * drivers to dynamically create minor instances of the dev- 843 * ice. An example of this might be a pseudo-terminal driver 844 * that creates a new pseudo-terminal whenever it is opened. 845 * A driver that chooses the minor number dynamically, normally 846 * creates only one minor device node in attach(9E) with 847 * ddi_create_minor_node(9F) then changes the minor number com- 848 * ponent of *devp using makedevice(9F) and getmajor(9F) The 849 * driver needs to keep track of available minor numbers inter- 850 * nally. 851 * Stuff the structure smb_dev. 852 * return. 853 */ 854 855 if (ddi_soft_state_zalloc(statep, nsmb_minor) == DDI_FAILURE) { 856 mutex_exit(&dev_lck); 857 return (ENXIO); 858 } 859 if ((sdp = ddi_get_soft_state(statep, nsmb_minor)) == NULL) { 860 mutex_exit(&dev_lck); 861 return (ENXIO); 862 } 863 864 sdp->sd_opened = 1; 865 sdp->sd_seq = nsmb_minor; 866 sdp->smb_cred = cr; 867 sdp->sd_flags |= NSMBFL_OPEN; 868 sdp->zoneid = crgetzoneid(cr); 869 mutex_exit(&dev_lck); 870 871 *dev = makedevice(nsmb_major, nsmb_minor); 872 873 return (0); 874 } 875 876 /*ARGSUSED*/ 877 static int 878 nsmb_close(dev_t dev, int flags, int otyp, cred_t *cr) 879 { 880 struct smb_vc *vcp; 881 struct smb_share *ssp; 882 struct smb_cred scred; 883 minor_t inst = getminor(dev); 884 smb_dev_t *sdp; 885 886 mutex_enter(&dev_lck); 887 /* 888 * 1. Check the validity of the minor number. 889 * 2. Release any shares/vc associated with the connection. 890 * 3. Can close the minor number. 891 * 4. Deallocate any resources allocated in open() call. 892 */ 893 smb_credinit(&scred, curproc, cr); 894 895 sdp = ddi_get_soft_state(statep, inst); 896 897 /* 898 * time to call ddi_get_soft_state() 899 */ 900 ssp = sdp->sd_share; 901 if (ssp != NULL) 902 smb_share_rele(ssp); 903 vcp = sdp->sd_vc; 904 if (vcp != NULL) { 905 /* 906 * If this dev minor was doing session setup 907 * and failed to authenticate (or whatever) 908 * then we need to "kill" the VC here so any 909 * other threads waiting for the VC setup to 910 * finish will drop their references. 911 */ 912 if (sdp->sd_flags & NSMBFL_NEWVC) 913 smb_vc_kill(vcp); 914 smb_vc_rele(vcp); 915 } 916 smb_credrele(&scred); 917 918 /* 919 * Free the instance 920 */ 921 ddi_soft_state_free(statep, inst); 922 mutex_exit(&dev_lck); 923 return (0); 924 } 925 926 int 927 smb_dev2share(int fd, struct smb_share **sspp) 928 { 929 register vnode_t *vp; 930 smb_dev_t *sdp; 931 struct smb_share *ssp; 932 dev_t dev; 933 file_t *fp; 934 935 if ((fp = getf(fd)) == NULL) 936 return (set_errno(EBADF)); 937 vp = fp->f_vnode; 938 dev = vp->v_rdev; 939 if (dev == NULL) { 940 releasef(fd); 941 return (EBADF); 942 } 943 sdp = ddi_get_soft_state(statep, getminor(dev)); 944 if (sdp == NULL) { 945 releasef(fd); 946 return (DDI_FAILURE); 947 } 948 ssp = sdp->sd_share; 949 if (ssp == NULL) { 950 releasef(fd); 951 return (ENOTCONN); 952 } 953 /* 954 * The share is already locked and referenced by the TCON ioctl 955 * We NULL to hand off share to caller (mount) 956 * This allows further ioctls against connection, for instance 957 * another tree connect and mount, in the automounter case 958 * 959 * We're effectively giving our reference to the mount. 960 * 961 * XXX: I'm not sure I like this. I'd rather see the ioctl 962 * caller do something explicit to give up this reference, 963 * (i.e. SMBIOC_TDIS above) and increment the hold here. 964 */ 965 sdp->sd_share = NULL; 966 releasef(fd); 967 *sspp = ssp; 968 return (0); 969 } 970