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