1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 25 * Copyright 2017 Joyent, Inc. 26 * Copyright 2020-2023 RackTop Systems, Inc. 27 */ 28 29 #include <smbsrv/smb_door.h> 30 #include <smbsrv/smb_ktypes.h> 31 #include <smbsrv/smb2_kproto.h> 32 #include <smbsrv/smb_kstat.h> 33 34 typedef struct smb_unshare { 35 list_node_t us_lnd; 36 char us_sharename[MAXNAMELEN]; 37 } smb_unshare_t; 38 39 static kmem_cache_t *smb_kshare_cache_share; 40 static kmem_cache_t *smb_kshare_cache_unexport; 41 42 static int smb_kshare_cmp(const void *, const void *); 43 static void smb_kshare_hold(const void *); 44 static boolean_t smb_kshare_rele(const void *); 45 static void smb_kshare_destroy(void *); 46 static char *smb_kshare_oemname(const char *); 47 static int smb_kshare_is_special(const char *); 48 static int smb_kshare_is_admin(const char *); 49 static smb_kshare_t *smb_kshare_decode(nvlist_t *); 50 static uint32_t smb_kshare_decode_bool(nvlist_t *, const char *, uint32_t); 51 static void smb_kshare_unexport_thread(smb_thread_t *, void *); 52 static int smb_kshare_export(smb_server_t *, smb_kshare_t *); 53 static int smb_kshare_unexport(smb_server_t *, const char *); 54 static int smb_kshare_export_trans(smb_server_t *, char *, char *, char *); 55 static void smb_kshare_csc_flags(smb_kshare_t *, const char *); 56 57 static boolean_t smb_export_isready(smb_server_t *); 58 59 #ifdef _KERNEL 60 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *); 61 #endif /* _KERNEL */ 62 63 static const smb_avl_nops_t smb_kshare_avlops = { 64 smb_kshare_cmp, 65 smb_kshare_hold, 66 smb_kshare_rele, 67 smb_kshare_destroy 68 }; 69 70 #ifdef _KERNEL 71 /* 72 * This function is not MultiThread safe. The caller has to make sure only one 73 * thread calls this function. 74 */ 75 door_handle_t 76 smb_kshare_door_init(int door_id) 77 { 78 return (door_ki_lookup(door_id)); 79 } 80 81 /* 82 * This function is not MultiThread safe. The caller has to make sure only one 83 * thread calls this function. 84 */ 85 void 86 smb_kshare_door_fini(door_handle_t dhdl) 87 { 88 if (dhdl) 89 door_ki_rele(dhdl); 90 } 91 92 /* 93 * This is a special interface that will be utilized by ZFS to cause 94 * a share to be added/removed 95 * 96 * arg is either a smb_share_t or share_name from userspace. 97 * It will need to be copied into the kernel. It is smb_share_t 98 * for add operations and share_name for delete operations. 99 */ 100 int 101 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share) 102 { 103 door_arg_t doorarg = { 0 }; 104 char *buf = NULL; 105 char *str = NULL; 106 int error; 107 int rc; 108 unsigned int used; 109 smb_dr_ctx_t *dec_ctx; 110 smb_dr_ctx_t *enc_ctx; 111 smb_share_t *lmshare = NULL; 112 int opcode; 113 114 opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE; 115 116 buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP); 117 enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE); 118 smb_dr_put_uint32(enc_ctx, opcode); 119 120 switch (opcode) { 121 case SMB_SHROP_ADD: 122 lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP); 123 error = xcopyin(arg, lmshare, sizeof (smb_share_t)); 124 if (error != 0) { 125 kmem_free(lmshare, sizeof (smb_share_t)); 126 kmem_free(buf, SMB_SHARE_DSIZE); 127 return (error); 128 } 129 smb_dr_put_share(enc_ctx, lmshare); 130 break; 131 132 case SMB_SHROP_DELETE: 133 str = kmem_alloc(MAXPATHLEN, KM_SLEEP); 134 error = copyinstr(arg, str, MAXPATHLEN, NULL); 135 if (error != 0) { 136 kmem_free(str, MAXPATHLEN); 137 kmem_free(buf, SMB_SHARE_DSIZE); 138 return (error); 139 } 140 smb_dr_put_string(enc_ctx, str); 141 kmem_free(str, MAXPATHLEN); 142 break; 143 } 144 145 if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) { 146 kmem_free(buf, SMB_SHARE_DSIZE); 147 if (lmshare) 148 kmem_free(lmshare, sizeof (smb_share_t)); 149 return (NERR_InternalError); 150 } 151 152 doorarg.data_ptr = buf; 153 doorarg.data_size = used; 154 doorarg.rbuf = buf; 155 doorarg.rsize = SMB_SHARE_DSIZE; 156 157 error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0); 158 159 if (error) { 160 kmem_free(buf, SMB_SHARE_DSIZE); 161 if (lmshare) 162 kmem_free(lmshare, sizeof (smb_share_t)); 163 return (error); 164 } 165 166 dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size); 167 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) { 168 kmem_free(buf, SMB_SHARE_DSIZE); 169 if (lmshare) 170 kmem_free(lmshare, sizeof (smb_share_t)); 171 return (NERR_InternalError); 172 } 173 174 rc = smb_dr_get_uint32(dec_ctx); 175 if (opcode == SMB_SHROP_ADD) 176 smb_dr_get_share(dec_ctx, lmshare); 177 178 if (smb_dr_decode_finish(dec_ctx)) 179 rc = NERR_InternalError; 180 181 kmem_free(buf, SMB_SHARE_DSIZE); 182 if (lmshare) 183 kmem_free(lmshare, sizeof (smb_share_t)); 184 185 return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc); 186 } 187 #endif /* _KERNEL */ 188 189 /* 190 * Executes map and unmap command for shares. 191 */ 192 int 193 smb_kshare_exec(smb_server_t *sv, smb_shr_execinfo_t *execinfo) 194 { 195 int exec_rc = 0; 196 197 (void) smb_kdoor_upcall(sv, SMB_DR_SHR_EXEC, 198 execinfo, smb_shr_execinfo_xdr, &exec_rc, xdr_int); 199 200 return (exec_rc); 201 } 202 203 /* 204 * Obtains any host access restriction on the specified 205 * share for the given host (ipaddr) by calling smbd 206 */ 207 uint32_t 208 smb_kshare_hostaccess(smb_kshare_t *shr, smb_session_t *session) 209 { 210 smb_shr_hostaccess_query_t req; 211 smb_inaddr_t *ipaddr = &session->ipaddr; 212 uint32_t host_access = SMB_SHRF_ACC_OPEN; 213 uint32_t flag = SMB_SHRF_ACC_OPEN; 214 uint32_t access; 215 216 if (smb_inet_iszero(ipaddr)) 217 return (ACE_ALL_PERMS); 218 219 if ((shr->shr_access_none == NULL || *shr->shr_access_none == '\0') && 220 (shr->shr_access_ro == NULL || *shr->shr_access_ro == '\0') && 221 (shr->shr_access_rw == NULL || *shr->shr_access_rw == '\0')) 222 return (ACE_ALL_PERMS); 223 224 if (shr->shr_access_none != NULL) 225 flag |= SMB_SHRF_ACC_NONE; 226 if (shr->shr_access_ro != NULL) 227 flag |= SMB_SHRF_ACC_RO; 228 if (shr->shr_access_rw != NULL) 229 flag |= SMB_SHRF_ACC_RW; 230 231 req.shq_none = shr->shr_access_none; 232 req.shq_ro = shr->shr_access_ro; 233 req.shq_rw = shr->shr_access_rw; 234 req.shq_flag = flag; 235 req.shq_ipaddr = *ipaddr; 236 237 (void) smb_kdoor_upcall(session->s_server, SMB_DR_SHR_HOSTACCESS, 238 &req, smb_shr_hostaccess_query_xdr, &host_access, xdr_uint32_t); 239 240 switch (host_access) { 241 case SMB_SHRF_ACC_RO: 242 access = ACE_ALL_PERMS & ~ACE_ALL_WRITE_PERMS; 243 break; 244 case SMB_SHRF_ACC_OPEN: 245 case SMB_SHRF_ACC_RW: 246 access = ACE_ALL_PERMS; 247 break; 248 case SMB_SHRF_ACC_NONE: 249 default: 250 access = 0; 251 } 252 253 return (access); 254 } 255 256 /* 257 * This function is called when smb_server_t is 258 * created which means smb/service is ready for 259 * exporting SMB shares 260 */ 261 void 262 smb_export_start(smb_server_t *sv) 263 { 264 mutex_enter(&sv->sv_export.e_mutex); 265 if (sv->sv_export.e_ready) { 266 mutex_exit(&sv->sv_export.e_mutex); 267 return; 268 } 269 270 sv->sv_export.e_ready = B_TRUE; 271 mutex_exit(&sv->sv_export.e_mutex); 272 273 smb_avl_create(&sv->sv_export.e_share_avl, sizeof (smb_kshare_t), 274 offsetof(smb_kshare_t, shr_link), &smb_kshare_avlops); 275 276 (void) smb_kshare_export_trans(sv, "IPC$", "IPC$", "Remote IPC"); 277 (void) smb_kshare_export_trans(sv, "c$", SMB_CVOL, "Default Share"); 278 (void) smb_kshare_export_trans(sv, "vss$", SMB_VSS, "VSS"); 279 } 280 281 /* 282 * This function is called when smb_server_t goes 283 * away which means SMB shares should not be made 284 * available to clients 285 */ 286 void 287 smb_export_stop(smb_server_t *sv) 288 { 289 mutex_enter(&sv->sv_export.e_mutex); 290 if (!sv->sv_export.e_ready) { 291 mutex_exit(&sv->sv_export.e_mutex); 292 return; 293 } 294 sv->sv_export.e_ready = B_FALSE; 295 mutex_exit(&sv->sv_export.e_mutex); 296 297 smb_avl_destroy(&sv->sv_export.e_share_avl); 298 } 299 300 void 301 smb_kshare_g_init(void) 302 { 303 smb_kshare_cache_share = kmem_cache_create("smb_share_cache", 304 sizeof (smb_kshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 305 306 smb_kshare_cache_unexport = kmem_cache_create("smb_unexport_cache", 307 sizeof (smb_unshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 308 } 309 310 void 311 smb_kshare_init(smb_server_t *sv) 312 { 313 314 smb_slist_constructor(&sv->sv_export.e_unexport_list, 315 sizeof (smb_unshare_t), offsetof(smb_unshare_t, us_lnd)); 316 } 317 318 int 319 smb_kshare_start(smb_server_t *sv) 320 { 321 smb_thread_init(&sv->sv_export.e_unexport_thread, "smb_kshare_unexport", 322 smb_kshare_unexport_thread, sv, smbsrv_base_pri, sv); 323 324 return (smb_thread_start(&sv->sv_export.e_unexport_thread)); 325 } 326 327 void 328 smb_kshare_stop(smb_server_t *sv) 329 { 330 smb_thread_stop(&sv->sv_export.e_unexport_thread); 331 smb_thread_destroy(&sv->sv_export.e_unexport_thread); 332 } 333 334 void 335 smb_kshare_fini(smb_server_t *sv) 336 { 337 smb_unshare_t *ux; 338 339 while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list)) 340 != NULL) { 341 smb_slist_remove(&sv->sv_export.e_unexport_list, ux); 342 kmem_cache_free(smb_kshare_cache_unexport, ux); 343 } 344 smb_slist_destructor(&sv->sv_export.e_unexport_list); 345 } 346 347 void 348 smb_kshare_g_fini(void) 349 { 350 kmem_cache_destroy(smb_kshare_cache_unexport); 351 kmem_cache_destroy(smb_kshare_cache_share); 352 } 353 354 /* 355 * A list of shares in nvlist format can be sent down 356 * from userspace thourgh the IOCTL interface. The nvlist 357 * is unpacked here and all the shares in the list will 358 * be exported. 359 */ 360 int 361 smb_kshare_export_list(smb_ioc_share_t *ioc) 362 { 363 smb_server_t *sv = NULL; 364 nvlist_t *shrlist = NULL; 365 nvlist_t *share; 366 nvpair_t *nvp; 367 smb_kshare_t *shr; 368 char *shrname; 369 int rc; 370 371 if ((rc = smb_server_lookup(&sv)) != 0) 372 return (rc); 373 374 if (!smb_export_isready(sv)) { 375 rc = ENOTACTIVE; 376 goto out; 377 } 378 379 /* 380 * Reality check that the nvlist's reported length doesn't exceed the 381 * ioctl's total length. We then assume the nvlist_unpack() will 382 * sanity check the nvlist itself. 383 */ 384 if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) { 385 rc = EINVAL; 386 goto out; 387 } 388 rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, KM_SLEEP); 389 if (rc != 0) 390 goto out; 391 392 for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL; 393 nvp = nvlist_next_nvpair(shrlist, nvp)) { 394 395 /* 396 * Since this loop can run for a while we want to exit 397 * as soon as the server state is anything but RUNNING 398 * to allow shutdown to proceed. 399 */ 400 if (sv->sv_state != SMB_SERVER_STATE_RUNNING) 401 goto out; 402 403 if (nvpair_type(nvp) != DATA_TYPE_NVLIST) 404 continue; 405 406 shrname = nvpair_name(nvp); 407 ASSERT(shrname); 408 409 if ((rc = nvpair_value_nvlist(nvp, &share)) != 0) { 410 cmn_err(CE_WARN, "export[%s]: failed accessing", 411 shrname); 412 continue; 413 } 414 415 if ((shr = smb_kshare_decode(share)) == NULL) { 416 cmn_err(CE_WARN, "export[%s]: failed decoding", 417 shrname); 418 continue; 419 } 420 421 /* smb_kshare_export consumes shr so it's not leaked */ 422 if ((rc = smb_kshare_export(sv, shr)) != 0) { 423 smb_kshare_destroy(shr); 424 continue; 425 } 426 } 427 rc = 0; 428 429 out: 430 nvlist_free(shrlist); 431 smb_server_release(sv); 432 return (rc); 433 } 434 435 /* 436 * This function is invoked when a share is disabled to disconnect trees 437 * and close files. Cleaning up may involve VOP and/or VFS calls, which 438 * may conflict/deadlock with stuck threads if something is amiss with the 439 * file system. Queueing the request for asynchronous processing allows the 440 * call to return immediately so that, if the unshare is being done in the 441 * context of a forced unmount, the forced unmount will always be able to 442 * proceed (unblocking stuck I/O and eventually allowing all blocked unshare 443 * processes to complete). 444 * 445 * The path lookup to find the root vnode of the VFS in question and the 446 * release of this vnode are done synchronously prior to any associated 447 * unmount. Doing these asynchronous to an associated unmount could run 448 * the risk of a spurious EBUSY for a standard unmount or an EIO during 449 * the path lookup due to a forced unmount finishing first. 450 */ 451 int 452 smb_kshare_unexport_list(smb_ioc_share_t *ioc) 453 { 454 smb_server_t *sv = NULL; 455 smb_unshare_t *ux; 456 nvlist_t *shrlist = NULL; 457 nvpair_t *nvp; 458 boolean_t unexport = B_FALSE; 459 char *shrname; 460 int rc; 461 462 if ((rc = smb_server_lookup(&sv)) != 0) 463 return (rc); 464 465 /* 466 * Reality check that the nvlist's reported length doesn't exceed the 467 * ioctl's total length. We then assume the nvlist_unpack() will 468 * sanity check the nvlist itself. 469 */ 470 if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) { 471 rc = EINVAL; 472 goto out; 473 } 474 if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, 0)) != 0) 475 goto out; 476 477 for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL; 478 nvp = nvlist_next_nvpair(shrlist, nvp)) { 479 if (nvpair_type(nvp) != DATA_TYPE_NVLIST) 480 continue; 481 482 shrname = nvpair_name(nvp); 483 ASSERT(shrname); 484 485 if ((rc = smb_kshare_unexport(sv, shrname)) != 0) 486 continue; 487 488 ux = kmem_cache_alloc(smb_kshare_cache_unexport, KM_SLEEP); 489 (void) strlcpy(ux->us_sharename, shrname, MAXNAMELEN); 490 491 smb_slist_insert_tail(&sv->sv_export.e_unexport_list, ux); 492 unexport = B_TRUE; 493 } 494 495 if (unexport) 496 smb_thread_signal(&sv->sv_export.e_unexport_thread); 497 rc = 0; 498 499 out: 500 nvlist_free(shrlist); 501 smb_server_release(sv); 502 return (rc); 503 } 504 505 /* 506 * Get properties (currently only shortname enablement) 507 * of specified share. 508 */ 509 int 510 smb_kshare_info(smb_ioc_shareinfo_t *ioc) 511 { 512 smb_server_t *sv; 513 int rc; 514 515 if ((rc = smb_server_lookup(&sv)) == 0) { 516 ioc->shortnames = sv->sv_cfg.skc_short_names; 517 smb_server_release(sv); 518 } 519 return (rc); 520 } 521 522 /* 523 * smb_kshare_access 524 * 525 * Does this user have access to the share? 526 * returns: 0 (access OK) or errno 527 * 528 * SMB users always have VEXEC (traverse) via privileges, 529 * so just check for READ or WRITE permissions. 530 */ 531 int 532 smb_kshare_access(smb_ioc_shareaccess_t *ioc) 533 { 534 smb_server_t *sv = NULL; 535 smb_user_t *user = NULL; 536 smb_kshare_t *shr = NULL; 537 smb_node_t *shroot = NULL; 538 vnode_t *vp = NULL; 539 int rc = EACCES; 540 541 if ((rc = smb_server_lookup(&sv)) != 0) { 542 rc = ESRCH; 543 goto out; 544 } 545 546 shr = smb_kshare_lookup(sv, ioc->shrname); 547 if (shr == NULL) { 548 rc = ENOENT; 549 goto out; 550 } 551 if ((shroot = shr->shr_root_node) == NULL) { 552 /* Only "file" shares have shr_root_node */ 553 rc = 0; 554 goto out; 555 } 556 vp = shroot->vp; 557 558 user = smb_server_lookup_user(sv, ioc->session_id, ioc->user_id); 559 if (user == NULL) { 560 rc = EINVAL; 561 goto out; 562 } 563 ASSERT(user->u_cred != NULL); 564 565 rc = smb_vop_access(vp, VREAD, 0, NULL, user->u_cred); 566 if (rc != 0) 567 rc = smb_vop_access(vp, VWRITE, 0, NULL, user->u_cred); 568 569 out: 570 if (user != NULL) 571 smb_user_release(user); 572 if (shr != NULL) 573 smb_kshare_release(sv, shr); 574 if (sv != NULL) 575 smb_server_release(sv); 576 577 return (rc); 578 } 579 580 /* 581 * This function builds a response for a NetShareEnum RAP request. 582 * List of shares is scanned twice. In the first round the total number 583 * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal) 584 * and also the number of shares that fit in the given buffer are calculated. 585 * In the second round the shares data are encoded in the buffer. 586 * 587 * The data associated with each share has two parts, a fixed size part and 588 * a variable size part which is share's comment. The outline of the response 589 * buffer is so that fixed part for all the shares will appear first and follows 590 * with the comments for all those shares and that's why the data cannot be 591 * encoded in one round without unnecessarily complicating the code. 592 */ 593 void 594 smb_kshare_enum(smb_server_t *sv, smb_enumshare_info_t *esi) 595 { 596 smb_avl_t *share_avl; 597 smb_avl_cursor_t cursor; 598 smb_kshare_t *shr; 599 int remained; 600 uint16_t infolen = 0; 601 uint16_t cmntlen = 0; 602 uint16_t sharelen; 603 uint16_t clen; 604 uint32_t cmnt_offs; 605 smb_msgbuf_t info_mb; 606 smb_msgbuf_t cmnt_mb; 607 boolean_t autohome_added = B_FALSE; 608 609 if (!smb_export_isready(sv)) { 610 esi->es_ntotal = esi->es_nsent = 0; 611 esi->es_datasize = 0; 612 return; 613 } 614 615 esi->es_ntotal = esi->es_nsent = 0; 616 remained = esi->es_bufsize; 617 share_avl = &sv->sv_export.e_share_avl; 618 619 /* Do the necessary calculations in the first round */ 620 smb_avl_iterinit(share_avl, &cursor); 621 622 while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) { 623 if (shr->shr_oemname == NULL) { 624 smb_avl_release(share_avl, shr); 625 continue; 626 } 627 628 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 629 if (esi->es_posix_uid == shr->shr_uid) { 630 autohome_added = B_TRUE; 631 } else { 632 smb_avl_release(share_avl, shr); 633 continue; 634 } 635 } 636 637 esi->es_ntotal++; 638 639 if (remained <= 0) { 640 smb_avl_release(share_avl, shr); 641 continue; 642 } 643 644 clen = strlen(shr->shr_cmnt) + 1; 645 sharelen = SHARE_INFO_1_SIZE + clen; 646 647 if (sharelen <= remained) { 648 infolen += SHARE_INFO_1_SIZE; 649 cmntlen += clen; 650 } 651 652 remained -= sharelen; 653 smb_avl_release(share_avl, shr); 654 } 655 656 esi->es_datasize = infolen + cmntlen; 657 658 smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0); 659 smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0); 660 cmnt_offs = infolen; 661 662 /* Encode the data in the second round */ 663 smb_avl_iterinit(share_avl, &cursor); 664 autohome_added = B_FALSE; 665 666 while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) { 667 if (shr->shr_oemname == NULL) { 668 smb_avl_release(share_avl, shr); 669 continue; 670 } 671 672 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 673 if (esi->es_posix_uid == shr->shr_uid) { 674 autohome_added = B_TRUE; 675 } else { 676 smb_avl_release(share_avl, shr); 677 continue; 678 } 679 } 680 681 if (smb_msgbuf_encode(&info_mb, "13c.wl", 682 shr->shr_oemname, shr->shr_type, cmnt_offs) < 0) { 683 smb_avl_release(share_avl, shr); 684 break; 685 } 686 687 if (smb_msgbuf_encode(&cmnt_mb, "s", shr->shr_cmnt) < 0) { 688 smb_avl_release(share_avl, shr); 689 break; 690 } 691 692 cmnt_offs += strlen(shr->shr_cmnt) + 1; 693 esi->es_nsent++; 694 695 smb_avl_release(share_avl, shr); 696 } 697 698 smb_msgbuf_term(&info_mb); 699 smb_msgbuf_term(&cmnt_mb); 700 } 701 702 /* 703 * Looks up the given share and returns a pointer 704 * to its definition if it's found. A hold on the 705 * object is taken before the pointer is returned 706 * in which case the caller MUST always call 707 * smb_kshare_release(). 708 */ 709 smb_kshare_t * 710 smb_kshare_lookup(smb_server_t *sv, const char *shrname) 711 { 712 smb_kshare_t key; 713 smb_kshare_t *shr; 714 715 ASSERT(shrname); 716 717 if (!smb_export_isready(sv)) 718 return (NULL); 719 720 key.shr_name = (char *)shrname; 721 shr = smb_avl_lookup(&sv->sv_export.e_share_avl, &key); 722 return (shr); 723 } 724 725 /* 726 * Releases the hold taken on the specified share object 727 */ 728 void 729 smb_kshare_release(smb_server_t *sv, smb_kshare_t *shr) 730 { 731 ASSERT(shr); 732 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC); 733 734 smb_avl_release(&sv->sv_export.e_share_avl, shr); 735 } 736 737 /* 738 * Add the given share in the specified server. 739 * If the share is a disk share, lookup the share path 740 * and hold the smb_node_t for the share root. 741 * 742 * If the share is an Autohome share and it is 743 * already in the AVL only a reference count for 744 * that share is incremented. 745 */ 746 static int 747 smb_kshare_export(smb_server_t *sv, smb_kshare_t *shr) 748 { 749 smb_avl_t *share_avl; 750 smb_kshare_t *auto_shr; 751 smb_node_t *snode = NULL; 752 int rc = 0; 753 754 share_avl = &sv->sv_export.e_share_avl; 755 756 if (!STYPE_ISDSK(shr->shr_type)) { 757 if ((rc = smb_avl_add(share_avl, shr)) != 0) { 758 cmn_err(CE_WARN, "export[%s]: failed caching (%d)", 759 shr->shr_name, rc); 760 } 761 762 return (rc); 763 } 764 765 if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) { 766 rc = EEXIST; 767 if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) { 768 mutex_enter(&auto_shr->shr_mutex); 769 auto_shr->shr_autocnt++; 770 mutex_exit(&auto_shr->shr_mutex); 771 rc = 0; 772 } 773 smb_avl_release(share_avl, auto_shr); 774 return (rc); 775 } 776 777 /* 778 * Get the root smb_node_t for this share, held. 779 * This hold is normally released during AVL destroy, 780 * via the element destructor: smb_kshare_destroy 781 */ 782 rc = smb_server_share_lookup(sv, shr->shr_path, &snode); 783 if (rc != 0) { 784 cmn_err(CE_WARN, "export[%s(%s)]: lookup failed (%d)", 785 shr->shr_name, shr->shr_path, rc); 786 return (rc); 787 } 788 789 shr->shr_root_node = snode; 790 if ((rc = smb_avl_add(share_avl, shr)) != 0) { 791 cmn_err(CE_WARN, "export[%s]: failed caching (%d)", 792 shr->shr_name, rc); 793 shr->shr_root_node = NULL; 794 smb_node_release(snode); 795 return (rc); 796 } 797 798 /* 799 * For CA shares, find or create the CA handle dir, 800 * and (if restarted) import persistent handles. 801 */ 802 if ((shr->shr_flags & SMB_SHRF_CA) != 0) { 803 rc = smb2_dh_new_ca_share(sv, shr); 804 if (rc != 0) { 805 /* Just make it a non-CA share. */ 806 mutex_enter(&shr->shr_mutex); 807 shr->shr_flags &= ~SMB_SHRF_CA; 808 mutex_exit(&shr->shr_mutex); 809 rc = 0; 810 } 811 } 812 813 return (rc); 814 } 815 816 /* 817 * Removes the share specified by 'shrname' from the AVL 818 * tree of the given server if it's there. 819 * 820 * If the share is an Autohome share, the autohome count 821 * is decremented and the share is only removed if the 822 * count goes to zero. 823 * 824 * If the share is a disk share, the hold on the corresponding 825 * file system is released before removing the share from 826 * the AVL tree. 827 */ 828 static int 829 smb_kshare_unexport(smb_server_t *sv, const char *shrname) 830 { 831 smb_avl_t *share_avl; 832 smb_kshare_t key; 833 smb_kshare_t *shr; 834 boolean_t auto_unexport; 835 836 share_avl = &sv->sv_export.e_share_avl; 837 838 key.shr_name = (char *)shrname; 839 if ((shr = smb_avl_lookup(share_avl, &key)) == NULL) 840 return (ENOENT); 841 842 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) { 843 mutex_enter(&shr->shr_mutex); 844 shr->shr_autocnt--; 845 auto_unexport = (shr->shr_autocnt == 0); 846 mutex_exit(&shr->shr_mutex); 847 if (!auto_unexport) { 848 smb_avl_release(share_avl, shr); 849 return (0); 850 } 851 } 852 853 smb_avl_remove(share_avl, shr); 854 855 mutex_enter(&shr->shr_mutex); 856 shr->shr_flags |= SMB_SHRF_REMOVED; 857 mutex_exit(&shr->shr_mutex); 858 859 smb_avl_release(share_avl, shr); 860 861 return (0); 862 } 863 864 /* 865 * Exports IPC$ or Admin shares 866 */ 867 static int 868 smb_kshare_export_trans(smb_server_t *sv, char *name, char *path, char *cmnt) 869 { 870 smb_kshare_t *shr; 871 872 ASSERT(name); 873 ASSERT(path); 874 875 shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP); 876 bzero(shr, sizeof (smb_kshare_t)); 877 878 shr->shr_magic = SMB_SHARE_MAGIC; 879 shr->shr_refcnt = 1; 880 shr->shr_flags = SMB_SHRF_TRANS | smb_kshare_is_admin(name); 881 if (strcasecmp(name, "IPC$") == 0) 882 shr->shr_type = STYPE_IPC; 883 else 884 shr->shr_type = STYPE_DISKTREE; 885 886 shr->shr_type |= smb_kshare_is_special(name); 887 888 shr->shr_name = smb_mem_strdup(name); 889 if (path) 890 shr->shr_path = smb_mem_strdup(path); 891 if (cmnt) 892 shr->shr_cmnt = smb_mem_strdup(cmnt); 893 shr->shr_oemname = smb_kshare_oemname(name); 894 895 return (smb_kshare_export(sv, shr)); 896 } 897 898 /* 899 * Decodes share information in an nvlist format into a smb_kshare_t 900 * structure. 901 * 902 * This is a temporary function and will be replaced by functions 903 * provided by libsharev2 code after it's available. 904 */ 905 static smb_kshare_t * 906 smb_kshare_decode(nvlist_t *share) 907 { 908 smb_kshare_t tmp; 909 smb_kshare_t *shr; 910 nvlist_t *smb; 911 char *csc_name = NULL, *strbuf = NULL; 912 int rc; 913 914 ASSERT(share); 915 916 bzero(&tmp, sizeof (smb_kshare_t)); 917 918 rc = nvlist_lookup_string(share, "name", &tmp.shr_name); 919 rc |= nvlist_lookup_string(share, "path", &tmp.shr_path); 920 (void) nvlist_lookup_string(share, "desc", &tmp.shr_cmnt); 921 922 ASSERT(tmp.shr_name && tmp.shr_path); 923 924 rc |= nvlist_lookup_nvlist(share, "smb", &smb); 925 if (rc != 0) { 926 cmn_err(CE_WARN, "kshare: failed looking up SMB properties" 927 " (%d)", rc); 928 return (NULL); 929 } 930 931 rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type); 932 if (rc != 0) { 933 cmn_err(CE_WARN, "kshare[%s]: failed getting the share type" 934 " (%d)", tmp.shr_name, rc); 935 return (NULL); 936 } 937 938 (void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER, 939 &tmp.shr_container); 940 (void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none); 941 (void) nvlist_lookup_string(smb, SHOPT_RO, &tmp.shr_access_ro); 942 (void) nvlist_lookup_string(smb, SHOPT_RW, &tmp.shr_access_rw); 943 944 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_ABE, SMB_SHRF_ABE); 945 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CATIA, 946 SMB_SHRF_CATIA); 947 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_GUEST, 948 SMB_SHRF_GUEST_OK); 949 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_DFSROOT, 950 SMB_SHRF_DFSROOT); 951 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_QUOTAS, 952 SMB_SHRF_QUOTAS); 953 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CA, SMB_SHRF_CA); 954 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_FSO, SMB_SHRF_FSO); 955 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_AUTOHOME, 956 SMB_SHRF_AUTOHOME); 957 958 if ((tmp.shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) { 959 rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid); 960 rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid); 961 if (rc != 0) { 962 cmn_err(CE_WARN, "kshare: failed looking up uid/gid" 963 " (%d)", rc); 964 return (NULL); 965 } 966 } 967 968 (void) nvlist_lookup_string(smb, SHOPT_ENCRYPT, &strbuf); 969 smb_cfg_set_require(strbuf, &tmp.shr_encrypt); 970 971 (void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name); 972 smb_kshare_csc_flags(&tmp, csc_name); 973 974 shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP); 975 bzero(shr, sizeof (smb_kshare_t)); 976 977 shr->shr_magic = SMB_SHARE_MAGIC; 978 shr->shr_refcnt = 1; 979 980 shr->shr_name = smb_mem_strdup(tmp.shr_name); 981 shr->shr_path = smb_mem_strdup(tmp.shr_path); 982 if (tmp.shr_cmnt) 983 shr->shr_cmnt = smb_mem_strdup(tmp.shr_cmnt); 984 if (tmp.shr_container) 985 shr->shr_container = smb_mem_strdup(tmp.shr_container); 986 if (tmp.shr_access_none) 987 shr->shr_access_none = smb_mem_strdup(tmp.shr_access_none); 988 if (tmp.shr_access_ro) 989 shr->shr_access_ro = smb_mem_strdup(tmp.shr_access_ro); 990 if (tmp.shr_access_rw) 991 shr->shr_access_rw = smb_mem_strdup(tmp.shr_access_rw); 992 993 shr->shr_oemname = smb_kshare_oemname(shr->shr_name); 994 shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name); 995 shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name); 996 shr->shr_encrypt = tmp.shr_encrypt; 997 998 shr->shr_uid = tmp.shr_uid; 999 shr->shr_gid = tmp.shr_gid; 1000 1001 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) 1002 shr->shr_autocnt = 1; 1003 1004 return (shr); 1005 } 1006 1007 #if 0 1008 static void 1009 smb_kshare_log(smb_kshare_t *shr) 1010 { 1011 cmn_err(CE_NOTE, "Share info:"); 1012 cmn_err(CE_NOTE, "\tname: %s", (shr->shr_name) ? shr->shr_name : ""); 1013 cmn_err(CE_NOTE, "\tpath: %s", (shr->shr_path) ? shr->shr_path : ""); 1014 cmn_err(CE_NOTE, "\tcmnt: (%s)", 1015 (shr->shr_cmnt) ? shr->shr_cmnt : "NULL"); 1016 cmn_err(CE_NOTE, "\toemname: (%s)", 1017 (shr->shr_oemname) ? shr->shr_oemname : "NULL"); 1018 cmn_err(CE_NOTE, "\tflags: %X", shr->shr_flags); 1019 cmn_err(CE_NOTE, "\ttype: %d", shr->shr_type); 1020 } 1021 #endif 1022 1023 /* 1024 * Compare function used by shares AVL 1025 */ 1026 static int 1027 smb_kshare_cmp(const void *p1, const void *p2) 1028 { 1029 smb_kshare_t *shr1 = (smb_kshare_t *)p1; 1030 smb_kshare_t *shr2 = (smb_kshare_t *)p2; 1031 int rc; 1032 1033 ASSERT(shr1); 1034 ASSERT(shr1->shr_name); 1035 1036 ASSERT(shr2); 1037 ASSERT(shr2->shr_name); 1038 1039 rc = smb_strcasecmp(shr1->shr_name, shr2->shr_name, 0); 1040 1041 if (rc < 0) 1042 return (-1); 1043 1044 if (rc > 0) 1045 return (1); 1046 1047 return (0); 1048 } 1049 1050 /* 1051 * This function is called by smb_avl routines whenever 1052 * there is a need to take a hold on a share structure 1053 * inside AVL 1054 */ 1055 static void 1056 smb_kshare_hold(const void *p) 1057 { 1058 smb_kshare_t *shr = (smb_kshare_t *)p; 1059 1060 ASSERT(shr); 1061 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC); 1062 1063 mutex_enter(&shr->shr_mutex); 1064 shr->shr_refcnt++; 1065 mutex_exit(&shr->shr_mutex); 1066 } 1067 1068 /* 1069 * This function must be called by smb_avl routines whenever 1070 * smb_kshare_hold is called and the hold needs to be released. 1071 */ 1072 static boolean_t 1073 smb_kshare_rele(const void *p) 1074 { 1075 smb_kshare_t *shr = (smb_kshare_t *)p; 1076 boolean_t destroy; 1077 1078 ASSERT(shr); 1079 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC); 1080 1081 mutex_enter(&shr->shr_mutex); 1082 ASSERT(shr->shr_refcnt > 0); 1083 shr->shr_refcnt--; 1084 destroy = (shr->shr_refcnt == 0); 1085 mutex_exit(&shr->shr_mutex); 1086 1087 return (destroy); 1088 } 1089 1090 /* 1091 * Frees all the memory allocated for the given 1092 * share structure. It also removes the structure 1093 * from the share cache. 1094 */ 1095 static void 1096 smb_kshare_destroy(void *p) 1097 { 1098 smb_kshare_t *shr = (smb_kshare_t *)p; 1099 1100 ASSERT(shr); 1101 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC); 1102 1103 if (shr->shr_ca_dir != NULL) 1104 smb_node_release(shr->shr_ca_dir); 1105 if (shr->shr_root_node) 1106 smb_node_release(shr->shr_root_node); 1107 1108 smb_mem_free(shr->shr_name); 1109 smb_mem_free(shr->shr_path); 1110 smb_mem_free(shr->shr_cmnt); 1111 smb_mem_free(shr->shr_container); 1112 smb_mem_free(shr->shr_oemname); 1113 smb_mem_free(shr->shr_access_none); 1114 smb_mem_free(shr->shr_access_ro); 1115 smb_mem_free(shr->shr_access_rw); 1116 1117 kmem_cache_free(smb_kshare_cache_share, shr); 1118 } 1119 1120 1121 /* 1122 * Generate an OEM name for the given share name. If the name is 1123 * shorter than 13 bytes the oemname will be returned; otherwise NULL 1124 * is returned. 1125 */ 1126 static char * 1127 smb_kshare_oemname(const char *shrname) 1128 { 1129 smb_wchar_t *unibuf; 1130 char *oem_name; 1131 int length; 1132 1133 length = strlen(shrname) + 1; 1134 1135 oem_name = smb_mem_alloc(length); 1136 unibuf = smb_mem_alloc(length * sizeof (smb_wchar_t)); 1137 1138 (void) smb_mbstowcs(unibuf, shrname, length); 1139 1140 if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0) 1141 (void) strcpy(oem_name, shrname); 1142 1143 smb_mem_free(unibuf); 1144 1145 if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) { 1146 smb_mem_free(oem_name); 1147 return (NULL); 1148 } 1149 1150 return (oem_name); 1151 } 1152 1153 /* 1154 * Special share reserved for interprocess communication (IPC$) or 1155 * remote administration of the server (ADMIN$). Can also refer to 1156 * administrative shares such as C$, D$, E$, and so forth. 1157 */ 1158 static int 1159 smb_kshare_is_special(const char *sharename) 1160 { 1161 int len; 1162 1163 if (sharename == NULL) 1164 return (0); 1165 1166 if ((len = strlen(sharename)) == 0) 1167 return (0); 1168 1169 if (sharename[len - 1] == '$') 1170 return (STYPE_SPECIAL); 1171 1172 return (0); 1173 } 1174 1175 /* 1176 * Check whether or not this is a default admin share: C$, D$ etc. 1177 */ 1178 static int 1179 smb_kshare_is_admin(const char *sharename) 1180 { 1181 if (sharename == NULL) 1182 return (0); 1183 1184 if (strlen(sharename) == 2 && 1185 smb_isalpha(sharename[0]) && sharename[1] == '$') { 1186 return (SMB_SHRF_ADMIN); 1187 } 1188 1189 return (0); 1190 } 1191 1192 /* 1193 * Decodes the given boolean share option. 1194 * If the option is present in the nvlist and it's value is true 1195 * returns the corresponding flag value, otherwise returns 0. 1196 */ 1197 static uint32_t 1198 smb_kshare_decode_bool(nvlist_t *nvl, const char *propname, uint32_t flag) 1199 { 1200 char *boolp; 1201 1202 if (nvlist_lookup_string(nvl, propname, &boolp) == 0) 1203 if (strcasecmp(boolp, "true") == 0) 1204 return (flag); 1205 1206 return (0); 1207 } 1208 1209 /* 1210 * Map a client-side caching (CSC) option to the appropriate share 1211 * flag. Only one option is allowed; an error will be logged if 1212 * multiple options have been specified. We don't need to do anything 1213 * about multiple values here because the SRVSVC will not recognize 1214 * a value containing multiple flags and will return the default value. 1215 * 1216 * If the option value is not recognized, it will be ignored: invalid 1217 * values will typically be caught and rejected by sharemgr. 1218 */ 1219 static void 1220 smb_kshare_csc_flags(smb_kshare_t *shr, const char *value) 1221 { 1222 int i; 1223 static struct { 1224 char *value; 1225 uint32_t flag; 1226 } cscopt[] = { 1227 { "disabled", SMB_SHRF_CSC_DISABLED }, 1228 { "manual", SMB_SHRF_CSC_MANUAL }, 1229 { "auto", SMB_SHRF_CSC_AUTO }, 1230 { "vdo", SMB_SHRF_CSC_VDO } 1231 }; 1232 1233 if (value == NULL) 1234 return; 1235 1236 for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) { 1237 if (strcasecmp(value, cscopt[i].value) == 0) { 1238 shr->shr_flags |= cscopt[i].flag; 1239 break; 1240 } 1241 } 1242 1243 switch (shr->shr_flags & SMB_SHRF_CSC_MASK) { 1244 case 0: 1245 case SMB_SHRF_CSC_DISABLED: 1246 case SMB_SHRF_CSC_MANUAL: 1247 case SMB_SHRF_CSC_AUTO: 1248 case SMB_SHRF_CSC_VDO: 1249 break; 1250 1251 default: 1252 cmn_err(CE_NOTE, "csc option conflict: 0x%08x", 1253 shr->shr_flags & SMB_SHRF_CSC_MASK); 1254 break; 1255 } 1256 } 1257 1258 /* 1259 * This function processes the unexport event list and disconnects shares 1260 * asynchronously. The function executes as a zone-specific thread. 1261 * 1262 * The server arg passed in is safe to use without a reference count, because 1263 * the server cannot be deleted until smb_thread_stop()/destroy() return, 1264 * which is also when the thread exits. 1265 */ 1266 /*ARGSUSED*/ 1267 static void 1268 smb_kshare_unexport_thread(smb_thread_t *thread, void *arg) 1269 { 1270 smb_server_t *sv = arg; 1271 smb_unshare_t *ux; 1272 1273 while (smb_thread_continue(thread)) { 1274 while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list)) 1275 != NULL) { 1276 smb_slist_remove(&sv->sv_export.e_unexport_list, ux); 1277 (void) smb_server_unshare(ux->us_sharename); 1278 kmem_cache_free(smb_kshare_cache_unexport, ux); 1279 } 1280 } 1281 } 1282 1283 static boolean_t 1284 smb_export_isready(smb_server_t *sv) 1285 { 1286 boolean_t ready; 1287 1288 mutex_enter(&sv->sv_export.e_mutex); 1289 ready = sv->sv_export.e_ready; 1290 mutex_exit(&sv->sv_export.e_mutex); 1291 1292 return (ready); 1293 } 1294 1295 #ifdef _KERNEL 1296 /* 1297 * Return 0 upon success. Otherwise > 0 1298 */ 1299 static int 1300 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx) 1301 { 1302 int status = smb_dr_get_int32(dec_ctx); 1303 int err; 1304 1305 switch (status) { 1306 case SMB_SHARE_DSUCCESS: 1307 return (0); 1308 1309 case SMB_SHARE_DERROR: 1310 err = smb_dr_get_uint32(dec_ctx); 1311 cmn_err(CE_WARN, "%d: Encountered door server error %d", 1312 opcode, err); 1313 (void) smb_dr_decode_finish(dec_ctx); 1314 return (err); 1315 } 1316 1317 ASSERT(0); 1318 return (EINVAL); 1319 } 1320 #endif /* _KERNEL */ 1321