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