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