1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2000-2001 Boris Popov 5 * 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * Connection engine. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 #include <sys/malloc.h> 40 #include <sys/priv.h> 41 #include <sys/proc.h> 42 #include <sys/lock.h> 43 #include <sys/sysctl.h> 44 #include <sys/socketvar.h> 45 46 #include <sys/iconv.h> 47 48 #include <netsmb/smb.h> 49 #include <netsmb/smb_subr.h> 50 #include <netsmb/smb_conn.h> 51 #include <netsmb/smb_tran.h> 52 #include <netsmb/smb_trantcp.h> 53 54 static struct smb_connobj smb_vclist; 55 static int smb_vcnext = 1; /* next unique id for VC */ 56 57 SYSCTL_NODE(_net, OID_AUTO, smb, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 58 "SMB protocol"); 59 60 static MALLOC_DEFINE(M_SMBCONN, "smb_conn", "SMB connection"); 61 62 static void smb_co_init(struct smb_connobj *cp, int level, char *ilockname, 63 char *lockname); 64 static void smb_co_done(struct smb_connobj *cp); 65 static int smb_vc_disconnect(struct smb_vc *vcp); 66 static void smb_vc_free(struct smb_connobj *cp); 67 static void smb_vc_gone(struct smb_connobj *cp, struct smb_cred *scred); 68 static smb_co_free_t smb_share_free; 69 static smb_co_gone_t smb_share_gone; 70 71 static int smb_sysctl_treedump(SYSCTL_HANDLER_ARGS); 72 73 SYSCTL_PROC(_net_smb, OID_AUTO, treedump, 74 CTLFLAG_RD | CTLTYPE_OPAQUE | CTLFLAG_MPSAFE, 75 NULL, 0, smb_sysctl_treedump, "S,treedump", 76 "Requester tree"); 77 78 int 79 smb_sm_init(void) 80 { 81 82 smb_co_init(&smb_vclist, SMBL_SM, "smbsm ilock", "smbsm"); 83 sx_xlock(&smb_vclist.co_interlock); 84 smb_co_unlock(&smb_vclist); 85 sx_unlock(&smb_vclist.co_interlock); 86 return 0; 87 } 88 89 int 90 smb_sm_done(void) 91 { 92 93 /* XXX: hold the mutex */ 94 if (smb_vclist.co_usecount > 1) { 95 SMBERROR("%d connections still active\n", smb_vclist.co_usecount - 1); 96 return EBUSY; 97 } 98 smb_co_done(&smb_vclist); 99 return 0; 100 } 101 102 static int 103 smb_sm_lockvclist(void) 104 { 105 int error; 106 107 sx_xlock(&smb_vclist.co_interlock); 108 error = smb_co_lock(&smb_vclist); 109 sx_unlock(&smb_vclist.co_interlock); 110 111 return error; 112 } 113 114 static void 115 smb_sm_unlockvclist(void) 116 { 117 118 sx_xlock(&smb_vclist.co_interlock); 119 smb_co_unlock(&smb_vclist); 120 sx_unlock(&smb_vclist.co_interlock); 121 } 122 123 static int 124 smb_sm_lookupint(struct smb_vcspec *vcspec, struct smb_sharespec *shspec, 125 struct smb_cred *scred, struct smb_vc **vcpp) 126 { 127 struct smb_connobj *scp; 128 struct smb_vc *vcp; 129 int exact = 1; 130 int error; 131 132 vcspec->shspec = shspec; 133 error = ENOENT; 134 vcp = NULL; 135 SMBCO_FOREACH(scp, &smb_vclist) { 136 vcp = (struct smb_vc *)scp; 137 error = smb_vc_lock(vcp); 138 if (error) 139 continue; 140 141 if ((vcp->obj.co_flags & SMBV_PRIVATE) || 142 !CONNADDREQ(vcp->vc_paddr, vcspec->sap) || 143 strcmp(vcp->vc_username, vcspec->username) != 0) 144 goto err1; 145 if (vcspec->owner != SMBM_ANY_OWNER) { 146 if (vcp->vc_uid != vcspec->owner) 147 goto err1; 148 } else 149 exact = 0; 150 if (vcspec->group != SMBM_ANY_GROUP) { 151 if (vcp->vc_grp != vcspec->group) 152 goto err1; 153 } else 154 exact = 0; 155 if (vcspec->mode & SMBM_EXACT) { 156 if (!exact || (vcspec->mode & SMBM_MASK) != 157 vcp->vc_mode) 158 goto err1; 159 } 160 if (smb_vc_access(vcp, scred, vcspec->mode) != 0) 161 goto err1; 162 vcspec->ssp = NULL; 163 if (shspec) { 164 error = (int)smb_vc_lookupshare(vcp, shspec, scred, 165 &vcspec->ssp); 166 if (error) 167 goto fail; 168 } 169 error = 0; 170 break; 171 err1: 172 error = 1; 173 fail: 174 smb_vc_unlock(vcp); 175 } 176 if (vcp) { 177 smb_vc_ref(vcp); 178 *vcpp = vcp; 179 } 180 return (error); 181 } 182 183 int 184 smb_sm_lookup(struct smb_vcspec *vcspec, struct smb_sharespec *shspec, 185 struct smb_cred *scred, struct smb_vc **vcpp) 186 { 187 struct smb_vc *vcp; 188 struct smb_share *ssp = NULL; 189 int error; 190 191 *vcpp = vcp = NULL; 192 193 error = smb_sm_lockvclist(); 194 if (error) 195 return error; 196 error = smb_sm_lookupint(vcspec, shspec, scred, vcpp); 197 if (error == 0 || (vcspec->flags & SMBV_CREATE) == 0) { 198 smb_sm_unlockvclist(); 199 return error; 200 } 201 error = smb_sm_lookupint(vcspec, NULL, scred, &vcp); 202 if (error) { 203 error = smb_vc_create(vcspec, scred, &vcp); 204 if (error) 205 goto out; 206 error = smb_vc_connect(vcp, scred); 207 if (error) 208 goto out; 209 } 210 if (shspec == NULL) 211 goto out; 212 error = smb_share_create(vcp, shspec, scred, &ssp); 213 if (error) 214 goto out; 215 error = smb_smb_treeconnect(ssp, scred); 216 if (error == 0) 217 vcspec->ssp = ssp; 218 else 219 smb_share_put(ssp, scred); 220 out: 221 smb_sm_unlockvclist(); 222 if (error == 0) 223 *vcpp = vcp; 224 else if (vcp) { 225 smb_vc_lock(vcp); 226 smb_vc_put(vcp, scred); 227 } 228 return error; 229 } 230 231 /* 232 * Common code for connection object 233 */ 234 static void 235 smb_co_init(struct smb_connobj *cp, int level, char *ilockname, char *lockname) 236 { 237 SLIST_INIT(&cp->co_children); 238 sx_init_flags(&cp->co_interlock, ilockname, SX_RECURSE); 239 cv_init(&cp->co_lock, "smblock"); 240 cp->co_lockcnt = 0; 241 cp->co_locker = NULL; 242 cp->co_level = level; 243 cp->co_usecount = 1; 244 sx_xlock(&cp->co_interlock); 245 smb_co_lock(cp); 246 sx_unlock(&cp->co_interlock); 247 } 248 249 static void 250 smb_co_done(struct smb_connobj *cp) 251 { 252 253 sx_destroy(&cp->co_interlock); 254 cv_destroy(&cp->co_lock); 255 cp->co_locker = NULL; 256 cp->co_flags = 0; 257 cp->co_lockcnt = 0; 258 } 259 260 static void 261 smb_co_gone(struct smb_connobj *cp, struct smb_cred *scred) 262 { 263 struct smb_connobj *parent; 264 265 if (cp->co_gone) 266 cp->co_gone(cp, scred); 267 parent = cp->co_parent; 268 if (parent) { 269 sx_xlock(&parent->co_interlock); 270 smb_co_lock(parent); 271 sx_unlock(&parent->co_interlock); 272 SLIST_REMOVE(&parent->co_children, cp, smb_connobj, co_next); 273 smb_co_put(parent, scred); 274 } 275 if (cp->co_free) 276 cp->co_free(cp); 277 } 278 279 void 280 smb_co_ref(struct smb_connobj *cp) 281 { 282 283 sx_xlock(&cp->co_interlock); 284 cp->co_usecount++; 285 sx_unlock(&cp->co_interlock); 286 } 287 288 void 289 smb_co_rele(struct smb_connobj *cp, struct smb_cred *scred) 290 { 291 292 sx_xlock(&cp->co_interlock); 293 smb_co_unlock(cp); 294 if (cp->co_usecount > 1) { 295 cp->co_usecount--; 296 sx_unlock(&cp->co_interlock); 297 return; 298 } 299 if (cp->co_usecount == 0) { 300 SMBERROR("negative use_count for object %d", cp->co_level); 301 sx_unlock(&cp->co_interlock); 302 return; 303 } 304 cp->co_usecount--; 305 cp->co_flags |= SMBO_GONE; 306 sx_unlock(&cp->co_interlock); 307 smb_co_gone(cp, scred); 308 } 309 310 int 311 smb_co_get(struct smb_connobj *cp, struct smb_cred *scred) 312 { 313 int error; 314 315 MPASS(sx_xholder(&cp->co_interlock) == curthread); 316 cp->co_usecount++; 317 error = smb_co_lock(cp); 318 if (error) 319 cp->co_usecount--; 320 return error; 321 } 322 323 void 324 smb_co_put(struct smb_connobj *cp, struct smb_cred *scred) 325 { 326 327 sx_xlock(&cp->co_interlock); 328 if (cp->co_usecount > 1) { 329 cp->co_usecount--; 330 } else if (cp->co_usecount == 1) { 331 cp->co_usecount--; 332 cp->co_flags |= SMBO_GONE; 333 } else { 334 SMBERROR("negative usecount"); 335 } 336 smb_co_unlock(cp); 337 sx_unlock(&cp->co_interlock); 338 if ((cp->co_flags & SMBO_GONE) == 0) 339 return; 340 smb_co_gone(cp, scred); 341 } 342 343 int 344 smb_co_lock(struct smb_connobj *cp) 345 { 346 347 MPASS(sx_xholder(&cp->co_interlock) == curthread); 348 for (;;) { 349 if (cp->co_flags & SMBO_GONE) 350 return EINVAL; 351 if (cp->co_locker == NULL) { 352 cp->co_locker = curthread; 353 return 0; 354 } 355 if (cp->co_locker == curthread) { 356 cp->co_lockcnt++; 357 return 0; 358 } 359 cv_wait(&cp->co_lock, &cp->co_interlock); 360 } 361 } 362 363 void 364 smb_co_unlock(struct smb_connobj *cp) 365 { 366 367 MPASS(sx_xholder(&cp->co_interlock) == curthread); 368 MPASS(cp->co_locker == curthread); 369 if (cp->co_lockcnt != 0) { 370 cp->co_lockcnt--; 371 return; 372 } 373 cp->co_locker = NULL; 374 cv_signal(&cp->co_lock); 375 } 376 377 static void 378 smb_co_addchild(struct smb_connobj *parent, struct smb_connobj *child) 379 { 380 381 smb_co_ref(parent); 382 SLIST_INSERT_HEAD(&parent->co_children, child, co_next); 383 child->co_parent = parent; 384 } 385 386 /* 387 * Session implementation 388 */ 389 390 int 391 smb_vc_create(struct smb_vcspec *vcspec, 392 struct smb_cred *scred, struct smb_vc **vcpp) 393 { 394 struct smb_vc *vcp; 395 struct ucred *cred = scred->scr_cred; 396 uid_t uid = vcspec->owner; 397 gid_t gid = vcspec->group; 398 uid_t realuid = cred->cr_uid; 399 char *domain = vcspec->domain; 400 int error, isroot; 401 402 isroot = smb_suser(cred) == 0; 403 /* 404 * Only superuser can create VCs with different uid and gid 405 */ 406 if (uid != SMBM_ANY_OWNER && uid != realuid && !isroot) 407 return EPERM; 408 if (gid != SMBM_ANY_GROUP && !groupmember(gid, cred) && !isroot) 409 return EPERM; 410 411 vcp = smb_zmalloc(sizeof(*vcp), M_SMBCONN, M_WAITOK); 412 smb_co_init(VCTOCP(vcp), SMBL_VC, "smb_vc ilock", "smb_vc"); 413 vcp->obj.co_free = smb_vc_free; 414 vcp->obj.co_gone = smb_vc_gone; 415 vcp->vc_number = smb_vcnext++; 416 vcp->vc_timo = SMB_DEFRQTIMO; 417 vcp->vc_smbuid = SMB_UID_UNKNOWN; 418 vcp->vc_mode = vcspec->rights & SMBM_MASK; 419 vcp->obj.co_flags = vcspec->flags & (SMBV_PRIVATE | SMBV_SINGLESHARE); 420 vcp->vc_tdesc = &smb_tran_nbtcp_desc; 421 vcp->vc_seqno = 0; 422 vcp->vc_mackey = NULL; 423 vcp->vc_mackeylen = 0; 424 425 if (uid == SMBM_ANY_OWNER) 426 uid = realuid; 427 if (gid == SMBM_ANY_GROUP) 428 gid = cred->cr_groups[0]; 429 vcp->vc_uid = uid; 430 vcp->vc_grp = gid; 431 432 smb_sl_init(&vcp->vc_stlock, "vcstlock"); 433 error = ENOMEM; 434 435 vcp->vc_paddr = sodupsockaddr(vcspec->sap, M_WAITOK); 436 if (vcp->vc_paddr == NULL) 437 goto fail; 438 vcp->vc_laddr = sodupsockaddr(vcspec->lap, M_WAITOK); 439 if (vcp->vc_laddr == NULL) 440 goto fail; 441 vcp->vc_pass = smb_strdup(vcspec->pass); 442 if (vcp->vc_pass == NULL) 443 goto fail; 444 vcp->vc_domain = smb_strdup((domain && domain[0]) ? domain : 445 "NODOMAIN"); 446 if (vcp->vc_domain == NULL) 447 goto fail; 448 vcp->vc_srvname = smb_strdup(vcspec->srvname); 449 if (vcp->vc_srvname == NULL) 450 goto fail; 451 vcp->vc_username = smb_strdup(vcspec->username); 452 if (vcp->vc_username == NULL) 453 goto fail; 454 error = (int)iconv_open("tolower", vcspec->localcs, &vcp->vc_tolower); 455 if (error) 456 goto fail; 457 error = (int)iconv_open("toupper", vcspec->localcs, &vcp->vc_toupper); 458 if (error) 459 goto fail; 460 if (vcspec->servercs[0]) { 461 error = (int)iconv_open(vcspec->servercs, vcspec->localcs, 462 &vcp->vc_cp_toserver); 463 if (error) 464 goto fail; 465 error = (int)iconv_open(vcspec->localcs, vcspec->servercs, 466 &vcp->vc_cp_tolocal); 467 if (error) 468 goto fail; 469 vcp->vc_toserver = vcp->vc_cp_toserver; 470 vcp->vc_tolocal = vcp->vc_cp_tolocal; 471 iconv_add(ENCODING_UNICODE, ENCODING_UNICODE, SMB_UNICODE_NAME); 472 iconv_add(ENCODING_UNICODE, SMB_UNICODE_NAME, ENCODING_UNICODE); 473 error = (int)iconv_open(SMB_UNICODE_NAME, vcspec->localcs, 474 &vcp->vc_ucs_toserver); 475 if (!error) { 476 error = (int)iconv_open(vcspec->localcs, SMB_UNICODE_NAME, 477 &vcp->vc_ucs_tolocal); 478 } 479 if (error) { 480 if (vcp->vc_ucs_toserver) 481 iconv_close(vcp->vc_ucs_toserver); 482 vcp->vc_ucs_toserver = NULL; 483 vcp->vc_ucs_tolocal = NULL; 484 } 485 } 486 error = (int)smb_iod_create(vcp); 487 if (error) 488 goto fail; 489 *vcpp = vcp; 490 smb_co_addchild(&smb_vclist, VCTOCP(vcp)); 491 return (0); 492 493 fail: 494 smb_vc_put(vcp, scred); 495 return (error); 496 } 497 498 static void 499 smb_vc_free(struct smb_connobj *cp) 500 { 501 struct smb_vc *vcp = CPTOVC(cp); 502 503 if (vcp->vc_iod) 504 smb_iod_destroy(vcp->vc_iod); 505 SMB_STRFREE(vcp->vc_username); 506 SMB_STRFREE(vcp->vc_srvname); 507 SMB_STRFREE(vcp->vc_pass); 508 SMB_STRFREE(vcp->vc_domain); 509 if (vcp->vc_mackey) 510 free(vcp->vc_mackey, M_SMBTEMP); 511 if (vcp->vc_paddr) 512 free(vcp->vc_paddr, M_SONAME); 513 if (vcp->vc_laddr) 514 free(vcp->vc_laddr, M_SONAME); 515 if (vcp->vc_tolower) 516 iconv_close(vcp->vc_tolower); 517 if (vcp->vc_toupper) 518 iconv_close(vcp->vc_toupper); 519 if (vcp->vc_tolocal) 520 vcp->vc_tolocal = NULL; 521 if (vcp->vc_toserver) 522 vcp->vc_toserver = NULL; 523 if (vcp->vc_cp_tolocal) 524 iconv_close(vcp->vc_cp_tolocal); 525 if (vcp->vc_cp_toserver) 526 iconv_close(vcp->vc_cp_toserver); 527 if (vcp->vc_ucs_tolocal) 528 iconv_close(vcp->vc_ucs_tolocal); 529 if (vcp->vc_ucs_toserver) 530 iconv_close(vcp->vc_ucs_toserver); 531 smb_co_done(VCTOCP(vcp)); 532 smb_sl_destroy(&vcp->vc_stlock); 533 free(vcp, M_SMBCONN); 534 } 535 536 /* 537 * Called when use count of VC dropped to zero. 538 */ 539 static void 540 smb_vc_gone(struct smb_connobj *cp, struct smb_cred *scred) 541 { 542 struct smb_vc *vcp = CPTOVC(cp); 543 544 smb_vc_disconnect(vcp); 545 } 546 547 void 548 smb_vc_ref(struct smb_vc *vcp) 549 { 550 smb_co_ref(VCTOCP(vcp)); 551 } 552 553 void 554 smb_vc_rele(struct smb_vc *vcp, struct smb_cred *scred) 555 { 556 smb_co_rele(VCTOCP(vcp), scred); 557 } 558 559 int 560 smb_vc_get(struct smb_vc *vcp, struct smb_cred *scred) 561 { 562 struct smb_connobj *cp; 563 int error; 564 565 cp = VCTOCP(vcp); 566 sx_xlock(&cp->co_interlock); 567 error = smb_co_get(cp, scred); 568 sx_unlock(&cp->co_interlock); 569 return error; 570 } 571 572 void 573 smb_vc_put(struct smb_vc *vcp, struct smb_cred *scred) 574 { 575 smb_co_put(VCTOCP(vcp), scred); 576 } 577 578 int 579 smb_vc_lock(struct smb_vc *vcp) 580 { 581 struct smb_connobj *cp; 582 int error; 583 584 cp = VCTOCP(vcp); 585 sx_xlock(&cp->co_interlock); 586 error = smb_co_lock(cp); 587 sx_unlock(&cp->co_interlock); 588 return error; 589 } 590 591 void 592 smb_vc_unlock(struct smb_vc *vcp) 593 { 594 595 struct smb_connobj *cp; 596 597 cp = VCTOCP(vcp); 598 sx_xlock(&cp->co_interlock); 599 smb_co_unlock(cp); 600 sx_unlock(&cp->co_interlock); 601 } 602 603 int 604 smb_vc_access(struct smb_vc *vcp, struct smb_cred *scred, mode_t mode) 605 { 606 struct ucred *cred = scred->scr_cred; 607 608 if (smb_suser(cred) == 0 || cred->cr_uid == vcp->vc_uid) 609 return 0; 610 mode >>= 3; 611 if (!groupmember(vcp->vc_grp, cred)) 612 mode >>= 3; 613 return (vcp->vc_mode & mode) == mode ? 0 : EACCES; 614 } 615 616 static int 617 smb_vc_cmpshare(struct smb_share *ssp, struct smb_sharespec *dp) 618 { 619 int exact = 1; 620 621 if (strcmp(ssp->ss_name, dp->name) != 0) 622 return 1; 623 if (dp->owner != SMBM_ANY_OWNER) { 624 if (ssp->ss_uid != dp->owner) 625 return 1; 626 } else 627 exact = 0; 628 if (dp->group != SMBM_ANY_GROUP) { 629 if (ssp->ss_grp != dp->group) 630 return 1; 631 } else 632 exact = 0; 633 634 if (dp->mode & SMBM_EXACT) { 635 if (!exact) 636 return 1; 637 return (dp->mode & SMBM_MASK) == ssp->ss_mode ? 0 : 1; 638 } 639 if (smb_share_access(ssp, dp->scred, dp->mode) != 0) 640 return 1; 641 return 0; 642 } 643 644 /* 645 * Lookup share in the given VC. Share referenced and locked on return. 646 * VC expected to be locked on entry and will be left locked on exit. 647 */ 648 int 649 smb_vc_lookupshare(struct smb_vc *vcp, struct smb_sharespec *dp, 650 struct smb_cred *scred, struct smb_share **sspp) 651 { 652 struct smb_connobj *scp = NULL; 653 struct smb_share *ssp = NULL; 654 int error; 655 656 *sspp = NULL; 657 dp->scred = scred; 658 SMBCO_FOREACH(scp, VCTOCP(vcp)) { 659 ssp = (struct smb_share *)scp; 660 error = smb_share_lock(ssp); 661 if (error) 662 continue; 663 if (smb_vc_cmpshare(ssp, dp) == 0) 664 break; 665 smb_share_unlock(ssp); 666 } 667 if (ssp) { 668 smb_share_ref(ssp); 669 *sspp = ssp; 670 error = 0; 671 } else 672 error = ENOENT; 673 return error; 674 } 675 676 int 677 smb_vc_connect(struct smb_vc *vcp, struct smb_cred *scred) 678 { 679 680 return smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL); 681 } 682 683 /* 684 * Destroy VC to server, invalidate shares linked with it. 685 * Transport should be locked on entry. 686 */ 687 int 688 smb_vc_disconnect(struct smb_vc *vcp) 689 { 690 691 if (vcp->vc_iod != NULL) 692 smb_iod_request(vcp->vc_iod, SMBIOD_EV_DISCONNECT | 693 SMBIOD_EV_SYNC, NULL); 694 return 0; 695 } 696 697 static char smb_emptypass[] = ""; 698 699 const char * 700 smb_vc_getpass(struct smb_vc *vcp) 701 { 702 if (vcp->vc_pass) 703 return vcp->vc_pass; 704 return smb_emptypass; 705 } 706 707 static int 708 smb_vc_getinfo(struct smb_vc *vcp, struct smb_vc_info *vip) 709 { 710 bzero(vip, sizeof(struct smb_vc_info)); 711 vip->itype = SMB_INFO_VC; 712 vip->usecount = vcp->obj.co_usecount; 713 vip->uid = vcp->vc_uid; 714 vip->gid = vcp->vc_grp; 715 vip->mode = vcp->vc_mode; 716 vip->flags = vcp->obj.co_flags; 717 vip->sopt = vcp->vc_sopt; 718 vip->iodstate = vcp->vc_iod->iod_state; 719 bzero(&vip->sopt.sv_skey, sizeof(vip->sopt.sv_skey)); 720 snprintf(vip->srvname, sizeof(vip->srvname), "%s", vcp->vc_srvname); 721 snprintf(vip->vcname, sizeof(vip->vcname), "%s", vcp->vc_username); 722 return 0; 723 } 724 725 u_short 726 smb_vc_nextmid(struct smb_vc *vcp) 727 { 728 u_short r; 729 730 sx_xlock(&vcp->obj.co_interlock); 731 r = vcp->vc_mid++; 732 sx_unlock(&vcp->obj.co_interlock); 733 return r; 734 } 735 736 /* 737 * Share implementation 738 */ 739 /* 740 * Allocate share structure and attach it to the given VC 741 * Connection expected to be locked on entry. Share will be returned 742 * in locked state. 743 */ 744 int 745 smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec, 746 struct smb_cred *scred, struct smb_share **sspp) 747 { 748 struct smb_share *ssp; 749 struct ucred *cred = scred->scr_cred; 750 uid_t realuid = cred->cr_uid; 751 uid_t uid = shspec->owner; 752 gid_t gid = shspec->group; 753 int error, isroot; 754 755 isroot = smb_suser(cred) == 0; 756 /* 757 * Only superuser can create shares with different uid and gid 758 */ 759 if (uid != SMBM_ANY_OWNER && uid != realuid && !isroot) 760 return EPERM; 761 if (gid != SMBM_ANY_GROUP && !groupmember(gid, cred) && !isroot) 762 return EPERM; 763 error = smb_vc_lookupshare(vcp, shspec, scred, &ssp); 764 if (!error) { 765 smb_share_put(ssp, scred); 766 return EEXIST; 767 } 768 if (uid == SMBM_ANY_OWNER) 769 uid = realuid; 770 if (gid == SMBM_ANY_GROUP) 771 gid = cred->cr_groups[0]; 772 ssp = smb_zmalloc(sizeof(*ssp), M_SMBCONN, M_WAITOK); 773 smb_co_init(SSTOCP(ssp), SMBL_SHARE, "smbss ilock", "smbss"); 774 ssp->obj.co_free = smb_share_free; 775 ssp->obj.co_gone = smb_share_gone; 776 smb_sl_init(&ssp->ss_stlock, "ssstlock"); 777 ssp->ss_name = smb_strdup(shspec->name); 778 if (shspec->pass && shspec->pass[0]) 779 ssp->ss_pass = smb_strdup(shspec->pass); 780 ssp->ss_type = shspec->stype; 781 ssp->ss_tid = SMB_TID_UNKNOWN; 782 ssp->ss_uid = uid; 783 ssp->ss_grp = gid; 784 ssp->ss_mode = shspec->rights & SMBM_MASK; 785 smb_co_addchild(VCTOCP(vcp), SSTOCP(ssp)); 786 *sspp = ssp; 787 return 0; 788 } 789 790 static void 791 smb_share_free(struct smb_connobj *cp) 792 { 793 struct smb_share *ssp = CPTOSS(cp); 794 795 SMB_STRFREE(ssp->ss_name); 796 SMB_STRFREE(ssp->ss_pass); 797 smb_sl_destroy(&ssp->ss_stlock); 798 smb_co_done(SSTOCP(ssp)); 799 free(ssp, M_SMBCONN); 800 } 801 802 static void 803 smb_share_gone(struct smb_connobj *cp, struct smb_cred *scred) 804 { 805 struct smb_share *ssp = CPTOSS(cp); 806 807 smb_smb_treedisconnect(ssp, scred); 808 } 809 810 void 811 smb_share_ref(struct smb_share *ssp) 812 { 813 smb_co_ref(SSTOCP(ssp)); 814 } 815 816 void 817 smb_share_rele(struct smb_share *ssp, struct smb_cred *scred) 818 { 819 smb_co_rele(SSTOCP(ssp), scred); 820 } 821 822 int 823 smb_share_get(struct smb_share *ssp, struct smb_cred *scred) 824 { 825 struct smb_connobj *cp = SSTOCP(ssp); 826 int error; 827 828 sx_xlock(&cp->co_interlock); 829 error = smb_co_get(cp, scred); 830 sx_unlock(&cp->co_interlock); 831 return error; 832 } 833 834 void 835 smb_share_put(struct smb_share *ssp, struct smb_cred *scred) 836 { 837 838 smb_co_put(SSTOCP(ssp), scred); 839 } 840 841 int 842 smb_share_lock(struct smb_share *ssp) 843 { 844 struct smb_connobj *cp; 845 int error; 846 847 cp = SSTOCP(ssp); 848 sx_xlock(&cp->co_interlock); 849 error = smb_co_lock(cp); 850 sx_unlock(&cp->co_interlock); 851 return error; 852 } 853 854 void 855 smb_share_unlock(struct smb_share *ssp) 856 { 857 struct smb_connobj *cp; 858 859 cp = SSTOCP(ssp); 860 sx_xlock(&cp->co_interlock); 861 smb_co_unlock(cp); 862 sx_unlock(&cp->co_interlock); 863 } 864 865 int 866 smb_share_access(struct smb_share *ssp, struct smb_cred *scred, mode_t mode) 867 { 868 struct ucred *cred = scred->scr_cred; 869 870 if (smb_suser(cred) == 0 || cred->cr_uid == ssp->ss_uid) 871 return 0; 872 mode >>= 3; 873 if (!groupmember(ssp->ss_grp, cred)) 874 mode >>= 3; 875 return (ssp->ss_mode & mode) == mode ? 0 : EACCES; 876 } 877 878 void 879 smb_share_invalidate(struct smb_share *ssp) 880 { 881 ssp->ss_tid = SMB_TID_UNKNOWN; 882 } 883 884 int 885 smb_share_valid(struct smb_share *ssp) 886 { 887 return ssp->ss_tid != SMB_TID_UNKNOWN && 888 ssp->ss_vcgenid == SSTOVC(ssp)->vc_genid; 889 } 890 891 const char* 892 smb_share_getpass(struct smb_share *ssp) 893 { 894 struct smb_vc *vcp; 895 896 if (ssp->ss_pass) 897 return ssp->ss_pass; 898 vcp = SSTOVC(ssp); 899 if (vcp->vc_pass) 900 return vcp->vc_pass; 901 return smb_emptypass; 902 } 903 904 static int 905 smb_share_getinfo(struct smb_share *ssp, struct smb_share_info *sip) 906 { 907 bzero(sip, sizeof(struct smb_share_info)); 908 sip->itype = SMB_INFO_SHARE; 909 sip->usecount = ssp->obj.co_usecount; 910 sip->tid = ssp->ss_tid; 911 sip->type= ssp->ss_type; 912 sip->uid = ssp->ss_uid; 913 sip->gid = ssp->ss_grp; 914 sip->mode= ssp->ss_mode; 915 sip->flags = ssp->obj.co_flags; 916 snprintf(sip->sname, sizeof(sip->sname), "%s", ssp->ss_name); 917 return 0; 918 } 919 920 /* 921 * Dump an entire tree into sysctl call 922 */ 923 static int 924 smb_sysctl_treedump(SYSCTL_HANDLER_ARGS) 925 { 926 struct smb_connobj *scp1, *scp2; 927 struct smb_vc *vcp; 928 struct smb_share *ssp; 929 struct smb_vc_info vci; 930 struct smb_share_info ssi; 931 int error, itype; 932 933 error = sysctl_wire_old_buffer(req, 0); 934 if (error) 935 return (error); 936 error = smb_sm_lockvclist(); 937 if (error) 938 return error; 939 SMBCO_FOREACH(scp1, &smb_vclist) { 940 vcp = (struct smb_vc *)scp1; 941 error = smb_vc_lock(vcp); 942 if (error) 943 continue; 944 smb_vc_getinfo(vcp, &vci); 945 error = SYSCTL_OUT(req, &vci, sizeof(struct smb_vc_info)); 946 if (error) { 947 smb_vc_unlock(vcp); 948 break; 949 } 950 SMBCO_FOREACH(scp2, VCTOCP(vcp)) { 951 ssp = (struct smb_share *)scp2; 952 error = smb_share_lock(ssp); 953 if (error) { 954 error = 0; 955 continue; 956 } 957 smb_share_getinfo(ssp, &ssi); 958 smb_share_unlock(ssp); 959 error = SYSCTL_OUT(req, &ssi, sizeof(struct smb_share_info)); 960 if (error) 961 break; 962 } 963 smb_vc_unlock(vcp); 964 if (error) 965 break; 966 } 967 if (!error) { 968 itype = SMB_INFO_NONE; 969 error = SYSCTL_OUT(req, &itype, sizeof(itype)); 970 } 971 smb_sm_unlockvclist(); 972 return error; 973 } 974