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