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_conn.c,v 1.27.166.1 2005/05/27 02:35:29 lindak Exp $ 33 */ 34 /* 35 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 36 * Use is subject to license terms. 37 */ 38 39 /* 40 * Connection engine. 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kmem.h> 46 #include <sys/proc.h> 47 #include <sys/lock.h> 48 #include <sys/vnode.h> 49 #include <sys/stream.h> 50 #include <sys/stropts.h> 51 #include <sys/socketvar.h> 52 #include <sys/cred.h> 53 #include <sys/cred_impl.h> 54 #include <netinet/in.h> 55 #include <inet/ip.h> 56 #include <inet/ip6.h> 57 #include <sys/cmn_err.h> 58 #include <sys/thread.h> 59 #include <sys/atomic.h> 60 61 #ifdef APPLE 62 #include <sys/smb_apple.h> 63 #include <sys/smb_iconv.h> 64 #else 65 #include <netsmb/smb_osdep.h> 66 #endif 67 68 #include <netsmb/smb.h> 69 #include <netsmb/smb_conn.h> 70 #include <netsmb/smb_subr.h> 71 #include <netsmb/smb_tran.h> 72 #include <netsmb/smb_pass.h> 73 74 static struct smb_connobj smb_vclist; 75 static uint_t smb_vcnext = 0; /* next unique id for VC */ 76 77 void smb_co_init(struct smb_connobj *cp, int level, char *objname); 78 void smb_co_done(struct smb_connobj *cp); 79 void smb_co_hold(struct smb_connobj *cp); 80 void smb_co_rele(struct smb_connobj *cp); 81 void smb_co_kill(struct smb_connobj *cp); 82 83 #ifdef APPLE 84 static void smb_sm_lockvclist(void); 85 static void smb_sm_unlockvclist(void); 86 #endif 87 88 static void smb_vc_free(struct smb_connobj *cp); 89 static void smb_vc_gone(struct smb_connobj *cp); 90 91 static void smb_share_free(struct smb_connobj *cp); 92 static void smb_share_gone(struct smb_connobj *cp); 93 94 /* smb_dup_sockaddr moved to smb_tran.c */ 95 96 int 97 smb_sm_init(void) 98 { 99 smb_co_init(&smb_vclist, SMBL_SM, "smbsm"); 100 return (0); 101 } 102 103 int 104 smb_sm_idle(void) 105 { 106 int error = 0; 107 SMB_CO_LOCK(&smb_vclist); 108 if (smb_vclist.co_usecount > 1) { 109 SMBSDEBUG("%d connections still active\n", 110 smb_vclist.co_usecount - 1); 111 error = EBUSY; 112 } 113 SMB_CO_UNLOCK(&smb_vclist); 114 return (error); 115 } 116 117 void 118 smb_sm_done(void) 119 { 120 /* 121 * XXX Q4BP why are we not iterating on smb_vclist here? 122 * Because the caller has just called smb_sm_idle() to 123 * make sure we have no VCs before calling this. 124 */ 125 smb_co_done(&smb_vclist); 126 } 127 128 /* 129 * Find a VC identified by the info in vcspec, 130 * and return it with a "hold", but not locked. 131 */ 132 /*ARGSUSED*/ 133 static int 134 smb_sm_lookupvc( 135 struct smb_vcspec *vcspec, 136 struct smb_cred *scred, 137 struct smb_vc **vcpp) 138 { 139 struct smb_connobj *co; 140 struct smb_vc *vcp; 141 zoneid_t zoneid = getzoneid(); 142 143 ASSERT(MUTEX_HELD(&smb_vclist.co_lock)); 144 145 /* var, head, next_field */ 146 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { 147 vcp = CPTOVC(co); 148 149 /* 150 * Some things we can check without 151 * holding the lock (those that are 152 * set at creation and never change). 153 */ 154 155 /* VCs in other zones are invisibile. */ 156 if (vcp->vc_zoneid != zoneid) 157 continue; 158 159 /* Also segregate by owner. */ 160 if (vcp->vc_uid != vcspec->owner) 161 continue; 162 163 /* XXX: we ignore the group. Remove vc_gid? */ 164 165 /* server */ 166 if (smb_cmp_sockaddr(vcp->vc_paddr, vcspec->sap)) 167 continue; 168 169 /* domain+user */ 170 if (strcmp(vcp->vc_domain, vcspec->domain)) 171 continue; 172 if (strcmp(vcp->vc_username, vcspec->username)) 173 continue; 174 175 SMB_VC_LOCK(vcp); 176 177 /* No new references allowed when _GONE is set */ 178 if (vcp->vc_flags & SMBV_GONE) 179 goto unlock_continue; 180 181 if (vcp->vc_vopt & SMBVOPT_PRIVATE) 182 goto unlock_continue; 183 184 found: 185 /* 186 * Success! (Found one we can use) 187 * Return with it held, unlocked. 188 * In-line smb_vc_hold here. 189 */ 190 co->co_usecount++; 191 SMB_VC_UNLOCK(vcp); 192 *vcpp = vcp; 193 return (0); 194 195 unlock_continue: 196 SMB_VC_UNLOCK(vcp); 197 /* keep looking. */ 198 } 199 200 return (ENOENT); 201 } 202 203 int 204 smb_sm_findvc( 205 struct smb_vcspec *vcspec, 206 struct smb_cred *scred, 207 struct smb_vc **vcpp) 208 { 209 struct smb_vc *vcp; 210 int error; 211 212 *vcpp = vcp = NULL; 213 214 SMB_CO_LOCK(&smb_vclist); 215 error = smb_sm_lookupvc(vcspec, scred, &vcp); 216 SMB_CO_UNLOCK(&smb_vclist); 217 218 /* Return if smb_sm_lookupvc fails */ 219 if (error != 0) 220 return (error); 221 222 /* Ingore any VC that's not active. */ 223 if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { 224 smb_vc_rele(vcp); 225 return (ENOENT); 226 } 227 228 /* Active VC. Return it held. */ 229 *vcpp = vcp; 230 return (error); 231 } 232 233 int 234 smb_sm_negotiate( 235 struct smb_vcspec *vcspec, 236 struct smb_cred *scred, 237 struct smb_vc **vcpp) 238 { 239 struct smb_vc *vcp; 240 clock_t tmo; 241 int created, error; 242 243 top: 244 *vcpp = vcp = NULL; 245 246 SMB_CO_LOCK(&smb_vclist); 247 error = smb_sm_lookupvc(vcspec, scred, &vcp); 248 if (error) { 249 /* The VC was not found. Create? */ 250 if ((vcspec->optflags & SMBVOPT_CREATE) == 0) { 251 SMB_CO_UNLOCK(&smb_vclist); 252 return (error); 253 } 254 error = smb_vc_create(vcspec, scred, &vcp); 255 if (error) { 256 /* Could not create? Unusual. */ 257 SMB_CO_UNLOCK(&smb_vclist); 258 return (error); 259 } 260 /* Note: co_usecount == 1 */ 261 created = 1; 262 } else 263 created = 0; 264 SMB_CO_UNLOCK(&smb_vclist); 265 266 if (created == 0) { 267 /* 268 * Found an existing VC. Reuse it, but first, 269 * wait for any other thread doing setup, etc. 270 * Note: We hold a reference on the VC. 271 */ 272 error = 0; 273 SMB_VC_LOCK(vcp); 274 while (vcp->vc_state < SMBIOD_ST_VCACTIVE) { 275 if (vcp->vc_flags & SMBV_GONE) 276 break; 277 tmo = lbolt + SEC_TO_TICK(2); 278 tmo = cv_timedwait_sig(&vcp->vc_statechg, 279 &vcp->vc_lock, tmo); 280 if (tmo == 0) { 281 error = EINTR; 282 break; 283 } 284 } 285 SMB_VC_UNLOCK(vcp); 286 287 /* Interrupted? */ 288 if (error) 289 goto out; 290 291 /* 292 * Was there a vc_kill while we waited? 293 * If so, this VC is gone. Start over. 294 */ 295 if (vcp->vc_flags & SMBV_GONE) { 296 smb_vc_rele(vcp); 297 goto top; 298 } 299 300 /* 301 * The possible states here are: 302 * SMBIOD_ST_VCACTIVE, SMBIOD_ST_DEAD 303 * 304 * SMBIOD_ST_VCACTIVE is the normal case, 305 * where found a connection ready to use. 306 * 307 * We may find vc_state == SMBIOD_ST_DEAD 308 * if a previous session has disconnected. 309 * In this case, we'd like to reconnect, 310 * so take over setting up this VC as if 311 * this thread had created it. 312 */ 313 SMB_VC_LOCK(vcp); 314 if (vcp->vc_state == SMBIOD_ST_DEAD) { 315 vcp->vc_state = SMBIOD_ST_NOTCONN; 316 created = 1; 317 /* Will signal vc_statechg below */ 318 } 319 SMB_VC_UNLOCK(vcp); 320 } 321 322 if (created) { 323 /* 324 * We have a NEW VC, held, but not locked. 325 */ 326 327 SMBIODEBUG("vc_state=%d\n", vcp->vc_state); 328 switch (vcp->vc_state) { 329 330 case SMBIOD_ST_NOTCONN: 331 (void) smb_vc_setup(vcspec, scred, vcp, 0); 332 vcp->vc_genid++; 333 /* XXX: Save credentials of caller here? */ 334 vcp->vc_state = SMBIOD_ST_RECONNECT; 335 /* FALLTHROUGH */ 336 337 case SMBIOD_ST_RECONNECT: 338 error = smb_iod_connect(vcp); 339 if (error) 340 break; 341 vcp->vc_state = SMBIOD_ST_TRANACTIVE; 342 /* FALLTHROUGH */ 343 344 case SMBIOD_ST_TRANACTIVE: 345 /* XXX: Just pass vcspec instead? */ 346 vcp->vc_intok = vcspec->tok; 347 vcp->vc_intoklen = vcspec->toklen; 348 error = smb_smb_negotiate(vcp, &vcp->vc_scred); 349 vcp->vc_intok = NULL; 350 vcp->vc_intoklen = 0; 351 if (error) 352 break; 353 vcp->vc_state = SMBIOD_ST_NEGOACTIVE; 354 /* FALLTHROUGH */ 355 356 case SMBIOD_ST_NEGOACTIVE: 357 case SMBIOD_ST_SSNSETUP: 358 case SMBIOD_ST_VCACTIVE: 359 /* We can (re)use this VC. */ 360 error = 0; 361 break; 362 363 default: 364 error = EINVAL; 365 break; 366 } 367 368 if (error) { 369 /* 370 * Leave the VC in a state that allows the 371 * next open to attempt a new connection. 372 * This call does the cv_broadcast too, 373 * so that's in the else part. 374 */ 375 smb_iod_disconnect(vcp); 376 } else { 377 SMB_VC_LOCK(vcp); 378 cv_broadcast(&vcp->vc_statechg); 379 SMB_VC_UNLOCK(vcp); 380 } 381 } 382 383 out: 384 if (error) { 385 /* 386 * Undo the hold from lookupvc, 387 * or destroy if from vc_create. 388 */ 389 smb_vc_rele(vcp); 390 } else { 391 /* Return it held. */ 392 *vcpp = vcp; 393 } 394 395 return (error); 396 } 397 398 399 int 400 smb_sm_ssnsetup( 401 struct smb_vcspec *vcspec, 402 struct smb_cred *scred, 403 struct smb_vc *vcp) 404 { 405 int error; 406 407 /* 408 * We have a VC, held, but not locked. 409 * 410 * Code from smb_iod_ssnsetup, 411 * with lots of rework. 412 */ 413 414 SMBIODEBUG("vc_state=%d\n", vcp->vc_state); 415 switch (vcp->vc_state) { 416 417 case SMBIOD_ST_NEGOACTIVE: 418 /* 419 * This is the state we normally find. 420 * Calling _setup AGAIN to update the 421 * flags, security info, etc. 422 */ 423 error = smb_vc_setup(vcspec, scred, vcp, 1); 424 if (error) 425 break; 426 vcp->vc_state = SMBIOD_ST_SSNSETUP; 427 /* FALLTHROUGH */ 428 429 case SMBIOD_ST_SSNSETUP: 430 /* XXX: Just pass vcspec instead? */ 431 vcp->vc_intok = vcspec->tok; 432 vcp->vc_intoklen = vcspec->toklen; 433 error = smb_smb_ssnsetup(vcp, &vcp->vc_scred); 434 vcp->vc_intok = NULL; 435 vcp->vc_intoklen = 0; 436 if (error) 437 break; 438 /* OK, start the reader thread... */ 439 error = smb_iod_create(vcp); 440 if (error) 441 break; 442 vcp->vc_state = SMBIOD_ST_VCACTIVE; 443 /* FALLTHROUGH */ 444 445 case SMBIOD_ST_VCACTIVE: 446 /* We can (re)use this VC. */ 447 error = 0; 448 break; 449 450 default: 451 error = EINVAL; 452 break; 453 } 454 455 SMB_VC_LOCK(vcp); 456 cv_broadcast(&vcp->vc_statechg); 457 SMB_VC_UNLOCK(vcp); 458 459 return (error); 460 } 461 462 int 463 smb_sm_tcon( 464 struct smb_sharespec *shspec, 465 struct smb_cred *scred, 466 struct smb_vc *vcp, 467 struct smb_share **sspp) 468 { 469 struct smb_share *ssp; 470 int error; 471 472 *sspp = ssp = NULL; 473 474 if (vcp->vc_state != SMBIOD_ST_VCACTIVE) { 475 /* 476 * The wait for vc_state in smb_sm_negotiate 477 * _should_ get us a VC in the right state. 478 */ 479 SMBIODEBUG("bad vc_state=%d\n", vcp->vc_state); 480 return (ENOTCONN); 481 } 482 483 SMB_VC_LOCK(vcp); 484 error = smb_vc_lookupshare(vcp, shspec, scred, &ssp); 485 if (error) { 486 /* The share was not found. Create? */ 487 if ((shspec->optflags & SMBVOPT_CREATE) == 0) { 488 SMB_VC_UNLOCK(vcp); 489 return (error); 490 } 491 error = smb_share_create(vcp, shspec, scred, &ssp); 492 if (error) { 493 /* Could not create? Unusual. */ 494 SMB_VC_UNLOCK(vcp); 495 return (error); 496 } 497 /* Note: co_usecount == 1 */ 498 } 499 SMB_VC_UNLOCK(vcp); 500 501 /* 502 * We have a share, held, but not locked. 503 * Make it connected... 504 */ 505 SMB_SS_LOCK(ssp); 506 if (!smb_share_valid(ssp)) 507 error = smb_share_tcon(ssp); 508 SMB_SS_UNLOCK(ssp); 509 510 if (error) { 511 /* 512 * Undo hold from lookupshare, 513 * or destroy if from _create. 514 */ 515 smb_share_rele(ssp); 516 } else { 517 /* Return it held. */ 518 *sspp = ssp; 519 } 520 521 return (error); 522 } 523 524 /* 525 * Common code for connection object 526 */ 527 /*ARGSUSED*/ 528 void 529 smb_co_init(struct smb_connobj *cp, int level, char *objname) 530 { 531 532 mutex_init(&cp->co_lock, objname, MUTEX_DRIVER, NULL); 533 534 cp->co_level = level; 535 cp->co_usecount = 1; 536 SLIST_INIT(&cp->co_children); 537 } 538 539 /* 540 * Called just before free of an object 541 * of which smb_connobj is a part, i.e. 542 * _vc_free, _share_free, also sm_done. 543 */ 544 void 545 smb_co_done(struct smb_connobj *cp) 546 { 547 ASSERT(SLIST_EMPTY(&cp->co_children)); 548 mutex_destroy(&cp->co_lock); 549 } 550 551 static void 552 smb_co_addchild( 553 struct smb_connobj *parent, 554 struct smb_connobj *child) 555 { 556 557 /* 558 * Set the child's pointer to the parent. 559 * No references yet, so no need to lock. 560 */ 561 ASSERT(child->co_usecount == 1); 562 child->co_parent = parent; 563 564 /* 565 * Add the child to the parent's list of 566 * children, and in-line smb_co_hold 567 */ 568 ASSERT(MUTEX_HELD(&parent->co_lock)); 569 parent->co_usecount++; 570 SLIST_INSERT_HEAD(&parent->co_children, child, co_next); 571 } 572 573 void 574 smb_co_hold(struct smb_connobj *cp) 575 { 576 SMB_CO_LOCK(cp); 577 cp->co_usecount++; 578 SMB_CO_UNLOCK(cp); 579 } 580 581 /* 582 * Called via smb_vc_rele, smb_share_rele 583 */ 584 void 585 smb_co_rele(struct smb_connobj *co) 586 { 587 struct smb_connobj *parent; 588 int old_flags; 589 590 SMB_CO_LOCK(co); 591 if (co->co_usecount > 1) { 592 co->co_usecount--; 593 SMB_CO_UNLOCK(co); 594 return; 595 } 596 ASSERT(co->co_usecount == 1); 597 co->co_usecount = 0; 598 599 /* 600 * This list of children should be empty now. 601 * Check this while we're still linked, so 602 * we have a better chance of debugging. 603 */ 604 ASSERT(SLIST_EMPTY(&co->co_children)); 605 606 /* 607 * OK, this element is going away. 608 * 609 * We need to drop the lock on this CO so we can take the 610 * parent CO lock. The _GONE flag prevents this CO from 611 * getting new references before we can unlink it from the 612 * parent list. 613 * 614 * The _GONE flag is also used to ensure that the co_gone 615 * function is called only once. Note that smb_co_kill may 616 * do this before we get here. If we find that the _GONE 617 * flag was not already set, then call the co_gone hook 618 * (smb_share_gone, smb_vc_gone) which will disconnect 619 * the share or the VC, respectively. 620 * 621 * Note the old: smb_co_gone(co, scred); 622 * is now in-line here. 623 */ 624 old_flags = co->co_flags; 625 co->co_flags |= SMBO_GONE; 626 SMB_CO_UNLOCK(co); 627 628 if ((old_flags & SMBO_GONE) == 0 && co->co_gone) 629 co->co_gone(co); 630 631 /* 632 * If we have a parent (only smb_vclist does not) 633 * then unlink from parent's list of children. 634 * We have the only reference to the child. 635 */ 636 parent = co->co_parent; 637 if (parent) { 638 SMB_CO_LOCK(parent); 639 ASSERT(SLIST_FIRST(&parent->co_children)); 640 if (SLIST_FIRST(&parent->co_children)) { 641 SLIST_REMOVE(&parent->co_children, co, 642 smb_connobj, co_next); 643 } 644 SMB_CO_UNLOCK(parent); 645 } 646 647 /* 648 * Now it's safe to free the CO 649 */ 650 if (co->co_free) { 651 co->co_free(co); 652 } 653 654 /* 655 * Finally, if the CO had a parent, decrement 656 * the parent's hold count for the lost child. 657 */ 658 if (parent) { 659 /* 660 * Recursive call here (easier for debugging). 661 * Can only go two levels. 662 */ 663 smb_co_rele(parent); 664 } 665 } 666 667 /* 668 * Do just the first part of what co_gone does, 669 * i.e. tree disconnect, or disconnect a VC. 670 * This is used to forcibly close things. 671 */ 672 void 673 smb_co_kill(struct smb_connobj *co) 674 { 675 int old_flags; 676 677 SMB_CO_LOCK(co); 678 old_flags = co->co_flags; 679 co->co_flags |= SMBO_GONE; 680 SMB_CO_UNLOCK(co); 681 682 /* 683 * Do the same "call only once" logic here as in 684 * smb_co_rele, though it's probably not possible 685 * for this to be called after smb_co_rele. 686 */ 687 if ((old_flags & SMBO_GONE) == 0 && co->co_gone) 688 co->co_gone(co); 689 690 /* XXX: Walk list of children and kill those too? */ 691 } 692 693 694 /* 695 * Session implementation 696 */ 697 698 /* 699 * This sets the fields that are allowed to change 700 * when doing a reconnect. Many others are set in 701 * smb_vc_create and never change afterwards. 702 * Don't want domain or user to change here. 703 */ 704 int 705 smb_vc_setup(struct smb_vcspec *vcspec, struct smb_cred *scred, 706 struct smb_vc *vcp, int is_ss) 707 { 708 int error, minauth; 709 710 /* Just save all the SMBVOPT_ options. */ 711 vcp->vc_vopt = vcspec->optflags; 712 713 if (is_ss) { 714 /* Called from smb_sm_ssnsetup */ 715 716 if (vcspec->optflags & SMBVOPT_USE_KEYCHAIN) { 717 /* 718 * Get p/w hashes from the keychain. 719 * The password in vcspec->pass is 720 * fiction, so don't store it. 721 */ 722 error = smb_pkey_getpwh(vcp, scred->vc_ucred); 723 return (error); 724 } 725 726 /* 727 * Note: this can be called more than once 728 * for a given vcp, so free the old strings. 729 */ 730 SMB_STRFREE(vcp->vc_pass); 731 732 /* 733 * Don't store the cleartext password 734 * unless the minauth value was changed 735 * to allow use of cleartext passwords. 736 * (By default, this is not allowed.) 737 */ 738 minauth = vcspec->optflags & SMBVOPT_MINAUTH; 739 if (minauth == SMBVOPT_MINAUTH_NONE) 740 vcp->vc_pass = smb_strdup(vcspec->pass); 741 742 /* Compute LM and NTLM hashes. */ 743 smb_oldlm_hash(vcspec->pass, vcp->vc_lmhash); 744 smb_ntlmv1hash(vcspec->pass, vcp->vc_nthash); 745 } 746 747 /* Success! */ 748 error = 0; 749 return (error); 750 } 751 752 /*ARGSUSED*/ 753 int 754 smb_vc_create(struct smb_vcspec *vcspec, 755 struct smb_cred *scred, struct smb_vc **vcpp) 756 { 757 static char objtype[] = "smb_vc"; 758 struct smb_vc *vcp; 759 int error = 0; 760 761 ASSERT(MUTEX_HELD(&smb_vclist.co_lock)); 762 763 /* 764 * Checks for valid uid/gid are now in 765 * smb_usr_ioc2vcspec, so at this point 766 * we know the user has right to create 767 * with the uid/gid in the vcspec. 768 */ 769 770 vcp = kmem_zalloc(sizeof (struct smb_vc), KM_SLEEP); 771 772 smb_co_init(VCTOCP(vcp), SMBL_VC, objtype); 773 vcp->vc_co.co_free = smb_vc_free; 774 vcp->vc_co.co_gone = smb_vc_gone; 775 776 cv_init(&vcp->vc_statechg, objtype, CV_DRIVER, NULL); 777 sema_init(&vcp->vc_sendlock, 1, objtype, SEMA_DRIVER, NULL); 778 rw_init(&vcp->iod_rqlock, objtype, RW_DRIVER, NULL); 779 cv_init(&vcp->iod_exit, objtype, CV_DRIVER, NULL); 780 781 vcp->vc_number = atomic_inc_uint_nv(&smb_vcnext); 782 vcp->vc_state = SMBIOD_ST_NOTCONN; 783 vcp->vc_timo = SMB_DEFRQTIMO; 784 /* 785 * I think SMB_UID_UNKNOWN is not the correct 786 * initial value for vc_smbuid. See the long 787 * comment in smb_iod_sendrq() 788 */ 789 vcp->vc_smbuid = SMB_UID_UNKNOWN; /* XXX should be zero */ 790 vcp->vc_tdesc = &smb_tran_nbtcp_desc; 791 792 /* 793 * These identify the connection. 794 */ 795 vcp->vc_zoneid = getzoneid(); 796 vcp->vc_uid = vcspec->owner; 797 vcp->vc_grp = vcspec->group; 798 vcp->vc_mode = vcspec->rights & SMBM_MASK; 799 800 vcp->vc_domain = smb_strdup(vcspec->domain); 801 vcp->vc_username = smb_strdup(vcspec->username); 802 vcp->vc_srvname = smb_strdup(vcspec->srvname); 803 vcp->vc_paddr = smb_dup_sockaddr(vcspec->sap); 804 vcp->vc_laddr = smb_dup_sockaddr(vcspec->lap); 805 806 #ifdef NOICONVSUPPORT 807 /* 808 * REVISIT 809 */ 810 error = iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower); 811 if (error) 812 goto errout; 813 814 error = iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper); 815 if (error) 816 goto errout; 817 818 if (vcspec->servercs[0]) { 819 820 error = iconv_open(vcspec->servercs, vcspec->localcs, 821 &vcp->vc_toserver); 822 if (error) 823 goto errout; 824 825 error = iconv_open(vcspec->localcs, vcspec->servercs, 826 &vcp->vc_tolocal); 827 if (error) 828 goto errout; 829 } 830 #endif /* NOICONVSUPPORT */ 831 832 /* This fills in vcp->vc_tdata */ 833 if ((error = SMB_TRAN_CREATE(vcp, curproc)) != 0) 834 goto errout; 835 836 /* Success! */ 837 smb_co_addchild(&smb_vclist, VCTOCP(vcp)); 838 *vcpp = vcp; 839 return (0); 840 841 errout: 842 /* 843 * This will destroy the new vc. 844 * See: smb_vc_free 845 */ 846 smb_vc_rele(vcp); 847 return (error); 848 } 849 850 void 851 smb_vc_hold(struct smb_vc *vcp) 852 { 853 smb_co_hold(VCTOCP(vcp)); 854 } 855 856 void 857 smb_vc_rele(struct smb_vc *vcp) 858 { 859 smb_co_rele(VCTOCP(vcp)); 860 } 861 862 void 863 smb_vc_kill(struct smb_vc *vcp) 864 { 865 smb_co_kill(VCTOCP(vcp)); 866 } 867 868 /* 869 * Normally called via smb_vc_rele() 870 * after co_usecount drops to zero. 871 * Also called via: smb_vc_kill() 872 * 873 * Shutdown the VC to this server, 874 * invalidate shares linked with it. 875 */ 876 /*ARGSUSED*/ 877 static void 878 smb_vc_gone(struct smb_connobj *cp) 879 { 880 struct smb_vc *vcp = CPTOVC(cp); 881 882 /* 883 * Was smb_vc_disconnect(vcp); 884 */ 885 smb_iod_disconnect(vcp); 886 887 /* Note: smb_iod_destroy in vc_free */ 888 } 889 890 static void 891 smb_vc_free(struct smb_connobj *cp) 892 { 893 struct smb_vc *vcp = CPTOVC(cp); 894 895 /* 896 * The VC has no more references, so 897 * no locks should be needed here. 898 * Make sure the IOD is gone. 899 */ 900 smb_iod_destroy(vcp); 901 902 if (vcp->vc_tdata) 903 SMB_TRAN_DONE(vcp, curproc); 904 905 SMB_STRFREE(vcp->vc_username); 906 SMB_STRFREE(vcp->vc_srvname); 907 SMB_STRFREE(vcp->vc_pass); 908 SMB_STRFREE(vcp->vc_domain); 909 if (vcp->vc_paddr) { 910 smb_free_sockaddr(vcp->vc_paddr); 911 vcp->vc_paddr = NULL; 912 } 913 if (vcp->vc_laddr) { 914 smb_free_sockaddr(vcp->vc_laddr); 915 vcp->vc_laddr = NULL; 916 } 917 918 /* 919 * We are not using the iconv routines here. So commenting them for now. 920 * REVISIT. 921 */ 922 #ifdef NOTYETDEFINED 923 if (vcp->vc_tolower) 924 iconv_close(vcp->vc_tolower); 925 if (vcp->vc_toupper) 926 iconv_close(vcp->vc_toupper); 927 if (vcp->vc_tolocal) 928 iconv_close(vcp->vc_tolocal); 929 if (vcp->vc_toserver) 930 iconv_close(vcp->vc_toserver); 931 #endif 932 if (vcp->vc_intok) 933 kmem_free(vcp->vc_intok, vcp->vc_intoklen); 934 if (vcp->vc_outtok) 935 kmem_free(vcp->vc_outtok, vcp->vc_outtoklen); 936 if (vcp->vc_negtok) 937 kmem_free(vcp->vc_negtok, vcp->vc_negtoklen); 938 939 if (vcp->vc_mackey != NULL) 940 kmem_free(vcp->vc_mackey, vcp->vc_mackeylen); 941 942 cv_destroy(&vcp->iod_exit); 943 rw_destroy(&vcp->iod_rqlock); 944 sema_destroy(&vcp->vc_sendlock); 945 cv_destroy(&vcp->vc_statechg); 946 smb_co_done(VCTOCP(vcp)); 947 kmem_free(vcp, sizeof (*vcp)); 948 } 949 950 951 /* 952 * Lookup share in the given VC. Share referenced and locked on return. 953 * VC expected to be locked on entry and will be left locked on exit. 954 */ 955 /*ARGSUSED*/ 956 int 957 smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *shspec, 958 struct smb_cred *scred, struct smb_share **sspp) 959 { 960 struct smb_connobj *co; 961 struct smb_share *ssp = NULL; 962 963 ASSERT(MUTEX_HELD(&vcp->vc_lock)); 964 965 *sspp = NULL; 966 967 /* var, head, next_field */ 968 SLIST_FOREACH(co, &(VCTOCP(vcp)->co_children), co_next) { 969 ssp = CPTOSS(co); 970 971 /* No new refs if _GONE is set. */ 972 if (ssp->ss_flags & SMBS_GONE) 973 continue; 974 975 /* This has a hold, so no need to lock it. */ 976 if (strcmp(ssp->ss_name, shspec->name) == 0) 977 goto found; 978 } 979 return (ENOENT); 980 981 found: 982 /* Return it with a hold. */ 983 smb_share_hold(ssp); 984 *sspp = ssp; 985 return (0); 986 } 987 988 989 static char smb_emptypass[] = ""; 990 991 const char * 992 smb_vc_getpass(struct smb_vc *vcp) 993 { 994 if (vcp->vc_pass) 995 return (vcp->vc_pass); 996 return (smb_emptypass); 997 } 998 999 uint16_t 1000 smb_vc_nextmid(struct smb_vc *vcp) 1001 { 1002 uint16_t r; 1003 1004 r = atomic_inc_16_nv(&vcp->vc_mid); 1005 return (r); 1006 } 1007 1008 /* 1009 * Get a pointer to the IP address suitable for passing to Trusted 1010 * Extensions find_tpc() routine. Used by smbfs_mount_label_policy(). 1011 * Compare this code to nfs_mount_label_policy() if problems arise. 1012 * Without support for direct CIFS-over-TCP, we should always see 1013 * an AF_NETBIOS sockaddr here. 1014 */ 1015 void * 1016 smb_vc_getipaddr(struct smb_vc *vcp, int *ipvers) 1017 { 1018 switch (vcp->vc_paddr->sa_family) { 1019 case AF_NETBIOS: { 1020 struct sockaddr_nb *snb; 1021 1022 *ipvers = IPV4_VERSION; 1023 /*LINTED*/ 1024 snb = (struct sockaddr_nb *)vcp->vc_paddr; 1025 return ((void *)&snb->snb_ipaddr); 1026 } 1027 case AF_INET: { 1028 struct sockaddr_in *sin; 1029 1030 *ipvers = IPV4_VERSION; 1031 /*LINTED*/ 1032 sin = (struct sockaddr_in *)vcp->vc_paddr; 1033 return ((void *)&sin->sin_addr); 1034 } 1035 case AF_INET6: { 1036 struct sockaddr_in6 *sin6; 1037 1038 *ipvers = IPV6_VERSION; 1039 /*LINTED*/ 1040 sin6 = (struct sockaddr_in6 *)vcp->vc_paddr; 1041 return ((void *)&sin6->sin6_addr); 1042 } 1043 default: 1044 SMBSDEBUG("invalid address family %d\n", 1045 vcp->vc_paddr->sa_family); 1046 *ipvers = 0; 1047 return (NULL); 1048 } 1049 } 1050 1051 /* 1052 * Share implementation 1053 */ 1054 /* 1055 * Allocate share structure and attach it to the given VC 1056 * Connection expected to be locked on entry. Share will be returned 1057 * in locked state. 1058 */ 1059 /*ARGSUSED*/ 1060 int 1061 smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec, 1062 struct smb_cred *scred, struct smb_share **sspp) 1063 { 1064 static char objtype[] = "smb_ss"; 1065 struct smb_share *ssp; 1066 1067 ASSERT(MUTEX_HELD(&vcp->vc_lock)); 1068 1069 ssp = kmem_zalloc(sizeof (struct smb_share), KM_SLEEP); 1070 smb_co_init(SSTOCP(ssp), SMBL_SHARE, objtype); 1071 ssp->ss_co.co_free = smb_share_free; 1072 ssp->ss_co.co_gone = smb_share_gone; 1073 1074 ssp->ss_name = smb_strdup(shspec->name); 1075 ssp->ss_mount = NULL; 1076 if (shspec->pass && shspec->pass[0]) 1077 ssp->ss_pass = smb_strdup(shspec->pass); 1078 ssp->ss_type = shspec->stype; 1079 ssp->ss_tid = SMB_TID_UNKNOWN; 1080 ssp->ss_mode = shspec->rights & SMBM_MASK; 1081 ssp->ss_fsname = NULL; 1082 smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp)); 1083 *sspp = ssp; 1084 1085 return (0); 1086 } 1087 1088 /* 1089 * Normally called via smb_share_rele() 1090 * after co_usecount drops to zero. 1091 */ 1092 static void 1093 smb_share_free(struct smb_connobj *cp) 1094 { 1095 struct smb_share *ssp = CPTOSS(cp); 1096 1097 SMB_STRFREE(ssp->ss_name); 1098 SMB_STRFREE(ssp->ss_pass); 1099 SMB_STRFREE(ssp->ss_fsname); 1100 smb_co_done(SSTOCP(ssp)); 1101 kmem_free(ssp, sizeof (*ssp)); 1102 } 1103 1104 /* 1105 * Normally called via smb_share_rele() 1106 * after co_usecount drops to zero. 1107 * Also called via: smb_share_kill() 1108 */ 1109 static void 1110 smb_share_gone(struct smb_connobj *cp) 1111 { 1112 struct smb_cred scred; 1113 struct smb_share *ssp = CPTOSS(cp); 1114 1115 smb_credinit(&scred, curproc, NULL); 1116 smb_iod_shutdown_share(ssp); 1117 smb_smb_treedisconnect(ssp, &scred); 1118 smb_credrele(&scred); 1119 } 1120 1121 void 1122 smb_share_hold(struct smb_share *ssp) 1123 { 1124 smb_co_hold(SSTOCP(ssp)); 1125 } 1126 1127 void 1128 smb_share_rele(struct smb_share *ssp) 1129 { 1130 smb_co_rele(SSTOCP(ssp)); 1131 } 1132 1133 void 1134 smb_share_kill(struct smb_share *ssp) 1135 { 1136 smb_co_kill(SSTOCP(ssp)); 1137 } 1138 1139 1140 void 1141 smb_share_invalidate(struct smb_share *ssp) 1142 { 1143 ssp->ss_tid = SMB_TID_UNKNOWN; 1144 } 1145 1146 /* 1147 * Returns NON-zero if the share is valid. 1148 * Called with the share locked. 1149 */ 1150 int 1151 smb_share_valid(struct smb_share *ssp) 1152 { 1153 struct smb_vc *vcp = SSTOVC(ssp); 1154 1155 ASSERT(MUTEX_HELD(&ssp->ss_lock)); 1156 1157 if ((ssp->ss_flags & SMBS_CONNECTED) == 0) 1158 return (0); 1159 1160 if (ssp->ss_tid == SMB_TID_UNKNOWN) { 1161 SMBIODEBUG("found TID unknown\n"); 1162 ssp->ss_flags &= ~SMBS_CONNECTED; 1163 } 1164 1165 if (ssp->ss_vcgenid != vcp->vc_genid) { 1166 SMBIODEBUG("wrong genid\n"); 1167 ssp->ss_flags &= ~SMBS_CONNECTED; 1168 } 1169 1170 return (ssp->ss_flags & SMBS_CONNECTED); 1171 } 1172 1173 /* 1174 * Connect (or reconnect) a share object. 1175 * Called with the share locked. 1176 */ 1177 int 1178 smb_share_tcon(struct smb_share *ssp) 1179 { 1180 struct smb_vc *vcp = SSTOVC(ssp); 1181 clock_t tmo; 1182 int error; 1183 1184 ASSERT(MUTEX_HELD(&ssp->ss_lock)); 1185 1186 if (ssp->ss_flags & SMBS_CONNECTED) { 1187 SMBIODEBUG("alread connected?"); 1188 return (0); 1189 } 1190 1191 /* 1192 * Wait for completion of any state changes 1193 * that might be underway. 1194 */ 1195 while (ssp->ss_flags & SMBS_RECONNECTING) { 1196 ssp->ss_conn_waiters++; 1197 tmo = cv_wait_sig(&ssp->ss_conn_done, &ssp->ss_lock); 1198 ssp->ss_conn_waiters--; 1199 if (tmo == 0) { 1200 /* Interrupt! */ 1201 return (EINTR); 1202 } 1203 } 1204 1205 /* Did someone else do it for us? */ 1206 if (ssp->ss_flags & SMBS_CONNECTED) 1207 return (0); 1208 1209 /* 1210 * OK, we'll do the work. 1211 */ 1212 ssp->ss_flags |= SMBS_RECONNECTING; 1213 1214 /* Drop the lock while doing the call. */ 1215 SMB_SS_UNLOCK(ssp); 1216 error = smb_smb_treeconnect(ssp, &vcp->vc_scred); 1217 SMB_SS_LOCK(ssp); 1218 1219 if (!error) 1220 ssp->ss_flags |= SMBS_CONNECTED; 1221 ssp->ss_flags &= ~SMBS_RECONNECTING; 1222 1223 /* They can all go ahead! */ 1224 if (ssp->ss_conn_waiters) 1225 cv_broadcast(&ssp->ss_conn_done); 1226 1227 return (error); 1228 } 1229 1230 const char * 1231 smb_share_getpass(struct smb_share *ssp) 1232 { 1233 struct smb_vc *vcp; 1234 1235 if (ssp->ss_pass) 1236 return (ssp->ss_pass); 1237 vcp = SSTOVC(ssp); 1238 if (vcp->vc_pass) 1239 return (vcp->vc_pass); 1240 return (smb_emptypass); 1241 } 1242 1243 int 1244 smb_share_count(void) 1245 { 1246 struct smb_connobj *covc, *coss; 1247 struct smb_vc *vcp; 1248 zoneid_t zoneid = getzoneid(); 1249 int nshares = 0; 1250 1251 SMB_CO_LOCK(&smb_vclist); 1252 SLIST_FOREACH(covc, &smb_vclist.co_children, co_next) { 1253 vcp = CPTOVC(covc); 1254 1255 /* VCs in other zones are invisibile. */ 1256 if (vcp->vc_zoneid != zoneid) 1257 continue; 1258 1259 SMB_VC_LOCK(vcp); 1260 1261 /* var, head, next_field */ 1262 SLIST_FOREACH(coss, &(VCTOCP(vcp)->co_children), co_next) { 1263 nshares++; 1264 } 1265 1266 SMB_VC_UNLOCK(vcp); 1267 } 1268 SMB_CO_UNLOCK(&smb_vclist); 1269 1270 return (nshares); 1271 } 1272 1273 /* 1274 * Solaris zones support 1275 */ 1276 /*ARGSUSED*/ 1277 void 1278 lingering_vc(struct smb_vc *vc) 1279 { 1280 /* good place for a breakpoint */ 1281 DEBUG_ENTER("lingering VC"); 1282 } 1283 1284 /* 1285 * On zone shutdown, kill any IOD threads still running in this zone. 1286 */ 1287 /* ARGSUSED */ 1288 void 1289 nsmb_zone_shutdown(zoneid_t zoneid, void *data) 1290 { 1291 struct smb_connobj *co; 1292 struct smb_vc *vcp; 1293 1294 SMB_CO_LOCK(&smb_vclist); 1295 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { 1296 vcp = CPTOVC(co); 1297 1298 if (vcp->vc_zoneid != zoneid) 1299 continue; 1300 1301 /* 1302 * This will close the connection, and 1303 * cause the IOD thread to terminate. 1304 */ 1305 smb_vc_kill(vcp); 1306 } 1307 SMB_CO_UNLOCK(&smb_vclist); 1308 } 1309 1310 /* 1311 * On zone destroy, kill any IOD threads and free all resources they used. 1312 */ 1313 /* ARGSUSED */ 1314 void 1315 nsmb_zone_destroy(zoneid_t zoneid, void *data) 1316 { 1317 struct smb_connobj *co; 1318 struct smb_vc *vcp; 1319 1320 /* 1321 * We will repeat what should have already happened 1322 * in zone_shutdown to make things go away. 1323 * 1324 * There should have been an smb_vc_rele call 1325 * by now for all VCs in the zone. If not, 1326 * there's probably more we needed to do in 1327 * the shutdown call. 1328 */ 1329 1330 SMB_CO_LOCK(&smb_vclist); 1331 1332 if (smb_vclist.co_usecount > 1) { 1333 SMBERROR("%d connections still active\n", 1334 smb_vclist.co_usecount - 1); 1335 } 1336 1337 /* var, head, next_field */ 1338 SLIST_FOREACH(co, &smb_vclist.co_children, co_next) { 1339 vcp = CPTOVC(co); 1340 1341 if (vcp->vc_zoneid != zoneid) 1342 continue; 1343 1344 /* Debugging */ 1345 lingering_vc(vcp); 1346 } 1347 1348 SMB_CO_UNLOCK(&smb_vclist); 1349 } 1350