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