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_kshare_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 nvlist_free(shrlist); 432 smb_server_release(sv); 433 return (rc); 434 } 435 436 /* 437 * This function is invoked when a share is disabled to disconnect trees 438 * and close files. Cleaning up may involve VOP and/or VFS calls, which 439 * may conflict/deadlock with stuck threads if something is amiss with the 440 * file system. Queueing the request for asynchronous processing allows the 441 * call to return immediately so that, if the unshare is being done in the 442 * context of a forced unmount, the forced unmount will always be able to 443 * proceed (unblocking stuck I/O and eventually allowing all blocked unshare 444 * processes to complete). 445 * 446 * The path lookup to find the root vnode of the VFS in question and the 447 * release of this vnode are done synchronously prior to any associated 448 * unmount. Doing these asynchronous to an associated unmount could run 449 * the risk of a spurious EBUSY for a standard unmount or an EIO during 450 * the path lookup due to a forced unmount finishing first. 451 */ 452 int 453 smb_kshare_unexport_list(smb_ioc_share_t *ioc) 454 { 455 smb_server_t *sv = NULL; 456 smb_unshare_t *ux; 457 nvlist_t *shrlist = NULL; 458 nvpair_t *nvp; 459 boolean_t unexport = B_FALSE; 460 char *shrname; 461 int rc; 462 463 if ((rc = smb_server_lookup(&sv)) != 0) 464 return (rc); 465 466 if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, 0)) != 0) 467 goto out; 468 469 for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL; 470 nvp = nvlist_next_nvpair(shrlist, nvp)) { 471 if (nvpair_type(nvp) != DATA_TYPE_NVLIST) 472 continue; 473 474 shrname = nvpair_name(nvp); 475 ASSERT(shrname); 476 477 if ((rc = smb_kshare_unexport(sv, shrname)) != 0) 478 continue; 479 480 ux = kmem_cache_alloc(smb_kshare_cache_unexport, KM_SLEEP); 481 (void) strlcpy(ux->us_sharename, shrname, MAXNAMELEN); 482 483 smb_slist_insert_tail(&sv->sv_export.e_unexport_list, ux); 484 unexport = B_TRUE; 485 } 486 487 if (unexport) 488 smb_thread_signal(&sv->sv_export.e_unexport_thread); 489 rc = 0; 490 491 out: 492 nvlist_free(shrlist); 493 smb_server_release(sv); 494 return (rc); 495 } 496 497 /* 498 * Get properties (currently only shortname enablement) 499 * of specified share. 500 */ 501 int 502 smb_kshare_info(smb_ioc_shareinfo_t *ioc) 503 { 504 ioc->shortnames = smb_shortnames; 505 return (0); 506 } 507 508 /* 509 * This function builds a response for a NetShareEnum RAP request. 510 * List of shares is scanned twice. In the first round the total number 511 * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal) 512 * and also the number of shares that fit in the given buffer are calculated. 513 * In the second round the shares data are encoded in the buffer. 514 * 515 * The data associated with each share has two parts, a fixed size part and 516 * a variable size part which is share's comment. The outline of the response 517 * buffer is so that fixed part for all the shares will appear first and follows 518 * with the comments for all those shares and that's why the data cannot be 519 * encoded in one round without unnecessarily complicating the code. 520 */ 521 void 522 smb_kshare_enum(smb_server_t *sv, smb_enumshare_info_t *esi) 523 { 524 smb_avl_t *share_avl; 525 smb_avl_cursor_t cursor; 526 smb_kshare_t *shr; 527 int remained; 528 uint16_t infolen = 0; 529 uint16_t cmntlen = 0; 530 uint16_t sharelen; 531 uint16_t clen; 532 uint32_t cmnt_offs; 533 smb_msgbuf_t info_mb; 534 smb_msgbuf_t cmnt_mb; 535 boolean_t autohome_added = B_FALSE; 536 537 if (!smb_export_isready(sv)) { 538 esi->es_ntotal = esi->es_nsent = 0; 539 esi->es_datasize = 0; 540 return; 541 } 542 543 esi->es_ntotal = esi->es_nsent = 0; 544 remained = esi->es_bufsize; 545 share_avl = &sv->sv_export.e_share_avl; 546 547 /* Do the necessary calculations in the first round */ 548 smb_avl_iterinit(share_avl, &cursor); 549 550 while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) { 551 if (shr->shr_oemname == NULL) { 552 smb_avl_release(share_avl, shr); 553 continue; 554 } 555 556 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 557 if (esi->es_posix_uid == shr->shr_uid) { 558 autohome_added = B_TRUE; 559 } else { 560 smb_avl_release(share_avl, shr); 561 continue; 562 } 563 } 564 565 esi->es_ntotal++; 566 567 if (remained <= 0) { 568 smb_avl_release(share_avl, shr); 569 continue; 570 } 571 572 clen = strlen(shr->shr_cmnt) + 1; 573 sharelen = SHARE_INFO_1_SIZE + clen; 574 575 if (sharelen <= remained) { 576 infolen += SHARE_INFO_1_SIZE; 577 cmntlen += clen; 578 } 579 580 remained -= sharelen; 581 smb_avl_release(share_avl, shr); 582 } 583 584 esi->es_datasize = infolen + cmntlen; 585 586 smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0); 587 smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0); 588 cmnt_offs = infolen; 589 590 /* Encode the data in the second round */ 591 smb_avl_iterinit(share_avl, &cursor); 592 autohome_added = B_FALSE; 593 594 while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) { 595 if (shr->shr_oemname == NULL) { 596 smb_avl_release(share_avl, shr); 597 continue; 598 } 599 600 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) { 601 if (esi->es_posix_uid == shr->shr_uid) { 602 autohome_added = B_TRUE; 603 } else { 604 smb_avl_release(share_avl, shr); 605 continue; 606 } 607 } 608 609 if (smb_msgbuf_encode(&info_mb, "13c.wl", 610 shr->shr_oemname, shr->shr_type, cmnt_offs) < 0) { 611 smb_avl_release(share_avl, shr); 612 break; 613 } 614 615 if (smb_msgbuf_encode(&cmnt_mb, "s", shr->shr_cmnt) < 0) { 616 smb_avl_release(share_avl, shr); 617 break; 618 } 619 620 cmnt_offs += strlen(shr->shr_cmnt) + 1; 621 esi->es_nsent++; 622 623 smb_avl_release(share_avl, shr); 624 } 625 626 smb_msgbuf_term(&info_mb); 627 smb_msgbuf_term(&cmnt_mb); 628 } 629 630 /* 631 * Looks up the given share and returns a pointer 632 * to its definition if it's found. A hold on the 633 * object is taken before the pointer is returned 634 * in which case the caller MUST always call 635 * smb_kshare_release(). 636 */ 637 smb_kshare_t * 638 smb_kshare_lookup(smb_server_t *sv, const char *shrname) 639 { 640 smb_kshare_t key; 641 smb_kshare_t *shr; 642 643 ASSERT(shrname); 644 645 if (!smb_export_isready(sv)) 646 return (NULL); 647 648 key.shr_name = (char *)shrname; 649 shr = smb_avl_lookup(&sv->sv_export.e_share_avl, &key); 650 return (shr); 651 } 652 653 /* 654 * Releases the hold taken on the specified share object 655 */ 656 void 657 smb_kshare_release(smb_server_t *sv, smb_kshare_t *shr) 658 { 659 ASSERT(shr); 660 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC); 661 662 smb_avl_release(&sv->sv_export.e_share_avl, shr); 663 } 664 665 /* 666 * Add the given share in the specified server. 667 * If the share is a disk share, smb_vfs_hold() is 668 * invoked to ensure that there is a hold on the 669 * corresponding file system before the share is 670 * added to shares AVL. 671 * 672 * If the share is an Autohome share and it is 673 * already in the AVL only a reference count for 674 * that share is incremented. 675 */ 676 static int 677 smb_kshare_export(smb_server_t *sv, smb_kshare_t *shr) 678 { 679 smb_avl_t *share_avl; 680 smb_kshare_t *auto_shr; 681 vnode_t *vp; 682 int rc = 0; 683 684 share_avl = &sv->sv_export.e_share_avl; 685 686 if (!STYPE_ISDSK(shr->shr_type)) { 687 if ((rc = smb_avl_add(share_avl, shr)) != 0) { 688 cmn_err(CE_WARN, "export[%s]: failed caching (%d)", 689 shr->shr_name, rc); 690 } 691 692 return (rc); 693 } 694 695 if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) { 696 if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) == 0) { 697 smb_avl_release(share_avl, auto_shr); 698 return (EEXIST); 699 } 700 701 mutex_enter(&auto_shr->shr_mutex); 702 auto_shr->shr_autocnt++; 703 mutex_exit(&auto_shr->shr_mutex); 704 smb_avl_release(share_avl, auto_shr); 705 return (0); 706 } 707 708 if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) { 709 cmn_err(CE_WARN, "export[%s(%s)]: failed obtaining vnode (%d)", 710 shr->shr_name, shr->shr_path, rc); 711 return (rc); 712 } 713 714 if ((rc = smb_vfs_hold(&sv->sv_export, vp->v_vfsp)) == 0) { 715 if ((rc = smb_avl_add(share_avl, shr)) != 0) { 716 cmn_err(CE_WARN, "export[%s]: failed caching (%d)", 717 shr->shr_name, rc); 718 smb_vfs_rele(&sv->sv_export, vp->v_vfsp); 719 } 720 } else { 721 cmn_err(CE_WARN, "export[%s(%s)]: failed holding VFS (%d)", 722 shr->shr_name, shr->shr_path, rc); 723 } 724 725 VN_RELE(vp); 726 return (rc); 727 } 728 729 /* 730 * Removes the share specified by 'shrname' from the AVL 731 * tree of the given server if it's there. 732 * 733 * If the share is an Autohome share, the autohome count 734 * is decremented and the share is only removed if the 735 * count goes to zero. 736 * 737 * If the share is a disk share, the hold on the corresponding 738 * file system is released before removing the share from 739 * the AVL tree. 740 */ 741 static int 742 smb_kshare_unexport(smb_server_t *sv, const char *shrname) 743 { 744 smb_avl_t *share_avl; 745 smb_kshare_t key; 746 smb_kshare_t *shr; 747 vnode_t *vp; 748 int rc; 749 boolean_t auto_unexport; 750 751 share_avl = &sv->sv_export.e_share_avl; 752 753 key.shr_name = (char *)shrname; 754 if ((shr = smb_avl_lookup(share_avl, &key)) == NULL) 755 return (ENOENT); 756 757 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) { 758 mutex_enter(&shr->shr_mutex); 759 shr->shr_autocnt--; 760 auto_unexport = (shr->shr_autocnt == 0); 761 mutex_exit(&shr->shr_mutex); 762 if (!auto_unexport) { 763 smb_avl_release(share_avl, shr); 764 return (0); 765 } 766 } 767 768 if (STYPE_ISDSK(shr->shr_type)) { 769 if ((rc = smb_server_sharevp(sv, shr->shr_path, &vp)) != 0) { 770 smb_avl_release(share_avl, shr); 771 cmn_err(CE_WARN, "unexport[%s]: failed obtaining vnode" 772 " (%d)", shrname, rc); 773 return (rc); 774 } 775 776 smb_vfs_rele(&sv->sv_export, vp->v_vfsp); 777 VN_RELE(vp); 778 } 779 780 smb_avl_remove(share_avl, shr); 781 smb_avl_release(share_avl, shr); 782 783 return (0); 784 } 785 786 /* 787 * Exports IPC$ or Admin shares 788 */ 789 static int 790 smb_kshare_export_trans(smb_server_t *sv, char *name, char *path, char *cmnt) 791 { 792 smb_kshare_t *shr; 793 794 ASSERT(name); 795 ASSERT(path); 796 797 shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP); 798 bzero(shr, sizeof (smb_kshare_t)); 799 800 shr->shr_magic = SMB_SHARE_MAGIC; 801 shr->shr_refcnt = 1; 802 shr->shr_flags = SMB_SHRF_TRANS | smb_kshare_is_admin(shr->shr_name); 803 if (strcasecmp(name, "IPC$") == 0) 804 shr->shr_type = STYPE_IPC; 805 else 806 shr->shr_type = STYPE_DISKTREE; 807 808 shr->shr_type |= smb_kshare_is_special(shr->shr_name); 809 810 shr->shr_name = smb_mem_strdup(name); 811 if (path) 812 shr->shr_path = smb_mem_strdup(path); 813 if (cmnt) 814 shr->shr_cmnt = smb_mem_strdup(cmnt); 815 shr->shr_oemname = smb_kshare_oemname(name); 816 817 return (smb_kshare_export(sv, shr)); 818 } 819 820 /* 821 * Decodes share information in an nvlist format into a smb_kshare_t 822 * structure. 823 * 824 * This is a temporary function and will be replaced by functions 825 * provided by libsharev2 code after it's available. 826 */ 827 static smb_kshare_t * 828 smb_kshare_decode(nvlist_t *share) 829 { 830 smb_kshare_t tmp; 831 smb_kshare_t *shr; 832 nvlist_t *smb; 833 char *csc_name = NULL; 834 int rc; 835 836 ASSERT(share); 837 838 bzero(&tmp, sizeof (smb_kshare_t)); 839 840 rc = nvlist_lookup_string(share, "name", &tmp.shr_name); 841 rc |= nvlist_lookup_string(share, "path", &tmp.shr_path); 842 (void) nvlist_lookup_string(share, "desc", &tmp.shr_cmnt); 843 844 ASSERT(tmp.shr_name && tmp.shr_path); 845 846 rc |= nvlist_lookup_nvlist(share, "smb", &smb); 847 if (rc != 0) { 848 cmn_err(CE_WARN, "kshare: failed looking up SMB properties" 849 " (%d)", rc); 850 return (NULL); 851 } 852 853 rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type); 854 if (rc != 0) { 855 cmn_err(CE_WARN, "kshare[%s]: failed getting the share type" 856 " (%d)", tmp.shr_name, rc); 857 return (NULL); 858 } 859 860 (void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER, 861 &tmp.shr_container); 862 (void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none); 863 (void) nvlist_lookup_string(smb, SHOPT_RO, &tmp.shr_access_ro); 864 (void) nvlist_lookup_string(smb, SHOPT_RW, &tmp.shr_access_rw); 865 866 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_ABE, SMB_SHRF_ABE); 867 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CATIA, 868 SMB_SHRF_CATIA); 869 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_GUEST, 870 SMB_SHRF_GUEST_OK); 871 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_DFSROOT, 872 SMB_SHRF_DFSROOT); 873 tmp.shr_flags |= smb_kshare_decode_bool(smb, "Autohome", 874 SMB_SHRF_AUTOHOME); 875 876 if ((tmp.shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) { 877 rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid); 878 rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid); 879 if (rc != 0) { 880 cmn_err(CE_WARN, "kshare: failed looking up uid/gid" 881 " (%d)", rc); 882 return (NULL); 883 } 884 } 885 886 (void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name); 887 smb_kshare_csc_flags(&tmp, csc_name); 888 889 shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP); 890 bzero(shr, sizeof (smb_kshare_t)); 891 892 shr->shr_magic = SMB_SHARE_MAGIC; 893 shr->shr_refcnt = 1; 894 895 shr->shr_name = smb_mem_strdup(tmp.shr_name); 896 shr->shr_path = smb_mem_strdup(tmp.shr_path); 897 if (tmp.shr_cmnt) 898 shr->shr_cmnt = smb_mem_strdup(tmp.shr_cmnt); 899 if (tmp.shr_container) 900 shr->shr_container = smb_mem_strdup(tmp.shr_container); 901 if (tmp.shr_access_none) 902 shr->shr_access_none = smb_mem_strdup(tmp.shr_access_none); 903 if (tmp.shr_access_ro) 904 shr->shr_access_ro = smb_mem_strdup(tmp.shr_access_ro); 905 if (tmp.shr_access_rw) 906 shr->shr_access_rw = smb_mem_strdup(tmp.shr_access_rw); 907 908 shr->shr_oemname = smb_kshare_oemname(shr->shr_name); 909 shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name); 910 shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name); 911 912 shr->shr_uid = tmp.shr_uid; 913 shr->shr_gid = tmp.shr_gid; 914 915 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) 916 shr->shr_autocnt = 1; 917 918 return (shr); 919 } 920 921 #if 0 922 static void 923 smb_kshare_log(smb_kshare_t *shr) 924 { 925 cmn_err(CE_NOTE, "Share info:"); 926 cmn_err(CE_NOTE, "\tname: %s", (shr->shr_name) ? shr->shr_name : ""); 927 cmn_err(CE_NOTE, "\tpath: %s", (shr->shr_path) ? shr->shr_path : ""); 928 cmn_err(CE_NOTE, "\tcmnt: (%s)", 929 (shr->shr_cmnt) ? shr->shr_cmnt : "NULL"); 930 cmn_err(CE_NOTE, "\toemname: (%s)", 931 (shr->shr_oemname) ? shr->shr_oemname : "NULL"); 932 cmn_err(CE_NOTE, "\tflags: %X", shr->shr_flags); 933 cmn_err(CE_NOTE, "\ttype: %d", shr->shr_type); 934 } 935 #endif 936 937 /* 938 * Compare function used by shares AVL 939 */ 940 static int 941 smb_kshare_cmp(const void *p1, const void *p2) 942 { 943 smb_kshare_t *shr1 = (smb_kshare_t *)p1; 944 smb_kshare_t *shr2 = (smb_kshare_t *)p2; 945 int rc; 946 947 ASSERT(shr1); 948 ASSERT(shr1->shr_name); 949 950 ASSERT(shr2); 951 ASSERT(shr2->shr_name); 952 953 rc = smb_strcasecmp(shr1->shr_name, shr2->shr_name, 0); 954 955 if (rc < 0) 956 return (-1); 957 958 if (rc > 0) 959 return (1); 960 961 return (0); 962 } 963 964 /* 965 * This function is called by smb_avl routines whenever 966 * there is a need to take a hold on a share structure 967 * inside AVL 968 */ 969 static void 970 smb_kshare_hold(const void *p) 971 { 972 smb_kshare_t *shr = (smb_kshare_t *)p; 973 974 ASSERT(shr); 975 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC); 976 977 mutex_enter(&shr->shr_mutex); 978 shr->shr_refcnt++; 979 mutex_exit(&shr->shr_mutex); 980 } 981 982 /* 983 * This function must be called by smb_avl routines whenever 984 * smb_kshare_hold is called and the hold needs to be released. 985 */ 986 static boolean_t 987 smb_kshare_rele(const void *p) 988 { 989 smb_kshare_t *shr = (smb_kshare_t *)p; 990 boolean_t destroy; 991 992 ASSERT(shr); 993 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC); 994 995 mutex_enter(&shr->shr_mutex); 996 ASSERT(shr->shr_refcnt > 0); 997 shr->shr_refcnt--; 998 destroy = (shr->shr_refcnt == 0); 999 mutex_exit(&shr->shr_mutex); 1000 1001 return (destroy); 1002 } 1003 1004 /* 1005 * Frees all the memory allocated for the given 1006 * share structure. It also removes the structure 1007 * from the share cache. 1008 */ 1009 static void 1010 smb_kshare_destroy(void *p) 1011 { 1012 smb_kshare_t *shr = (smb_kshare_t *)p; 1013 1014 ASSERT(shr); 1015 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC); 1016 1017 smb_mem_free(shr->shr_name); 1018 smb_mem_free(shr->shr_path); 1019 smb_mem_free(shr->shr_cmnt); 1020 smb_mem_free(shr->shr_container); 1021 smb_mem_free(shr->shr_oemname); 1022 smb_mem_free(shr->shr_access_none); 1023 smb_mem_free(shr->shr_access_ro); 1024 smb_mem_free(shr->shr_access_rw); 1025 1026 kmem_cache_free(smb_kshare_cache_share, shr); 1027 } 1028 1029 1030 /* 1031 * Generate an OEM name for the given share name. If the name is 1032 * shorter than 13 bytes the oemname will be returned; otherwise NULL 1033 * is returned. 1034 */ 1035 static char * 1036 smb_kshare_oemname(const char *shrname) 1037 { 1038 smb_wchar_t *unibuf; 1039 char *oem_name; 1040 int length; 1041 1042 length = strlen(shrname) + 1; 1043 1044 oem_name = smb_mem_alloc(length); 1045 unibuf = smb_mem_alloc(length * sizeof (smb_wchar_t)); 1046 1047 (void) smb_mbstowcs(unibuf, shrname, length); 1048 1049 if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0) 1050 (void) strcpy(oem_name, shrname); 1051 1052 smb_mem_free(unibuf); 1053 1054 if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) { 1055 smb_mem_free(oem_name); 1056 return (NULL); 1057 } 1058 1059 return (oem_name); 1060 } 1061 1062 /* 1063 * Special share reserved for interprocess communication (IPC$) or 1064 * remote administration of the server (ADMIN$). Can also refer to 1065 * administrative shares such as C$, D$, E$, and so forth. 1066 */ 1067 static int 1068 smb_kshare_is_special(const char *sharename) 1069 { 1070 int len; 1071 1072 if (sharename == NULL) 1073 return (0); 1074 1075 if ((len = strlen(sharename)) == 0) 1076 return (0); 1077 1078 if (sharename[len - 1] == '$') 1079 return (STYPE_SPECIAL); 1080 1081 return (0); 1082 } 1083 1084 /* 1085 * Check whether or not this is a default admin share: C$, D$ etc. 1086 */ 1087 static boolean_t 1088 smb_kshare_is_admin(const char *sharename) 1089 { 1090 if (sharename == NULL) 1091 return (B_FALSE); 1092 1093 if (strlen(sharename) == 2 && 1094 smb_isalpha(sharename[0]) && sharename[1] == '$') { 1095 return (B_TRUE); 1096 } 1097 1098 return (B_FALSE); 1099 } 1100 1101 /* 1102 * Decodes the given boolean share option. 1103 * If the option is present in the nvlist and it's value is true 1104 * returns the corresponding flag value, otherwise returns 0. 1105 */ 1106 static uint32_t 1107 smb_kshare_decode_bool(nvlist_t *nvl, const char *propname, uint32_t flag) 1108 { 1109 char *boolp; 1110 1111 if (nvlist_lookup_string(nvl, propname, &boolp) == 0) 1112 if (strcasecmp(boolp, "true") == 0) 1113 return (flag); 1114 1115 return (0); 1116 } 1117 1118 /* 1119 * Map a client-side caching (CSC) option to the appropriate share 1120 * flag. Only one option is allowed; an error will be logged if 1121 * multiple options have been specified. We don't need to do anything 1122 * about multiple values here because the SRVSVC will not recognize 1123 * a value containing multiple flags and will return the default value. 1124 * 1125 * If the option value is not recognized, it will be ignored: invalid 1126 * values will typically be caught and rejected by sharemgr. 1127 */ 1128 static void 1129 smb_kshare_csc_flags(smb_kshare_t *shr, const char *value) 1130 { 1131 int i; 1132 static struct { 1133 char *value; 1134 uint32_t flag; 1135 } cscopt[] = { 1136 { "disabled", SMB_SHRF_CSC_DISABLED }, 1137 { "manual", SMB_SHRF_CSC_MANUAL }, 1138 { "auto", SMB_SHRF_CSC_AUTO }, 1139 { "vdo", SMB_SHRF_CSC_VDO } 1140 }; 1141 1142 if (value == NULL) 1143 return; 1144 1145 for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) { 1146 if (strcasecmp(value, cscopt[i].value) == 0) { 1147 shr->shr_flags |= cscopt[i].flag; 1148 break; 1149 } 1150 } 1151 1152 switch (shr->shr_flags & SMB_SHRF_CSC_MASK) { 1153 case 0: 1154 case SMB_SHRF_CSC_DISABLED: 1155 case SMB_SHRF_CSC_MANUAL: 1156 case SMB_SHRF_CSC_AUTO: 1157 case SMB_SHRF_CSC_VDO: 1158 break; 1159 1160 default: 1161 cmn_err(CE_NOTE, "csc option conflict: 0x%08x", 1162 shr->shr_flags & SMB_SHRF_CSC_MASK); 1163 break; 1164 } 1165 } 1166 1167 /* 1168 * This function processes the unexport event list and disconnects shares 1169 * asynchronously. The function executes as a zone-specific thread. 1170 * 1171 * The server arg passed in is safe to use without a reference count, because 1172 * the server cannot be deleted until smb_thread_stop()/destroy() return, 1173 * which is also when the thread exits. 1174 */ 1175 /*ARGSUSED*/ 1176 static void 1177 smb_kshare_unexport_thread(smb_thread_t *thread, void *arg) 1178 { 1179 smb_server_t *sv = arg; 1180 smb_unshare_t *ux; 1181 1182 while (smb_thread_continue(thread)) { 1183 while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list)) 1184 != NULL) { 1185 smb_slist_remove(&sv->sv_export.e_unexport_list, ux); 1186 (void) smb_server_unshare(ux->us_sharename); 1187 kmem_cache_free(smb_kshare_cache_unexport, ux); 1188 } 1189 } 1190 } 1191 1192 static boolean_t 1193 smb_export_isready(smb_server_t *sv) 1194 { 1195 boolean_t ready; 1196 1197 mutex_enter(&sv->sv_export.e_mutex); 1198 ready = sv->sv_export.e_ready; 1199 mutex_exit(&sv->sv_export.e_mutex); 1200 1201 return (ready); 1202 } 1203 1204 #ifdef _KERNEL 1205 /* 1206 * Return 0 upon success. Otherwise > 0 1207 */ 1208 static int 1209 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx) 1210 { 1211 int status = smb_dr_get_int32(dec_ctx); 1212 int err; 1213 1214 switch (status) { 1215 case SMB_SHARE_DSUCCESS: 1216 return (0); 1217 1218 case SMB_SHARE_DERROR: 1219 err = smb_dr_get_uint32(dec_ctx); 1220 cmn_err(CE_WARN, "%d: Encountered door server error %d", 1221 opcode, err); 1222 (void) smb_dr_decode_finish(dec_ctx); 1223 return (err); 1224 } 1225 1226 ASSERT(0); 1227 return (EINVAL); 1228 } 1229 #endif /* _KERNEL */ 1230