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