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