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