1/* 2 * Copyright (c) 2000-2001 Boris Popov 3 * All rights reserved. 4 * 5 * Portions Copyright (C) 2001 - 2013 Apple Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36/* 37 * Connection engine. 38 */ 39 40#include <sys/sysctl.h> /* can't avoid that */ 41 42#include <sys/smb_apple.h> 43#include <sys/kauth.h> 44 45#include <netsmb/smb.h> 46#include <netsmb/smb_2.h> 47#include <netsmb/smb_subr.h> 48#include <netsmb/smb_conn.h> 49#include <netsmb/smb_dev.h> 50#include <netsmb/smb_tran.h> 51#include <netsmb/smb_trantcp.h> 52#include <netsmb/smb_gss.h> 53#include <netsmb/netbios.h> 54 55extern uint32_t smbfs_deadtimer; 56 57static struct smb_connobj smb_vclist; 58static int smb_vcnext = 1; /* next unique id for VC */ 59 60extern struct linker_set sysctl_net_smb; 61 62SYSCTL_DECL(_net_smb); 63 64SYSCTL_NODE(_net, OID_AUTO, smb, CTLFLAG_RW, NULL, "SMB protocol"); 65 66static void smb_co_put(struct smb_connobj *cp, vfs_context_t context); 67 68/* 69 * The smb_co_lock, smb_co_unlock, smb_co_ref, smb_co_rel and smb_co_put deal 70 * with the vclist, vc and shares. So the vclist owns the vc which owns the share. 71 * Currently the share owns nothing even though it does have some relationship 72 * with mount structure. 73 */ 74static int smb_co_lock(struct smb_connobj *cp) 75{ 76 77 if (cp->co_flags & SMBO_GONE) 78 return EBUSY; 79 if (cp->co_lockowner == current_thread()) { 80 cp->co_lockcount++; 81 } else { 82 lck_mtx_lock(cp->co_lock); 83 /* We got the lock, but the VC is going away, so unlock it return EBUSY */ 84 if (cp->co_flags & SMBO_GONE) { 85 lck_mtx_unlock(cp->co_lock); 86 return EBUSY; 87 } 88 cp->co_lockowner = current_thread(); 89 cp->co_lockcount = 1; 90 } 91 return (0); 92} 93 94static void smb_co_unlock(struct smb_connobj *cp) 95{ 96 if (cp->co_lockowner && (cp->co_lockowner != current_thread())) { 97 SMBERROR("not owner of lock"); 98 } else if (cp->co_lockcount && (--cp->co_lockcount == 0)) { 99 cp->co_lockowner = NULL; 100 lck_mtx_unlock(cp->co_lock); 101 lck_mtx_lock(&(cp)->co_interlock); 102 if (cp->co_lock_flags & SMBFS_CO_LOCK_WAIT){ 103 cp->co_lock_flags &= ~SMBFS_CO_LOCK_WAIT; 104 lck_mtx_unlock(&(cp)->co_interlock); 105 wakeup(&cp->co_lock); 106 } else 107 lck_mtx_unlock(&(cp)->co_interlock); 108 } 109} 110 111/* 112 * Common code for connection object 113 */ 114static void 115smb_co_init(struct smb_connobj *cp, int level, const char *objname, struct proc *p) 116{ 117#pragma unused (objname, p) 118 SLIST_INIT(&cp->co_children); 119 lck_mtx_init(&cp->co_interlock, co_lck_group, co_lck_attr); 120 cp->co_lock = lck_mtx_alloc_init(co_lck_group, co_lck_attr); 121 cp->co_lock_flags = 0; 122 cp->co_lockowner = 0; 123 cp->co_lockcount = 0; 124 125 cp->co_level = level; 126 cp->co_usecount = 1; 127 KASSERT(smb_co_lock(cp) == 0, 128 ("smb_co_init: lock failed")); 129} 130 131static void smb_co_done(struct smb_connobj *cp) 132{ 133 lck_mtx_destroy(&cp->co_interlock, co_lck_group); 134 lck_mtx_free(cp->co_lock, co_lck_group); 135 cp->co_lock = 0; 136 cp->co_lock_flags = 0; 137 cp->co_lockowner = 0; 138 cp->co_lockcount = 0; 139} 140 141static void smb_co_gone(struct smb_connobj *cp, vfs_context_t context) 142{ 143 struct smb_connobj *parent; 144 145 /* Drain any locks that are still held */ 146 lck_mtx_lock(&(cp)->co_interlock); 147 while (cp->co_lockcount > 0) { 148 cp->co_lock_flags |= SMBFS_CO_LOCK_WAIT; 149 msleep(&cp->co_lock, &(cp)->co_interlock, 0, 0, 0); 150 } 151 lck_mtx_unlock(&(cp)->co_interlock); 152 /* 153 * The old code would take a smb_co_lock here. Since SMBO_GONE is set 154 * the smb_co_lock did nothing. So I removed that code. 155 */ 156 157 if (cp->co_gone) 158 cp->co_gone(cp, context); 159 parent = cp->co_parent; 160 if (parent) { 161 if (smb_co_lock(parent)) { 162 SMBERROR("unable to lock level %d\n", parent->co_level); 163 } else { 164 SLIST_REMOVE(&parent->co_children, cp, smb_connobj, 165 co_next); 166 smb_co_put(parent, context); 167 } 168 } 169 if (cp->co_free) 170 cp->co_free(cp); 171} 172 173static void smb_co_put(struct smb_connobj *cp, vfs_context_t context) 174{ 175 176 lck_mtx_lock(&(cp)->co_interlock); 177 if (cp->co_usecount > 1) { 178 cp->co_usecount--; 179 } else if (cp->co_usecount == 1) { 180 cp->co_usecount--; 181 cp->co_flags |= SMBO_GONE; 182 } else { 183 SMBERROR("negative usecount\n"); 184 } 185 lck_mtx_unlock(&(cp)->co_interlock); 186 smb_co_unlock(cp); 187 if ((cp->co_flags & SMBO_GONE) == 0) 188 return; 189 190 smb_co_gone(cp, context); 191} 192 193static void smb_co_ref(struct smb_connobj *cp) 194{ 195 lck_mtx_lock(&(cp)->co_interlock); 196 if (cp->co_flags & SMBO_GONE) { 197 /* 198 * This can happen when we are doing a tree disconnect or a VC log off. 199 * In the future we could fix the tree disconnect by only taking a reference 200 * on the VC. Not sure what to do about the VC. If we could solve those 201 * two issues then we should make this a fatal error. 202 */ 203 SMBDEBUG("The object is in the gone state level = 0x%x\n",cp->co_level); 204 } 205 cp->co_usecount++; 206 lck_mtx_unlock(&(cp)->co_interlock); 207} 208 209static void smb_co_addchild(struct smb_connobj *parent, struct smb_connobj *child) 210{ 211 smb_co_ref(parent); 212 SLIST_INSERT_HEAD(&parent->co_children, child, co_next); 213 child->co_parent = parent; 214} 215 216static void smb_co_rele(struct smb_connobj *cp, vfs_context_t context) 217{ 218 lck_mtx_lock(&(cp)->co_interlock); 219 if (cp->co_usecount > 1) { 220 cp->co_usecount--; 221 lck_mtx_unlock(&(cp)->co_interlock); 222 return; 223 } 224 if (cp->co_usecount == 0) { 225 SMBERROR("negative co_usecount for level %d\n", cp->co_level); 226 lck_mtx_unlock(&(cp)->co_interlock); 227 return; 228 } 229 cp->co_usecount--; 230 if (cp->co_flags & SMBO_GONE) { 231 lck_mtx_unlock(&(cp)->co_interlock); 232 return; /* someone is already draining */ 233 } 234 cp->co_flags |= SMBO_GONE; 235 lck_mtx_unlock(&(cp)->co_interlock); 236 237 smb_co_gone(cp, context); 238} 239 240struct sockaddr * 241smb_dup_sockaddr(struct sockaddr *sa, int canwait) 242{ 243 struct sockaddr *sa2; 244 245 SMB_MALLOC(sa2, struct sockaddr *, sa->sa_len, M_SONAME, 246 canwait ? M_WAITOK : M_NOWAIT); 247 if (sa2) 248 bcopy(sa, sa2, sa->sa_len); 249 return (sa2); 250} 251 252int smb_sm_init(void) 253{ 254 smb_co_init(&smb_vclist, SMBL_VCLIST, "smb_vclist", current_proc()); 255 smb_co_unlock(&smb_vclist); 256 return (0); 257} 258 259int smb_sm_done(void) 260{ 261 if (smb_vclist.co_usecount > 1) { 262 SMBERROR("%d connections still active\n", smb_vclist.co_usecount - 1); 263 return (EBUSY); 264 } 265 /* XXX Q4BP why are we not iterating on smb_vclist here with SMBCO_FOREACH? */ 266 smb_co_done(&smb_vclist); 267 return (0); 268} 269 270static void smb_sm_lockvclist() 271{ 272 /* 273 * The smb_vclist never goes away so there is no way for smb_co_lock 274 * to fail in this case. 275 */ 276 KASSERT((smb_co_lock(&smb_vclist) == 0), ("smb_sm_lockvclist: lock failed")); 277} 278 279static void smb_sm_unlockvclist() 280{ 281 smb_co_unlock(&smb_vclist); 282} 283 284/* 285 * This routine will reset the virtual circuit. When doing a reconnect we need to 286 * keep some of the virtual circuit information around. We only reset the information 287 * that is required to do the reconnect. 288 */ 289void smb_vc_reset(struct smb_vc *vcp) 290{ 291 /* 292 * If these three flags were set keep them for the reconnect. Clear out 293 * any other flags that may have been set in the original connection. 294 */ 295 vcp->vc_hflags2 &= (SMB_FLAGS2_EXT_SEC | SMB_FLAGS2_KNOWS_LONG_NAMES | SMB_FLAGS2_UNICODE); 296 297 vcp->vc_mid = 0; 298 vcp->vc_low_pid = 1; 299 300 vcp->vc_message_id = 1; 301 302 /* leave vc_misc_flags untouched as it has preferences flags */ 303 //vcp->vc_misc_flags = 0; 304 305 /* Save previous sessID for reconnects SessionSetup request */ 306 vcp->vc_prev_session_id = vcp->vc_session_id; 307 vcp->vc_session_id = 0; 308 309 vcp->vc_number = smb_vcnext++; 310 311 /* Reset the smb signing */ 312 smb_reset_sig(vcp); 313} 314 315void smb_vc_ref(struct smb_vc *vcp) 316{ 317 smb_co_ref(VCTOCP(vcp)); 318} 319 320void smb_vc_rele(struct smb_vc *vcp, vfs_context_t context) 321{ 322 smb_co_rele(VCTOCP(vcp), context); 323} 324 325static void smb_vc_put(struct smb_vc *vcp, vfs_context_t context) 326{ 327 smb_co_put(VCTOCP(vcp), context); 328} 329 330int smb_vc_lock(struct smb_vc *vcp) 331{ 332 return smb_co_lock(VCTOCP(vcp)); 333} 334 335void smb_vc_unlock(struct smb_vc *vcp) 336{ 337 smb_co_unlock(VCTOCP(vcp)); 338} 339 340static void smb_vc_free(struct smb_connobj *cp) 341{ 342 struct smb_vc *vcp = (struct smb_vc*)cp; 343 344 smb_gss_rel_cred(vcp); 345 346 if (vcp->vc_iod) 347 smb_iod_destroy(vcp->vc_iod); 348 vcp->vc_iod = NULL; 349 350 if (vcp->negotiate_token) { 351 SMB_FREE(vcp->negotiate_token, M_SMBTEMP); 352 } 353 354 if (vcp->NativeOS) { 355 SMB_FREE(vcp->NativeOS, M_SMBSTR); 356 } 357 358 if (vcp->NativeLANManager) { 359 SMB_FREE(vcp->NativeLANManager, M_SMBSTR); 360 } 361 362 if (vcp->vc_username) { 363 SMB_FREE(vcp->vc_username, M_SMBSTR); 364 } 365 366 if (vcp->vc_srvname) { 367 SMB_FREE(vcp->vc_srvname, M_SMBSTR); 368 } 369 370 if (vcp->vc_localname) { 371 SMB_FREE(vcp->vc_localname, M_SMBSTR); 372 } 373 374 if (vcp->vc_pass) { 375 SMB_FREE(vcp->vc_pass, M_SMBSTR); 376 } 377 378 if (vcp->vc_domain) { 379 SMB_FREE(vcp->vc_domain, M_SMBSTR); 380 } 381 382 if (vcp->vc_mackey) { 383 SMB_FREE(vcp->vc_mackey, M_SMBTEMP); 384 } 385 386 if (vcp->vc_saddr) { 387 SMB_FREE(vcp->vc_saddr, M_SONAME); 388 } 389 390 if (vcp->vc_laddr) { 391 SMB_FREE(vcp->vc_laddr, M_SONAME); 392 } 393 394 smb_gss_destroy(&vcp->vc_gss); 395 396 if (vcp->throttle_info) 397 throttle_info_release(vcp->throttle_info); 398 vcp->throttle_info = NULL; 399 400 if (vcp->vc_model_info) { 401 SMB_FREE(vcp->vc_model_info, M_SMBTEMP); 402 } 403 404 smb_co_done(VCTOCP(vcp)); 405 lck_mtx_destroy(&vcp->vc_stlock, vcst_lck_group); 406 if (vcp) { 407 SMB_FREE(vcp, M_SMBCONN); 408 } 409} 410 411/* 412 * Force reconnect on vc 413 */ 414int smb_vc_force_reconnect(struct smb_vc *vcp) 415{ 416 if (vcp->vc_iod) { 417 smb_iod_request(vcp->vc_iod, SMBIOD_EV_FORCE_RECONNECT | SMBIOD_EV_SYNC, NULL); 418 } 419 420 return (0); 421} 422 423/* 424 * Destroy VC to server, invalidate shares linked with it. 425 * Transport should be locked on entry. 426 */ 427static int smb_vc_disconnect(struct smb_vc *vcp) 428{ 429 if (vcp->vc_iod) 430 smb_iod_request(vcp->vc_iod, SMBIOD_EV_DISCONNECT | SMBIOD_EV_SYNC, NULL); 431 return (0); 432} 433 434/* 435 * Called when use count of VC dropped to zero. 436 * VC should be locked on enter with LK_DRAIN. 437 */ 438static void smb_vc_gone(struct smb_connobj *cp, vfs_context_t context) 439{ 440#pragma unused(context) 441 struct smb_vc *vcp = (struct smb_vc*)cp; 442 smb_vc_disconnect(vcp); 443} 444 445static int smb_vc_create(struct smbioc_negotiate *vcspec, 446 struct sockaddr *saddr, struct sockaddr *laddr, 447 vfs_context_t context, struct smb_vc **vcpp) 448{ 449 struct smb_vc *vcp; 450 int error = 0; 451 452 /* Should never happen, but just to be safe */ 453 if (context == NULL) { 454 return ENOTSUP; 455 } 456 SMB_MALLOC(vcp, struct smb_vc *, sizeof(*vcp), M_SMBCONN, M_WAITOK | M_ZERO); 457 smb_co_init(VCTOCP(vcp), SMBL_VC, "smb_vc", vfs_context_proc(context)); 458 vcp->obj.co_free = smb_vc_free; 459 vcp->obj.co_gone = smb_vc_gone; 460 vcp->vc_number = smb_vcnext++; 461 vcp->vc_timo = SMB_DEFRQTIMO; 462 vcp->vc_smbuid = SMB_UID_UNKNOWN; 463 vcp->vc_tdesc = &smb_tran_nbtcp_desc; 464 vcp->vc_seqno = 0; 465 vcp->vc_mackey = NULL; 466 vcp->vc_mackeylen = 0; 467 vcp->vc_smb3_signing_key_len = 0; 468 vcp->vc_smb3_encrypt_key_len = 0; 469 vcp->vc_smb3_decrypt_key_len = 0; 470 vcp->vc_saddr = saddr; 471 vcp->vc_laddr = laddr; 472 /* Remove any user setable items */ 473 vcp->vc_flags &= ~SMBV_USER_LAND_MASK; 474 /* Now add the users setable items */ 475 vcp->vc_flags |= (vcspec->ioc_userflags & SMBV_USER_LAND_MASK); 476 477 /* Now add the throttle info */ 478 vcp->throttle_info = throttle_info_create(); 479#ifdef DEBUG_TURN_OFF_EXT_SEC 480 vcp->vc_hflags2 = SMB_FLAGS2_KNOWS_LONG_NAMES; 481#else // DEBUG_TURN_OFF_EXT_SEC 482 vcp->vc_hflags2 = SMB_FLAGS2_KNOWS_LONG_NAMES | SMB_FLAGS2_EXT_SEC | SMB_FLAGS2_UNICODE; 483#endif // DEBUG_TURN_OFF_EXT_SEC 484 485 vcp->vc_uid = vcspec->ioc_ssn.ioc_owner; 486 vcp->vc_gss.gss_asid = AU_ASSIGN_ASID; 487 488 /* Amount of time to wait while reconnecting */ 489 vcp->reconnect_wait_time = vcspec->ioc_ssn.ioc_reconnect_wait_time; 490 491 lck_mtx_init(&vcp->vc_credits_lock, vc_credits_lck_group, vc_credits_lck_attr); 492 493 lck_mtx_init(&vcp->vc_stlock, vcst_lck_group, vcst_lck_attr); 494 495 vcp->vc_srvname = smb_strndup(vcspec->ioc_ssn.ioc_srvname, sizeof(vcspec->ioc_ssn.ioc_srvname)); 496 if (vcp->vc_srvname) 497 vcp->vc_localname = smb_strndup(vcspec->ioc_ssn.ioc_localname, sizeof(vcspec->ioc_ssn.ioc_localname)); 498 if ((vcp->vc_srvname == NULL) || (vcp->vc_localname == NULL)) { 499 error = ENOMEM; 500 } 501 502 vcp->vc_message_id = 1; 503 vcp->vc_misc_flags = SMBV_HAS_FILEIDS; /* assume File IDs supported */ 504 vcp->vc_server_caps = 0; 505 vcp->vc_volume_caps = 0; 506 vcp->vc_model_info = NULL; 507 508 if (!error) 509 error = smb_iod_create(vcp); 510 if (error) { 511 smb_vc_put(vcp, context); 512 return error; 513 } 514 *vcpp = vcp; 515 516 /* is SMB 1 or SMB 2/3 only flags set? */ 517 if (vcspec->ioc_extra_flags & SMB_SMB1_ONLY) { 518 vcp->vc_misc_flags |= SMBV_NEG_SMB1_ONLY; 519 } 520 else if (vcspec->ioc_extra_flags & SMB_SMB2_ONLY) { 521 vcp->vc_misc_flags |= SMBV_NEG_SMB2_ONLY; 522 } 523 else if (vcspec->ioc_extra_flags & SMB_SMB3_ONLY) { 524 vcp->vc_misc_flags |= SMBV_NEG_SMB3_ONLY; 525 } 526 527 if (vcspec->ioc_extra_flags & SMB_SIGNING_REQUIRED) { 528 vcp->vc_misc_flags |= SMBV_CLIENT_SIGNING_REQUIRED; 529 } 530 531 /* Save client Guid */ 532 memcpy(vcp->vc_client_guid, vcspec->ioc_client_guid, sizeof(vcp->vc_client_guid)); 533 534 /* Set default max amount of time to wait for any response from server */ 535 if ((vcspec->ioc_max_resp_timeout != 0) && 536 (vcspec->ioc_max_resp_timeout <= 600)) { 537 vcp->vc_resp_wait_timeout = vcspec->ioc_max_resp_timeout; 538 SMBWARNING("vc_resp_wait_timeout changed from default to %d \n", vcp->vc_resp_wait_timeout); 539 } 540 else { 541 vcp->vc_resp_wait_timeout = SMB_RESP_WAIT_TIMO; 542 } 543 544 smb_sm_lockvclist(); 545 smb_co_addchild(&smb_vclist, VCTOCP(vcp)); 546 smb_sm_unlockvclist(); 547 return 0; 548} 549 550/* 551 * So we have three types of sockaddr strcutures, IPv4, IPv6 or NetBIOS. 552 * 553 * If both sa_family equal AF_NETBIOS then we can just compare the two sockaddr 554 * structures. 555 * 556 * If neither sa_family equal AF_NETBIOS then we can just compare the two sockaddr 557 * structures. 558 * 559 * If the search sa_family equal AF_NETBIOS and the vc sa_family doesn't then we 560 * can just compare, since its its not going to match. We never support sharing 561 * a AF_NETBIOS with a non AF_NETBIOS connection. 562 * 563 * Now that just leaves the cases were the VC is connected using AF_NETBIOS and 564 * the search sockaddr is either IPv4 or IPv6. We need to compare using the real 565 * sockaddr that is inside the AF_NETBIOS sockaddr_nb structure. 566 */ 567static int addressMatch(struct smb_vc *vcp, struct sockaddr *saddr) 568{ 569 struct sockaddr *vc_saddr = vcp->vc_saddr; 570 571 if ((vc_saddr->sa_family == AF_NETBIOS) && (saddr->sa_family != AF_NETBIOS)) { 572 vc_saddr = (struct sockaddr *)&((struct sockaddr_nb *)vcp->vc_saddr)->snb_addrin; 573 } 574 575 if ((vc_saddr->sa_len == saddr->sa_len) && (memcmp(vc_saddr, saddr, saddr->sa_len) == 0)) 576 return TRUE; 577 578 return FALSE; 579} 580 581/* 582 * On success the vc will have a reference taken and a lock. 583 * 584 * Only smb_sm_negotiate passes sockaddr, all other routines need to pass in a 585 * vcp to search on. 586 */ 587static int smb_sm_lookupint(struct sockaddr *sap, uid_t owner, char *username, 588 uint32_t user_flags, struct smb_vc **vcpp) 589{ 590 struct smb_vc *vcp, *tvcp; 591 int error; 592 593 594 DBG_ASSERT(vcpp); /* Better have passed us a vcpp */ 595tryagain: 596 smb_sm_lockvclist(); 597 error = ENOENT; 598 SMBCO_FOREACH_SAFE(vcp, &smb_vclist, tvcp) { 599 600 if (*vcpp && vcp != *vcpp) 601 continue; 602 else if (*vcpp) { 603 /* Found a match, lock it, we are done. */ 604 error = smb_vc_lock(vcp); 605 if (error != 0) { 606 /* Can happen with bad servers */ 607 SMBDEBUG("smb_vc_lock returned error %d\n", error); 608 } 609 break; 610 } else { 611 /* 612 * We should only get in here from the negotiate routine. We better 613 * have a sock addr or thats a programming error. 614 */ 615 DBG_ASSERT(sap); 616 617 /* Don't share a vcp that hasn't been authenticated yet */ 618 if ((vcp->vc_flags & SMBV_AUTH_DONE) != SMBV_AUTH_DONE) { 619 continue; 620 } 621 622 /* The sock address structure needs to match. */ 623 if (!addressMatch(vcp, sap)) { 624 continue; 625 } 626 627 /* Must be the same owner */ 628 if (vcp->vc_uid != owner) { 629 continue; 630 } 631 632 /* Ok we have a lock on the vcp, any error needs to unlock it */ 633 error = smb_vc_lock(vcp); 634 /* 635 * This VC is going away, but it is currently block on the lock we 636 * hold for smb_vclist. We need to unlock the list and allow the VC 637 * to be remove. This still may not be the VC we were looking for so 638 * start the search again. 639 */ 640 if (error) { 641 smb_sm_unlockvclist(); 642 goto tryagain; 643 } 644 645 /* 646 * The VC must be active and not in reconnect, otherwise we should 647 * just skip this VC. 648 */ 649 if ((vcp->vc_iod->iod_state != SMBIOD_ST_VCACTIVE) || 650 (vcp->vc_iod->iod_flags & SMBIOD_RECONNECT)) { 651 SMBWARNING("Skipping %s because its down or in reconnect: flags = 0x%x state = 0x%x\n", 652 vcp->vc_srvname, vcp->vc_iod->iod_flags, vcp->vc_iod->iod_state); 653 smb_vc_unlock(vcp); 654 error = ENOENT; 655 continue; 656 } 657 658 /* 659 * If they ask for authentication then the VC needs to match that 660 * authentication or we need to keep looking. So here are the 661 * scenarios we need to deal with here. 662 * 663 * 1. If they are asking for a private guest access and the VC has 664 * private guest access set then use this VC. If either is set, 665 * but not both then don't reuse the VC. 666 * 2. If they are asking for a anonymous access and the VC has 667 * anonymous access set then use this VC. If either is set, 668 * but not both then don't reuse the VC. 669 * 3. They are requesting kerberos access. If the current VC isn't 670 * using kerberos then don't reuse the vcp. 671 * 4. They are requesting guest access. If the current VC isn't 672 * using guest then don't reuse the VC. 673 * 4. They are using user level security. The VC user name needs to 674 * match the one passed in. 675 * 4. They don't care. Always use the authentication of this VC. 676 */ 677 if ((vcp->vc_flags & SMBV_SFS_ACCESS)) { 678 /* We're guest no matter what the user says, just use this VC */ 679 error = 0; 680 break; 681 } else if ((user_flags & SMBV_PRIV_GUEST_ACCESS) || (vcp->vc_flags & SMBV_PRIV_GUEST_ACCESS)) { 682 if ((user_flags & SMBV_PRIV_GUEST_ACCESS) && (vcp->vc_flags & SMBV_PRIV_GUEST_ACCESS)) { 683 error = 0; 684 break; 685 } else { 686 smb_vc_unlock(vcp); 687 error = ENOENT; 688 continue; 689 } 690 } else if ((user_flags & SMBV_ANONYMOUS_ACCESS) || (vcp->vc_flags & SMBV_ANONYMOUS_ACCESS)) { 691 if ((user_flags & SMBV_ANONYMOUS_ACCESS) && (vcp->vc_flags & SMBV_ANONYMOUS_ACCESS)) { 692 error = 0; 693 break; 694 } else { 695 smb_vc_unlock(vcp); 696 error = ENOENT; 697 continue; 698 } 699 } else if (user_flags & SMBV_KERBEROS_ACCESS) { 700 if (vcp->vc_flags & SMBV_KERBEROS_ACCESS) { 701 error = 0; 702 break; 703 } else { 704 smb_vc_unlock(vcp); 705 error = ENOENT; 706 continue; 707 } 708 } else if (user_flags & SMBV_GUEST_ACCESS) { 709 if (vcp->vc_flags & SMBV_GUEST_ACCESS) { 710 error = 0; 711 break; 712 } else { 713 smb_vc_unlock(vcp); 714 error = ENOENT; 715 continue; 716 } 717 } else if (username && username[0]) { 718 if (vcp->vc_username && 719 ((strncmp(vcp->vc_username, username, SMB_MAXUSERNAMELEN + 1)) == 0)) { 720 error = 0; 721 break; 722 } else { 723 smb_vc_unlock(vcp); 724 error = ENOENT; 725 continue; 726 } 727 } 728 error = 0; 729 break; 730 } 731 } 732 if (vcp && !error) { 733 smb_vc_ref(vcp); 734 *vcpp = vcp; 735 } 736 smb_sm_unlockvclist(); 737 return error; 738} 739 740int smb_sm_negotiate(struct smbioc_negotiate *vcspec, vfs_context_t context, 741 struct smb_vc **vcpp, struct smb_dev *sdp, int searchOnly) 742{ 743 struct smb_vc *vcp = NULL; 744 struct sockaddr *saddr = NULL, *laddr = NULL; 745 int error; 746 747 saddr = smb_memdupin(vcspec->ioc_kern_saddr, vcspec->ioc_saddr_len); 748 if (saddr == NULL) { 749 return ENOMEM; 750 } 751 752 *vcpp = vcp = NULL; 753 754 if (vcspec->ioc_extra_flags & SMB_FORCE_NEW_SESSION) { 755 error = ENOENT; /* Force a new virtual circuit session */ 756 } else { 757 error = smb_sm_lookupint(saddr, vcspec->ioc_ssn.ioc_owner, vcspec->ioc_user, 758 vcspec->ioc_userflags, &vcp); 759 } 760 761 if ((error == 0) || (searchOnly)) { 762 SMB_FREE(saddr, M_SMBDATA); 763 vcspec->ioc_extra_flags |= SMB_SHARING_VC; 764 } else { 765 /* NetBIOS connections require a local address */ 766 if (saddr->sa_family == AF_NETBIOS) { 767 laddr = smb_memdupin(vcspec->ioc_kern_laddr, vcspec->ioc_laddr_len); 768 if (laddr == NULL) { 769 SMB_FREE(saddr, M_SMBDATA); 770 return ENOMEM; 771 } 772 } 773 /* If smb_vc_create fails it will clean up saddr and laddr */ 774 error = smb_vc_create(vcspec, saddr, laddr, context, &vcp); 775 if (error == 0) { 776 /* Flags used to cancel the connection */ 777 vcp->connect_flag = &sdp->sd_flags; 778 error = smb_vc_negotiate(vcp, context); 779 vcp->connect_flag = NULL; 780 if (error) /* Remove the lock and reference */ 781 smb_vc_put(vcp, context); 782 } 783 } 784 if ((error == 0) && (vcp)) { 785 /* 786 * They don't want us to touch the home directory, remove the flag. This 787 * will prevent any shared sessions to touch the home directory when they 788 * shouldn't. 789 */ 790 if ((vcspec->ioc_userflags & SMBV_HOME_ACCESS_OK) != SMBV_HOME_ACCESS_OK) { 791 vcp->vc_flags &= ~SMBV_HOME_ACCESS_OK; 792 } 793 *vcpp = vcp; 794 smb_vc_unlock(vcp); 795 } 796 return error; 797} 798 799int smb_sm_ssnsetup(struct smb_vc *vcp, struct smbioc_setup *sspec, 800 vfs_context_t context) 801{ 802 int error; 803 804 /* 805 * Call smb_sm_lookupint to verify that the vcp is still on the 806 * list. If not found then something really bad has happen. Log 807 * it and just return the error. If smb_sm_lookupint returns without 808 * an error then the vcp will be locked and a refcnt will be taken. 809 */ 810 error = smb_sm_lookupint(NULL, 0, NULL, 0, &vcp); 811 if (error) { 812 SMBERROR("The virtual circtuit was not found: error = %d\n", error); 813 return error; 814 } 815 816 if ((vcp->vc_flags & SMBV_AUTH_DONE) == SMBV_AUTH_DONE) 817 goto done; /* Nothing more to do here */ 818 819 /* Remove any user setable items */ 820 vcp->vc_flags &= ~SMBV_USER_LAND_MASK; 821 /* Now add the users setable items */ 822 vcp->vc_flags |= (sspec->ioc_userflags & SMBV_USER_LAND_MASK); 823 /* 824 * Reset the username, password, domain, kerb client and service names. We 825 * never want to use any values left over from any previous calls. 826 */ 827 if (vcp->vc_username != NULL) { 828 SMB_FREE(vcp->vc_username, M_SMBSTR); 829 } 830 if (vcp->vc_pass != NULL) { 831 SMB_FREE(vcp->vc_pass, M_SMBSTR); 832 } 833 if (vcp->vc_domain != NULL) { 834 SMB_FREE(vcp->vc_domain, M_SMBSTR); 835 } 836 if (vcp->vc_gss.gss_cpn != NULL) { 837 SMB_FREE(vcp->vc_gss.gss_cpn, M_SMBSTR); 838 } 839 /* 840 * Freeing the SPN will make sure we never use the hint. Remember that the 841 * gss_spn contains the hint from the negotiate. We now require user 842 * land to send us a SPN, if we are going to use one. 843 */ 844 if (vcp->vc_gss.gss_spn != NULL) { 845 SMB_FREE(vcp->vc_gss.gss_spn, M_SMBSTR); 846 } 847 vcp->vc_username = smb_strndup(sspec->ioc_user, sizeof(sspec->ioc_user)); 848 vcp->vc_pass = smb_strndup(sspec->ioc_password, sizeof(sspec->ioc_password)); 849 vcp->vc_domain = smb_strndup(sspec->ioc_domain, sizeof(sspec->ioc_domain)); 850 851 if ((vcp->vc_pass == NULL) || (vcp->vc_domain == NULL) || 852 (vcp->vc_username == NULL)) { 853 error = ENOMEM; 854 goto done; 855 } 856 857 /* GSS principal names are only set if we are doing kerberos or ntlmssp */ 858 if (sspec->ioc_gss_client_size) { 859 vcp->vc_gss.gss_cpn = smb_memdupin(sspec->ioc_gss_client_name, sspec->ioc_gss_client_size); 860 } 861 vcp->vc_gss.gss_cpn_len = sspec->ioc_gss_client_size; 862 vcp->vc_gss.gss_client_nt = sspec->ioc_gss_client_nt; 863 864 if (sspec->ioc_gss_target_size) { 865 vcp->vc_gss.gss_spn = smb_memdupin(sspec->ioc_gss_target_name, sspec->ioc_gss_target_size); 866 } 867 vcp->vc_gss.gss_spn_len = sspec->ioc_gss_target_size; 868 vcp->vc_gss.gss_target_nt = sspec->ioc_gss_target_nt; 869 if (!(sspec->ioc_userflags & SMBV_ANONYMOUS_ACCESS)) { 870 SMB_LOG_AUTH("client size = %d client name type = %d\n", 871 sspec->ioc_gss_client_size, vcp->vc_gss.gss_client_nt); 872 SMB_LOG_AUTH("taget size = %d target name type = %d\n", 873 sspec->ioc_gss_target_size, vcp->vc_gss.gss_target_nt); 874 } 875 876 error = smb_vc_ssnsetup(vcp); 877 /* If no error then this virtual circuit has been authorized */ 878 if (error == 0) { 879 smb_gss_ref_cred(vcp); 880 vcp->vc_flags |= SMBV_AUTH_DONE; 881 } 882 883done: 884 if (error) { 885 /* 886 * Authorization failed, reset any authorization 887 * information. This includes removing guest access, 888 * user name, password and the domain name. We should 889 * not every return these values after authorization 890 * fails. 891 */ 892 vcp->vc_flags &= ~(SMBV_GUEST_ACCESS | SMBV_PRIV_GUEST_ACCESS | 893 SMBV_KERBEROS_ACCESS | SMBV_ANONYMOUS_ACCESS); 894 if (vcp->vc_username) { 895 SMB_FREE(vcp->vc_username, M_SMBSTR); 896 } 897 if (vcp->vc_pass) { 898 SMB_FREE(vcp->vc_pass, M_SMBSTR); 899 } 900 if (vcp->vc_domain) { 901 SMB_FREE(vcp->vc_domain, M_SMBSTR); 902 } 903 if (vcp->vc_gss.gss_cpn) { 904 SMB_FREE(vcp->vc_gss.gss_cpn, M_SMBSTR); 905 } 906 if (vcp->vc_gss.gss_spn) { 907 SMB_FREE(vcp->vc_gss.gss_spn, M_SMBSTR); 908 } 909 910 vcp->vc_gss.gss_spn_len = 0; 911 vcp->vc_gss.gss_cpn_len = 0; 912 } 913 914 /* Release the reference and lock that smb_sm_lookupint took on the vcp */ 915 smb_vc_put(vcp, context); 916 return error; 917} 918 919static void smb_share_free(struct smb_connobj *cp) 920{ 921 struct smb_share *share = (struct smb_share *)cp; 922 923 SMB_FREE(share->ss_name, M_SMBSTR); 924 lck_mtx_destroy(&share->ss_stlock, ssst_lck_group); 925 lck_mtx_destroy(&share->ss_shlock, ssst_lck_group); 926 lck_mtx_destroy(&share->ss_fid_lock, fid_lck_grp); 927 smb_co_done(SSTOCP(share)); 928 SMB_FREE(share, M_SMBCONN); 929} 930 931static void smb_share_gone(struct smb_connobj *cp, vfs_context_t context) 932{ 933 struct smb_share *share = (struct smb_share *)cp; 934 935 DBG_ASSERT(share); 936 DBG_ASSERT(SSTOVC(share)); 937 DBG_ASSERT(SSTOVC(share)->vc_iod); 938 smb_smb_treedisconnect(share, context); 939} 940 941void smb_share_ref(struct smb_share *share) 942{ 943 smb_co_ref(SSTOCP(share)); 944} 945 946void smb_share_rele(struct smb_share *share, vfs_context_t context) 947{ 948 smb_co_rele(SSTOCP(share), context); 949} 950 951/* 952 * Allocate share structure and attach it to the given VC. The vcp 953 * needs to be locked on entry. Share will be returned in unlocked state, 954 * but will have a reference on it. 955 */ 956static int 957smb_share_create(struct smb_vc *vcp, struct smbioc_share *shspec, 958 struct smb_share **outShare, vfs_context_t context) 959{ 960 struct smb_share *share; 961 int i; 962 963 /* Should never happen, but just to be safe */ 964 if (context == NULL) 965 return ENOTSUP; 966 967 SMB_MALLOC(share, struct smb_share *, sizeof(*share), M_SMBCONN, M_WAITOK | M_ZERO); 968 if (share == NULL) { 969 return ENOMEM; 970 } 971 share->ss_name = smb_strndup(shspec->ioc_share, sizeof(shspec->ioc_share)); 972 if (share->ss_name == NULL) { 973 SMB_FREE(share, M_SMBCONN); 974 return ENOMEM; 975 } 976 /* The smb_co_init routine locks the share and takes a reference */ 977 smb_co_init(SSTOCP(share), SMBL_SHARE, "smbss", vfs_context_proc(context)); 978 share->obj.co_free = smb_share_free; 979 share->obj.co_gone = smb_share_gone; 980 981 /* alloc FID mapping stuff */ 982 lck_mtx_init(&share->ss_fid_lock, fid_lck_grp, fid_lck_attr); 983 for (i = 0; i < SMB_FID_TABLE_SIZE; i++) { 984 LIST_INIT(&share->ss_fid_table[i].fid_list); 985 } 986 share->ss_fid_collisions = 0; 987 share->ss_fid_inserted = 0; 988 share->ss_fid_max_iter = 0; 989 990 lck_mtx_init(&share->ss_shlock, ssst_lck_group, ssst_lck_attr); 991 lck_mtx_init(&share->ss_stlock, ssst_lck_group, ssst_lck_attr); 992 lck_mtx_lock(&share->ss_shlock); 993 share->ss_mount = NULL; /* Just to be safe clear it out */ 994 /* Set the default dead timer */ 995 share->ss_dead_timer = smbfs_deadtimer; 996 lck_mtx_unlock(&share->ss_shlock); 997 share->ss_tid = SMB_TID_UNKNOWN; 998 share->ss_tree_id = SMB2_TID_UNKNOWN; 999 1000 /* unlock the share we no longer need the lock */ 1001 smb_co_unlock(SSTOCP(share)); 1002 smb_co_addchild(VCTOCP(vcp), SSTOCP(share)); 1003 *outShare = share; 1004 return (0); 1005} 1006 1007/* 1008 * If we already have a connection on the share take a reference and return. 1009 * Otherwise create the share, add it to the vc list and then do a tree 1010 * connect. 1011 */ 1012int smb_sm_tcon(struct smb_vc *vcp, struct smbioc_share *shspec, 1013 struct smb_share **shpp, vfs_context_t context) 1014{ 1015 int error; 1016 1017 *shpp = NULL; 1018 /* 1019 * Call smb_sm_lookupint to verify that the vcp is still on the 1020 * list. If not found then something really bad has happen. Log 1021 * it and just return the error. If smb_sm_lookupint returns without 1022 * an error then the vcp will be locked and a refcnt will be taken. 1023 */ 1024 error = smb_sm_lookupint(NULL, 0, NULL, 0, &vcp); 1025 if (error) { 1026 SMBERROR("The virtual circtuit was not found: error = %d\n", error); 1027 return error; 1028 } 1029 /* At this point we have a locked vcp create the share */ 1030 error = smb_share_create(vcp, shspec, shpp, context); 1031 /* 1032 * We hold a lock and reference on the vc. We are done with the vc lock 1033 * so unlock the vc but hold on to the vc references. 1034 */ 1035 smb_vc_unlock(vcp); 1036 if (error == 0) { 1037 error = smb_smb_treeconnect(*shpp, context); 1038 if (error) { 1039 /* Let the share drain, so it can get removed */ 1040 smb_share_rele(*shpp, context); 1041 *shpp = NULL; /* We failed reset it to NULL */ 1042 } 1043 } 1044 if (*shpp && (error == 0)) { 1045 shspec->ioc_optionalSupport = (*shpp)->optionalSupport; 1046 /* 1047 * ioc_fstype will always be 0 at this time because ss_fstype is filled 1048 * in at mount time. 1049 */ 1050 shspec->ioc_fstype = (*shpp)->ss_fstype; 1051 } 1052 1053 /* Release the reference that smb_sm_lookupint took on the vc */ 1054 smb_vc_rele(vcp, context); 1055 return error; 1056} 1057 1058int smb_vc_access(struct smb_vc *vcp, vfs_context_t context) 1059{ 1060 if (SMBV_HAS_GUEST_ACCESS(vcp)) 1061 return(0); 1062 1063 /* The smbfs_vnop_strategy routine has no context, we always allow these */ 1064 if (context == NULL) { 1065 return(0); 1066 } 1067 if ((vfs_context_suser(context) == 0) || 1068 (kauth_cred_getuid(vfs_context_ucred(context)) == vcp->vc_uid)) 1069 return (0); 1070 return (EACCES); 1071} 1072 1073int smb_vc_negotiate(struct smb_vc *vcp, vfs_context_t context) 1074{ 1075 return smb_iod_request(vcp->vc_iod, 1076 SMBIOD_EV_NEGOTIATE | SMBIOD_EV_SYNC, context); 1077} 1078 1079int smb_vc_ssnsetup(struct smb_vc *vcp) 1080{ 1081 return smb_iod_request(vcp->vc_iod, 1082 SMBIOD_EV_SSNSETUP | SMBIOD_EV_SYNC, NULL); 1083} 1084 1085static char smb_emptypass[] = ""; 1086 1087const char * smb_vc_getpass(struct smb_vc *vcp) 1088{ 1089 if (vcp->vc_pass) 1090 return vcp->vc_pass; 1091 return smb_emptypass; 1092} 1093 1094/* 1095 * They are in share level security and the share requires 1096 * a password. Use the vcp password always. On required for 1097 * Windows 98, should drop support someday. 1098 */ 1099const char * smb_share_getpass(struct smb_share *share) 1100{ 1101 DBG_ASSERT(SSTOVC(share)); 1102 return smb_vc_getpass(SSTOVC(share)); 1103} 1104 1105/* 1106 * The reconnect code needs to get a reference on the vc. First make sure 1107 * this vc is still in the list and no one has release it yet. If smb_sm_lookupint 1108 * finds it we will have it locked and a reference on it. Next make sure its 1109 * not being release. 1110 */ 1111int smb_vc_reconnect_ref(struct smb_vc *vcp, vfs_context_t context) 1112{ 1113 int error; 1114 1115 error = smb_sm_lookupint(NULL, 0, NULL, 0, &vcp); 1116 if (error) 1117 return error; 1118 1119 smb_vc_unlock(vcp); 1120 /* This vc is being release just give up */ 1121 if (vcp->ss_flags & SMBO_GONE) { 1122 smb_vc_rele(vcp, context); 1123 error = ENOTCONN; 1124 } 1125 return error; 1126} 1127 1128/* 1129 * Called from a thread that is not the main iod thread. Prevents us from 1130 * getting into a deadlock. 1131 */ 1132static void smb_reconnect_rel_thread(void *arg) 1133{ 1134 struct smbiod *iod = arg; 1135 1136 /* We are done release the reference */ 1137 smb_vc_rele(iod->iod_vc, iod->iod_context); 1138} 1139 1140/* 1141 * The reconnect code takes a reference on the vc. So we need to release that 1142 * reference, but if we are the last reference the smb_vc_rele routine will 1143 * attempt to destroy the vc, which will then attempt to destroy the main iod 1144 * thread for the vc. The reconnect code is running under the main iod thread, 1145 * which means we can't destroy the thread from that thread without hanging. So 1146 * start a new thread to just release the reference and do any cleanup required. 1147 * This will be a short live thread that just hangs around long enough to do the 1148 * work required to release the vc reference. 1149 */ 1150void smb_vc_reconnect_rel(struct smb_vc *vcp) 1151{ 1152 struct smbiod *iod = vcp->vc_iod; 1153 thread_t thread; 1154 int error; 1155 1156 do { 1157 error = kernel_thread_start((thread_continue_t)smb_reconnect_rel_thread, 1158 iod, &thread); 1159 /* 1160 * Never expect an error here, but just in case log it, sleep for one 1161 * second and try again. Nothing else we can do at this point. 1162 */ 1163 if (error) { 1164 struct timespec ts; 1165 1166 SMBERROR("Starting the reconnect vc release thread failed! %d\n", 1167 error); 1168 ts.tv_sec = 1; 1169 ts.tv_nsec = 0; 1170 msleep(iod, NULL, PWAIT | PCATCH, "smb_vc_reconnect_rel", &ts); 1171 } 1172 } while (error); 1173 thread_deallocate(thread); 1174} 1175 1176 1177