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