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 2017 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2017 Joyent, Inc.
26 */
27
28 #include <smbsrv/smb_door.h>
29 #include <smbsrv/smb_ktypes.h>
30 #include <smbsrv/smb2_kproto.h>
31 #include <smbsrv/smb_kstat.h>
32
33 typedef struct smb_unshare {
34 list_node_t us_lnd;
35 char us_sharename[MAXNAMELEN];
36 } smb_unshare_t;
37
38 static kmem_cache_t *smb_kshare_cache_share;
39 static kmem_cache_t *smb_kshare_cache_unexport;
40
41 static int smb_kshare_cmp(const void *, const void *);
42 static void smb_kshare_hold(const void *);
43 static boolean_t smb_kshare_rele(const void *);
44 static void smb_kshare_destroy(void *);
45 static char *smb_kshare_oemname(const char *);
46 static int smb_kshare_is_special(const char *);
47 static boolean_t smb_kshare_is_admin(const char *);
48 static smb_kshare_t *smb_kshare_decode(nvlist_t *);
49 static uint32_t smb_kshare_decode_bool(nvlist_t *, const char *, uint32_t);
50 static void smb_kshare_unexport_thread(smb_thread_t *, void *);
51 static int smb_kshare_export(smb_server_t *, smb_kshare_t *);
52 static int smb_kshare_unexport(smb_server_t *, const char *);
53 static int smb_kshare_export_trans(smb_server_t *, char *, char *, char *);
54 static void smb_kshare_csc_flags(smb_kshare_t *, const char *);
55 static int smb_named_kstat_update(kstat_t *ks, int rw);
56 static int smb_kshare_kstat_update(kstat_t *, int);
57 void kshare_stats_init(smb_server_t *, smb_kshare_t *);
58 void kshare_stats_fini(smb_kshare_t *);
59
60 static boolean_t smb_export_isready(smb_server_t *);
61
62 #ifdef _KERNEL
63 static int smb_kshare_chk_dsrv_status(int, smb_dr_ctx_t *);
64 #endif /* _KERNEL */
65
66 static const smb_avl_nops_t smb_kshare_avlops = {
67 smb_kshare_cmp,
68 smb_kshare_hold,
69 smb_kshare_rele,
70 smb_kshare_destroy
71 };
72
73 #ifdef _KERNEL
74 /*
75 * This function is not MultiThread safe. The caller has to make sure only one
76 * thread calls this function.
77 */
78 door_handle_t
79 smb_kshare_door_init(int door_id)
80 {
81 return (door_ki_lookup(door_id));
82 }
83
84 /*
85 * This function is not MultiThread safe. The caller has to make sure only one
86 * thread calls this function.
87 */
88 void
89 smb_kshare_door_fini(door_handle_t dhdl)
90 {
91 if (dhdl)
92 door_ki_rele(dhdl);
93 }
94
95 /*
96 * This is a special interface that will be utilized by ZFS to cause
97 * a share to be added/removed
98 *
99 * arg is either a smb_share_t or share_name from userspace.
100 * It will need to be copied into the kernel. It is smb_share_t
101 * for add operations and share_name for delete operations.
102 */
103 int
104 smb_kshare_upcall(door_handle_t dhdl, void *arg, boolean_t add_share)
105 {
106 door_arg_t doorarg = { 0 };
107 char *buf = NULL;
108 char *str = NULL;
109 int error;
110 int rc;
111 unsigned int used;
112 smb_dr_ctx_t *dec_ctx;
113 smb_dr_ctx_t *enc_ctx;
114 smb_share_t *lmshare = NULL;
115 int opcode;
116
117 opcode = (add_share) ? SMB_SHROP_ADD : SMB_SHROP_DELETE;
118
119 buf = kmem_alloc(SMB_SHARE_DSIZE, KM_SLEEP);
120 enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE);
121 smb_dr_put_uint32(enc_ctx, opcode);
122
123 switch (opcode) {
124 case SMB_SHROP_ADD:
125 lmshare = kmem_alloc(sizeof (smb_share_t), KM_SLEEP);
126 error = xcopyin(arg, lmshare, sizeof (smb_share_t));
127 if (error != 0) {
128 kmem_free(lmshare, sizeof (smb_share_t));
129 kmem_free(buf, SMB_SHARE_DSIZE);
130 return (error);
131 }
132 smb_dr_put_share(enc_ctx, lmshare);
133 break;
134
135 case SMB_SHROP_DELETE:
136 str = kmem_alloc(MAXPATHLEN, KM_SLEEP);
137 error = copyinstr(arg, str, MAXPATHLEN, NULL);
138 if (error != 0) {
139 kmem_free(str, MAXPATHLEN);
140 kmem_free(buf, SMB_SHARE_DSIZE);
141 return (error);
142 }
143 smb_dr_put_string(enc_ctx, str);
144 kmem_free(str, MAXPATHLEN);
145 break;
146 }
147
148 if ((error = smb_dr_encode_finish(enc_ctx, &used)) != 0) {
149 kmem_free(buf, SMB_SHARE_DSIZE);
150 if (lmshare)
151 kmem_free(lmshare, sizeof (smb_share_t));
152 return (NERR_InternalError);
153 }
154
155 doorarg.data_ptr = buf;
156 doorarg.data_size = used;
157 doorarg.rbuf = buf;
158 doorarg.rsize = SMB_SHARE_DSIZE;
159
160 error = door_ki_upcall_limited(dhdl, &doorarg, NULL, SIZE_MAX, 0);
161
162 if (error) {
163 kmem_free(buf, SMB_SHARE_DSIZE);
164 if (lmshare)
165 kmem_free(lmshare, sizeof (smb_share_t));
166 return (error);
167 }
168
169 dec_ctx = smb_dr_decode_start(doorarg.data_ptr, doorarg.data_size);
170 if (smb_kshare_chk_dsrv_status(opcode, dec_ctx) != 0) {
171 kmem_free(buf, SMB_SHARE_DSIZE);
172 if (lmshare)
173 kmem_free(lmshare, sizeof (smb_share_t));
174 return (NERR_InternalError);
175 }
176
177 rc = smb_dr_get_uint32(dec_ctx);
178 if (opcode == SMB_SHROP_ADD)
179 smb_dr_get_share(dec_ctx, lmshare);
180
181 if (smb_dr_decode_finish(dec_ctx))
182 rc = NERR_InternalError;
183
184 kmem_free(buf, SMB_SHARE_DSIZE);
185 if (lmshare)
186 kmem_free(lmshare, sizeof (smb_share_t));
187
188 return ((rc == NERR_DuplicateShare && add_share) ? 0 : rc);
189 }
190 #endif /* _KERNEL */
191
192 /*
193 * Executes map and unmap command for shares.
194 */
195 int
196 smb_kshare_exec(smb_server_t *sv, smb_shr_execinfo_t *execinfo)
197 {
198 int exec_rc = 0;
199
200 (void) smb_kdoor_upcall(sv, SMB_DR_SHR_EXEC,
201 execinfo, smb_shr_execinfo_xdr, &exec_rc, xdr_int);
202
203 return (exec_rc);
204 }
205
206 /*
207 * Obtains any host access restriction on the specified
208 * share for the given host (ipaddr) by calling smbd
209 */
210 uint32_t
211 smb_kshare_hostaccess(smb_kshare_t *shr, smb_session_t *session)
212 {
213 smb_shr_hostaccess_query_t req;
214 smb_inaddr_t *ipaddr = &session->ipaddr;
215 uint32_t host_access = SMB_SHRF_ACC_OPEN;
216 uint32_t flag = SMB_SHRF_ACC_OPEN;
217 uint32_t access;
218
219 if (smb_inet_iszero(ipaddr))
220 return (ACE_ALL_PERMS);
221
222 if ((shr->shr_access_none == NULL || *shr->shr_access_none == '\0') &&
223 (shr->shr_access_ro == NULL || *shr->shr_access_ro == '\0') &&
224 (shr->shr_access_rw == NULL || *shr->shr_access_rw == '\0'))
225 return (ACE_ALL_PERMS);
226
227 if (shr->shr_access_none != NULL)
228 flag |= SMB_SHRF_ACC_NONE;
229 if (shr->shr_access_ro != NULL)
230 flag |= SMB_SHRF_ACC_RO;
231 if (shr->shr_access_rw != NULL)
232 flag |= SMB_SHRF_ACC_RW;
233
234 req.shq_none = shr->shr_access_none;
235 req.shq_ro = shr->shr_access_ro;
236 req.shq_rw = shr->shr_access_rw;
237 req.shq_flag = flag;
238 req.shq_ipaddr = *ipaddr;
239
240 (void) smb_kdoor_upcall(session->s_server, SMB_DR_SHR_HOSTACCESS,
241 &req, smb_shr_hostaccess_query_xdr, &host_access, xdr_uint32_t);
242
243 switch (host_access) {
244 case SMB_SHRF_ACC_RO:
245 access = ACE_ALL_PERMS & ~ACE_ALL_WRITE_PERMS;
246 break;
247 case SMB_SHRF_ACC_OPEN:
248 case SMB_SHRF_ACC_RW:
249 access = ACE_ALL_PERMS;
250 break;
251 case SMB_SHRF_ACC_NONE:
252 default:
253 access = 0;
254 }
255
256 return (access);
257 }
258
259 /*
260 * This function is called when smb_server_t is
261 * created which means smb/service is ready for
262 * exporting SMB shares
263 */
264 void
265 smb_export_start(smb_server_t *sv)
266 {
267 mutex_enter(&sv->sv_export.e_mutex);
268 if (sv->sv_export.e_ready) {
269 mutex_exit(&sv->sv_export.e_mutex);
270 return;
271 }
272
273 sv->sv_export.e_ready = B_TRUE;
274 mutex_exit(&sv->sv_export.e_mutex);
275
276 smb_avl_create(&sv->sv_export.e_share_avl, sizeof (smb_kshare_t),
277 offsetof(smb_kshare_t, shr_link), &smb_kshare_avlops);
278
279 (void) smb_kshare_export_trans(sv, "IPC$", "IPC$", "Remote IPC");
280 (void) smb_kshare_export_trans(sv, "c$", SMB_CVOL, "Default Share");
281 (void) smb_kshare_export_trans(sv, "vss$", SMB_VSS, "VSS");
282 }
283
284 /*
285 * This function is called when smb_server_t goes
286 * away which means SMB shares should not be made
287 * available to clients
288 */
289 void
290 smb_export_stop(smb_server_t *sv)
291 {
292 mutex_enter(&sv->sv_export.e_mutex);
293 if (!sv->sv_export.e_ready) {
294 mutex_exit(&sv->sv_export.e_mutex);
295 return;
296 }
297 sv->sv_export.e_ready = B_FALSE;
298 mutex_exit(&sv->sv_export.e_mutex);
299
300 smb_avl_destroy(&sv->sv_export.e_share_avl);
301 }
302
303 void
304 smb_kshare_g_init(void)
305 {
306 smb_kshare_cache_share = kmem_cache_create("smb_share_cache",
307 sizeof (smb_kshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
308
309 smb_kshare_cache_unexport = kmem_cache_create("smb_unexport_cache",
310 sizeof (smb_unshare_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
311 }
312
313 void
314 smb_kshare_init(smb_server_t *sv)
315 {
316
317 smb_slist_constructor(&sv->sv_export.e_unexport_list,
318 sizeof (smb_unshare_t), offsetof(smb_unshare_t, us_lnd));
319 }
320
321 int
322 smb_kshare_start(smb_server_t *sv)
323 {
324 smb_thread_init(&sv->sv_export.e_unexport_thread, "smb_kshare_unexport",
325 smb_kshare_unexport_thread, sv, smbsrv_base_pri);
326
327 return (smb_thread_start(&sv->sv_export.e_unexport_thread));
328 }
329
330 void
331 smb_kshare_stop(smb_server_t *sv)
332 {
333 smb_thread_stop(&sv->sv_export.e_unexport_thread);
334 smb_thread_destroy(&sv->sv_export.e_unexport_thread);
335 }
336
337 void
338 smb_kshare_fini(smb_server_t *sv)
339 {
340 smb_unshare_t *ux;
341
342 while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list))
343 != NULL) {
344 smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
345 kmem_cache_free(smb_kshare_cache_unexport, ux);
346 }
347 smb_slist_destructor(&sv->sv_export.e_unexport_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 }
356
357 /*
358 * A list of shares in nvlist format can be sent down
359 * from userspace thourgh the IOCTL interface. The nvlist
360 * is unpacked here and all the shares in the list will
361 * be exported.
362 */
363 int
364 smb_kshare_export_list(smb_ioc_share_t *ioc)
365 {
366 smb_server_t *sv = NULL;
367 nvlist_t *shrlist = NULL;
368 nvlist_t *share;
369 nvpair_t *nvp;
370 smb_kshare_t *shr;
371 char *shrname;
372 int rc;
373
374 if ((rc = smb_server_lookup(&sv)) != 0)
375 return (rc);
376
377 if (!smb_export_isready(sv)) {
378 rc = ENOTACTIVE;
379 goto out;
380 }
381
382 /*
383 * Reality check that the nvlist's reported length doesn't exceed the
384 * ioctl's total length. We then assume the nvlist_unpack() will
385 * sanity check the nvlist itself.
386 */
387 if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) {
388 rc = EINVAL;
389 goto out;
390 }
391 rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, KM_SLEEP);
392 if (rc != 0)
393 goto out;
394
395 for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
396 nvp = nvlist_next_nvpair(shrlist, nvp)) {
397
398 /*
399 * Since this loop can run for a while we want to exit
400 * as soon as the server state is anything but RUNNING
401 * to allow shutdown to proceed.
402 */
403 if (sv->sv_state != SMB_SERVER_STATE_RUNNING)
404 goto out;
405
406 if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
407 continue;
408
409 shrname = nvpair_name(nvp);
410 ASSERT(shrname);
411
412 if ((rc = nvpair_value_nvlist(nvp, &share)) != 0) {
413 cmn_err(CE_WARN, "export[%s]: failed accessing",
414 shrname);
415 continue;
416 }
417
418 if ((shr = smb_kshare_decode(share)) == NULL) {
419 cmn_err(CE_WARN, "export[%s]: failed decoding",
420 shrname);
421 continue;
422 }
423
424 /* smb_kshare_export consumes shr so it's not leaked */
425 if ((rc = smb_kshare_export(sv, shr)) != 0) {
426 smb_kshare_destroy(shr);
427 continue;
428 }
429 }
430 rc = 0;
431
432 out:
433 nvlist_free(shrlist);
434 smb_server_release(sv);
435 return (rc);
436 }
437
438 /*
439 * This function is invoked when a share is disabled to disconnect trees
440 * and close files. Cleaning up may involve VOP and/or VFS calls, which
441 * may conflict/deadlock with stuck threads if something is amiss with the
442 * file system. Queueing the request for asynchronous processing allows the
443 * call to return immediately so that, if the unshare is being done in the
444 * context of a forced unmount, the forced unmount will always be able to
445 * proceed (unblocking stuck I/O and eventually allowing all blocked unshare
446 * processes to complete).
447 *
448 * The path lookup to find the root vnode of the VFS in question and the
449 * release of this vnode are done synchronously prior to any associated
450 * unmount. Doing these asynchronous to an associated unmount could run
451 * the risk of a spurious EBUSY for a standard unmount or an EIO during
452 * the path lookup due to a forced unmount finishing first.
453 */
454 int
455 smb_kshare_unexport_list(smb_ioc_share_t *ioc)
456 {
457 smb_server_t *sv = NULL;
458 smb_unshare_t *ux;
459 nvlist_t *shrlist = NULL;
460 nvpair_t *nvp;
461 boolean_t unexport = B_FALSE;
462 char *shrname;
463 int rc;
464
465 if ((rc = smb_server_lookup(&sv)) != 0)
466 return (rc);
467
468 /*
469 * Reality check that the nvlist's reported length doesn't exceed the
470 * ioctl's total length. We then assume the nvlist_unpack() will
471 * sanity check the nvlist itself.
472 */
473 if ((ioc->shrlen + offsetof(smb_ioc_share_t, shr)) > ioc->hdr.len) {
474 rc = EINVAL;
475 goto out;
476 }
477 if ((rc = nvlist_unpack(ioc->shr, ioc->shrlen, &shrlist, 0)) != 0)
478 goto out;
479
480 for (nvp = nvlist_next_nvpair(shrlist, NULL); nvp != NULL;
481 nvp = nvlist_next_nvpair(shrlist, nvp)) {
482 if (nvpair_type(nvp) != DATA_TYPE_NVLIST)
483 continue;
484
485 shrname = nvpair_name(nvp);
486 ASSERT(shrname);
487
488 if ((rc = smb_kshare_unexport(sv, shrname)) != 0)
489 continue;
490
491 ux = kmem_cache_alloc(smb_kshare_cache_unexport, KM_SLEEP);
492 (void) strlcpy(ux->us_sharename, shrname, MAXNAMELEN);
493
494 smb_slist_insert_tail(&sv->sv_export.e_unexport_list, ux);
495 unexport = B_TRUE;
496 }
497
498 if (unexport)
499 smb_thread_signal(&sv->sv_export.e_unexport_thread);
500 rc = 0;
501
502 out:
503 nvlist_free(shrlist);
504 smb_server_release(sv);
505 return (rc);
506 }
507
508 /*
509 * Get properties (currently only shortname enablement)
510 * of specified share.
511 */
512 int
513 smb_kshare_info(smb_ioc_shareinfo_t *ioc)
514 {
515 ioc->shortnames = smb_shortnames;
516 return (0);
517 }
518
519 /*
520 * This function builds a response for a NetShareEnum RAP request.
521 * List of shares is scanned twice. In the first round the total number
522 * of shares which their OEM name is shorter than 13 chars (esi->es_ntotal)
523 * and also the number of shares that fit in the given buffer are calculated.
524 * In the second round the shares data are encoded in the buffer.
525 *
526 * The data associated with each share has two parts, a fixed size part and
527 * a variable size part which is share's comment. The outline of the response
528 * buffer is so that fixed part for all the shares will appear first and follows
529 * with the comments for all those shares and that's why the data cannot be
530 * encoded in one round without unnecessarily complicating the code.
531 */
532 void
533 smb_kshare_enum(smb_server_t *sv, smb_enumshare_info_t *esi)
534 {
535 smb_avl_t *share_avl;
536 smb_avl_cursor_t cursor;
537 smb_kshare_t *shr;
538 int remained;
539 uint16_t infolen = 0;
540 uint16_t cmntlen = 0;
541 uint16_t sharelen;
542 uint16_t clen;
543 uint32_t cmnt_offs;
544 smb_msgbuf_t info_mb;
545 smb_msgbuf_t cmnt_mb;
546 boolean_t autohome_added = B_FALSE;
547
548 if (!smb_export_isready(sv)) {
549 esi->es_ntotal = esi->es_nsent = 0;
550 esi->es_datasize = 0;
551 return;
552 }
553
554 esi->es_ntotal = esi->es_nsent = 0;
555 remained = esi->es_bufsize;
556 share_avl = &sv->sv_export.e_share_avl;
557
558 /* Do the necessary calculations in the first round */
559 smb_avl_iterinit(share_avl, &cursor);
560
561 while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
562 if (shr->shr_oemname == NULL) {
563 smb_avl_release(share_avl, shr);
564 continue;
565 }
566
567 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
568 if (esi->es_posix_uid == shr->shr_uid) {
569 autohome_added = B_TRUE;
570 } else {
571 smb_avl_release(share_avl, shr);
572 continue;
573 }
574 }
575
576 esi->es_ntotal++;
577
578 if (remained <= 0) {
579 smb_avl_release(share_avl, shr);
580 continue;
581 }
582
583 clen = strlen(shr->shr_cmnt) + 1;
584 sharelen = SHARE_INFO_1_SIZE + clen;
585
586 if (sharelen <= remained) {
587 infolen += SHARE_INFO_1_SIZE;
588 cmntlen += clen;
589 }
590
591 remained -= sharelen;
592 smb_avl_release(share_avl, shr);
593 }
594
595 esi->es_datasize = infolen + cmntlen;
596
597 smb_msgbuf_init(&info_mb, (uint8_t *)esi->es_buf, infolen, 0);
598 smb_msgbuf_init(&cmnt_mb, (uint8_t *)esi->es_buf + infolen, cmntlen, 0);
599 cmnt_offs = infolen;
600
601 /* Encode the data in the second round */
602 smb_avl_iterinit(share_avl, &cursor);
603 autohome_added = B_FALSE;
604
605 while ((shr = smb_avl_iterate(share_avl, &cursor)) != NULL) {
606 if (shr->shr_oemname == NULL) {
607 smb_avl_release(share_avl, shr);
608 continue;
609 }
610
611 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) && !autohome_added) {
612 if (esi->es_posix_uid == shr->shr_uid) {
613 autohome_added = B_TRUE;
614 } else {
615 smb_avl_release(share_avl, shr);
616 continue;
617 }
618 }
619
620 if (smb_msgbuf_encode(&info_mb, "13c.wl",
621 shr->shr_oemname, shr->shr_type, cmnt_offs) < 0) {
622 smb_avl_release(share_avl, shr);
623 break;
624 }
625
626 if (smb_msgbuf_encode(&cmnt_mb, "s", shr->shr_cmnt) < 0) {
627 smb_avl_release(share_avl, shr);
628 break;
629 }
630
631 cmnt_offs += strlen(shr->shr_cmnt) + 1;
632 esi->es_nsent++;
633
634 smb_avl_release(share_avl, shr);
635 }
636
637 smb_msgbuf_term(&info_mb);
638 smb_msgbuf_term(&cmnt_mb);
639 }
640
641 /*
642 * Looks up the given share and returns a pointer
643 * to its definition if it's found. A hold on the
644 * object is taken before the pointer is returned
645 * in which case the caller MUST always call
646 * smb_kshare_release().
647 */
648 smb_kshare_t *
649 smb_kshare_lookup(smb_server_t *sv, const char *shrname)
650 {
651 smb_kshare_t key;
652 smb_kshare_t *shr;
653
654 ASSERT(shrname);
655
656 if (!smb_export_isready(sv))
657 return (NULL);
658
659 key.shr_name = (char *)shrname;
660 shr = smb_avl_lookup(&sv->sv_export.e_share_avl, &key);
661 return (shr);
662 }
663
664 /*
665 * Releases the hold taken on the specified share object
666 */
667 void
668 smb_kshare_release(smb_server_t *sv, smb_kshare_t *shr)
669 {
670 ASSERT(shr);
671 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
672
673 smb_avl_release(&sv->sv_export.e_share_avl, shr);
674 }
675
676 /*
677 * Add the given share in the specified server.
678 * If the share is a disk share, lookup the share path
679 * and hold the smb_node_t for the share root.
680 *
681 * If the share is an Autohome share and it is
682 * already in the AVL only a reference count for
683 * that share is incremented.
684 */
685 static int
686 smb_kshare_export(smb_server_t *sv, smb_kshare_t *shr)
687 {
688 smb_avl_t *share_avl;
689 smb_kshare_t *auto_shr;
690 smb_node_t *snode = NULL;
691 int rc = 0;
692
693 share_avl = &sv->sv_export.e_share_avl;
694
695 if (!STYPE_ISDSK(shr->shr_type)) {
696 if ((rc = smb_avl_add(share_avl, shr)) != 0) {
697 cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
698 shr->shr_name, rc);
699 }
700
701 return (rc);
702 }
703
704 if ((auto_shr = smb_avl_lookup(share_avl, shr)) != NULL) {
705 rc = EEXIST;
706 if ((auto_shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
707 mutex_enter(&auto_shr->shr_mutex);
708 auto_shr->shr_autocnt++;
709 mutex_exit(&auto_shr->shr_mutex);
710 rc = 0;
711 }
712 smb_avl_release(share_avl, auto_shr);
713 return (rc);
714 }
715
716 /*
717 * Get the root smb_node_t for this share, held.
718 * This hold is normally released during AVL destroy,
719 * via the element destructor: smb_kshare_destroy
720 */
721 rc = smb_server_share_lookup(sv, shr->shr_path, &snode);
722 if (rc != 0) {
723 cmn_err(CE_WARN, "export[%s(%s)]: lookup failed (%d)",
724 shr->shr_name, shr->shr_path, rc);
725 return (rc);
726 }
727
728 shr->shr_root_node = snode;
729 if ((rc = smb_avl_add(share_avl, shr)) != 0) {
730 cmn_err(CE_WARN, "export[%s]: failed caching (%d)",
731 shr->shr_name, rc);
732 shr->shr_root_node = NULL;
733 smb_node_release(snode);
734 return (rc);
735 }
736
737 kshare_stats_init(sv, shr);
738
739 /*
740 * For CA shares, find or create the CA handle dir,
741 * and (if restarted) import persistent handles.
742 */
743 if ((shr->shr_flags & SMB_SHRF_CA) != 0) {
744 rc = smb2_dh_new_ca_share(sv, shr);
745 if (rc != 0) {
746 /* Just make it a non-CA share. */
747 mutex_enter(&shr->shr_mutex);
748 shr->shr_flags &= ~SMB_SHRF_CA;
749 mutex_exit(&shr->shr_mutex);
750 rc = 0;
751 }
752 }
753
754 return (rc);
755 }
756
757
758 /*
759 * Following a pattern somewhat similar to smb_server_kstat_init,
760 * but organized a little differently.
761 */
762 void
763 kshare_stats_init(smb_server_t *sv, smb_kshare_t *ks)
764 {
765 static const char *kr_names[] = SMBSRV_CLSH__NAMES;
766 char ks_name[KSTAT_STRLEN];
767 smbsrv_clsh_kstats_t *ksr;
768 int idx;
769 smb_named_stats_t *smbnsp;
770 kstat_t *kstat = NULL;
771 int namelen;
772
773 /*
774 * Most share names are short, and we'd like to allow consumers like
775 * the smbstat command to compose the kstat names for short share names
776 * directly. In the (rare) case where we have longer share names, we
777 * need an indirection scheme to get around the limited (31 chars) size
778 * of kstat names. So for share names 24 chars or shorter, we compose
779 * the kstat name directly as "smbsrv:0:sh/sharename" and when the share
780 * name is longer, compose the kstat name using an arbitrary
781 * (but unique) identifier like: "smbsrv:0:sh/:ffffff0009560a98". To
782 * find the unique identifier given a (long) share name, the consumer
783 * has to enumerate the (fake) "smbsrvshr" kstat module, looking for the
784 * kstat with the sharename element matching the one they want. Both
785 * direct and indirect names are instantiated under the "smbsrvshr"
786 * module, so a consumer that wants all the share kstats could always
787 * lookup the kstat names using the indirection scheme if that's easier.
788 * (Nothing forces the consumer to directly compose kstat names when the
789 * share name happens to be short -- they can always enumerate to find
790 * it.)
791 *
792 * SMB share names are not allowed to contain a colon. The naming
793 * scheme here uses a colon at the beginning of what would otherwise be
794 * the share name part of the kstat name to indicate that this name uses
795 * the "indirection" scheme. With indirection, the part after the colon
796 * is an arbitrary (but unique per share) identifier of some other
797 * kstat, and a consumer needs to fetch that kstat to get the real share
798 * name.
799 */
800 namelen = strlen(ks->shr_name);
801 if (namelen <= 24) {
802 (void) snprintf(ks_name, sizeof (ks_name), "sh/%s",
803 ks->shr_name);
804
805 kstat = kstat_hold_byname("smbsrvshr", 0, ks_name, sv->sv_zid);
806 }
807
808 if (namelen > 24 || kstat != NULL) {
809 (void) snprintf(ks_name, sizeof (ks_name), "sh/:%p",
810 (void *)ks);
811
812 if (kstat != NULL)
813 kstat_rele(kstat);
814 }
815
816 ks->shr_ksp = kstat_create_zone(SMBSRV_KSTAT_MODULE, 0,
817 ks_name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_RAW,
818 sizeof (smbsrv_clsh_kstats_t), 0, sv->sv_zid);
819
820 if (ks->shr_ksp == NULL)
821 return;
822
823 ks->stats.ksns = kstat_create_zone("smbsrvshr", 0,
824 ks_name, SMBSRV_KSTAT_CLASS, KSTAT_TYPE_NAMED,
825 0, KSTAT_FLAG_VIRTUAL, sv->sv_zid);
826
827 if (ks->stats.ksns == NULL) {
828 kstat_delete(ks->shr_ksp);
829 ks->shr_ksp = NULL;
830 return;
831 }
832
833 ks->shr_ksp->ks_update = smb_kshare_kstat_update;
834 ks->shr_ksp->ks_private = ks;
835
836 /*
837 * In-line equivalent of smb_dispatch_stats_init
838 */
839 ksr = (smbsrv_clsh_kstats_t *)ks->shr_ksp->ks_data;
840 for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++) {
841 smb_latency_init(&ks->shr_stats[idx].sdt_lat);
842 (void) strlcpy(ksr->ks_clsh[idx].kr_name, kr_names[idx],
843 KSTAT_STRLEN);
844 }
845
846 /*
847 * SMB named kstats setup for > KSTAT_STRLEN name to short name mapping.
848 */
849 smbnsp = &ks->stats.ks_data;
850 ks->stats.ksns->ks_data = &ks->stats.ks_data;
851 ks->stats.ksns->ks_data_size = sizeof (ks->stats.ks_data);
852 ks->stats.ksns->ks_ndata = 1;
853 kstat_named_init(smbnsp->kn, "share name",
854 KSTAT_DATA_STRING);
855 ks->stats.ksns->ks_update = smb_named_kstat_update;
856 ks->stats.ksns->ks_private = (void *)ks;
857
858 kstat_install(ks->shr_ksp);
859 kstat_install(ks->stats.ksns);
860 }
861
862 void
863 kshare_stats_fini(smb_kshare_t *ks)
864 {
865 int idx;
866
867 for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++)
868 smb_latency_destroy(&ks->shr_stats[idx].sdt_lat);
869 }
870
871 static int
872 smb_named_kstat_update(kstat_t *ks, int rw)
873 {
874 smb_kshare_t *smbksp = (smb_kshare_t *)ks->ks_private;
875 smb_named_stats_t *smbnsp = &smbksp->stats.ks_data;
876
877 if (rw == KSTAT_READ) {
878 (void) strlcpy(smbnsp->name, smbksp->shr_name,
879 sizeof (smbnsp->name));
880
881 kstat_named_setstr(&smbnsp->kn[0],
882 (const char *)smbksp->shr_name);
883 }
884 return (0);
885 }
886
887 /*
888 * Update the kstat data from our private stats.
889 */
890 static int
891 smb_kshare_kstat_update(kstat_t *ksp, int rw)
892 {
893 smb_kshare_t *kshare;
894 smb_disp_stats_t *sds;
895 smbsrv_clsh_kstats_t *clsh;
896 smb_kstat_req_t *ksr;
897 int i;
898
899 if (rw == KSTAT_WRITE)
900 return (EACCES);
901
902 kshare = ksp->ks_private;
903 ASSERT(kshare->shr_magic == SMB_SHARE_MAGIC);
904 sds = kshare->shr_stats;
905
906 clsh = (smbsrv_clsh_kstats_t *)ksp->ks_data;
907 ksr = clsh->ks_clsh;
908
909 for (i = 0; i < SMBSRV_CLSH__NREQ; i++, ksr++, sds++) {
910 ksr->kr_rxb = sds->sdt_rxb;
911 ksr->kr_txb = sds->sdt_txb;
912 mutex_enter(&sds->sdt_lat.ly_mutex);
913 ksr->kr_nreq = sds->sdt_lat.ly_a_nreq;
914 ksr->kr_sum = sds->sdt_lat.ly_a_sum;
915 ksr->kr_a_mean = sds->sdt_lat.ly_a_mean;
916 ksr->kr_a_stddev = sds->sdt_lat.ly_a_stddev;
917 ksr->kr_d_mean = sds->sdt_lat.ly_d_mean;
918 ksr->kr_d_stddev = sds->sdt_lat.ly_d_stddev;
919 sds->sdt_lat.ly_d_mean = 0;
920 sds->sdt_lat.ly_d_nreq = 0;
921 sds->sdt_lat.ly_d_stddev = 0;
922 sds->sdt_lat.ly_d_sum = 0;
923 mutex_exit(&sds->sdt_lat.ly_mutex);
924 }
925
926 return (0);
927 }
928
929 /*
930 * Removes the share specified by 'shrname' from the AVL
931 * tree of the given server if it's there.
932 *
933 * If the share is an Autohome share, the autohome count
934 * is decremented and the share is only removed if the
935 * count goes to zero.
936 *
937 * If the share is a disk share, the hold on the corresponding
938 * file system is released before removing the share from
939 * the AVL tree.
940 */
941 static int
942 smb_kshare_unexport(smb_server_t *sv, const char *shrname)
943 {
944 smb_avl_t *share_avl;
945 smb_kshare_t key;
946 smb_kshare_t *shr;
947 boolean_t auto_unexport;
948
949 share_avl = &sv->sv_export.e_share_avl;
950
951 key.shr_name = (char *)shrname;
952 if ((shr = smb_avl_lookup(share_avl, &key)) == NULL)
953 return (ENOENT);
954
955 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
956 mutex_enter(&shr->shr_mutex);
957 shr->shr_autocnt--;
958 auto_unexport = (shr->shr_autocnt == 0);
959 mutex_exit(&shr->shr_mutex);
960 if (!auto_unexport) {
961 smb_avl_release(share_avl, shr);
962 return (0);
963 }
964 }
965
966 smb_avl_remove(share_avl, shr);
967
968 mutex_enter(&shr->shr_mutex);
969 shr->shr_flags |= SMB_SHRF_REMOVED;
970 mutex_exit(&shr->shr_mutex);
971
972 smb_avl_release(share_avl, shr);
973
974 return (0);
975 }
976
977 /*
978 * Exports IPC$ or Admin shares
979 */
980 static int
981 smb_kshare_export_trans(smb_server_t *sv, char *name, char *path, char *cmnt)
982 {
983 smb_kshare_t *shr;
984
985 ASSERT(name);
986 ASSERT(path);
987
988 shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
989 bzero(shr, sizeof (smb_kshare_t));
990
991 shr->shr_magic = SMB_SHARE_MAGIC;
992 shr->shr_refcnt = 1;
993 shr->shr_flags = SMB_SHRF_TRANS | smb_kshare_is_admin(shr->shr_name);
994 if (strcasecmp(name, "IPC$") == 0)
995 shr->shr_type = STYPE_IPC;
996 else
997 shr->shr_type = STYPE_DISKTREE;
998
999 shr->shr_type |= smb_kshare_is_special(shr->shr_name);
1000
1001 shr->shr_name = smb_mem_strdup(name);
1002 if (path)
1003 shr->shr_path = smb_mem_strdup(path);
1004 if (cmnt)
1005 shr->shr_cmnt = smb_mem_strdup(cmnt);
1006 shr->shr_oemname = smb_kshare_oemname(name);
1007
1008 return (smb_kshare_export(sv, shr));
1009 }
1010
1011 /*
1012 * Decodes share information in an nvlist format into a smb_kshare_t
1013 * structure.
1014 *
1015 * This is a temporary function and will be replaced by functions
1016 * provided by libsharev2 code after it's available.
1017 */
1018 static smb_kshare_t *
1019 smb_kshare_decode(nvlist_t *share)
1020 {
1021 smb_kshare_t tmp;
1022 smb_kshare_t *shr;
1023 nvlist_t *smb;
1024 char *csc_name = NULL, *strbuf = NULL;
1025 int rc;
1026
1027 ASSERT(share);
1028
1029 bzero(&tmp, sizeof (smb_kshare_t));
1030
1031 rc = nvlist_lookup_string(share, "name", &tmp.shr_name);
1032 rc |= nvlist_lookup_string(share, "path", &tmp.shr_path);
1033 (void) nvlist_lookup_string(share, "desc", &tmp.shr_cmnt);
1034
1035 ASSERT(tmp.shr_name && tmp.shr_path);
1036
1037 rc |= nvlist_lookup_nvlist(share, "smb", &smb);
1038 if (rc != 0) {
1039 cmn_err(CE_WARN, "kshare: failed looking up SMB properties"
1040 " (%d)", rc);
1041 return (NULL);
1042 }
1043
1044 rc = nvlist_lookup_uint32(smb, "type", &tmp.shr_type);
1045 if (rc != 0) {
1046 cmn_err(CE_WARN, "kshare[%s]: failed getting the share type"
1047 " (%d)", tmp.shr_name, rc);
1048 return (NULL);
1049 }
1050
1051 (void) nvlist_lookup_string(smb, SHOPT_AD_CONTAINER,
1052 &tmp.shr_container);
1053 (void) nvlist_lookup_string(smb, SHOPT_NONE, &tmp.shr_access_none);
1054 (void) nvlist_lookup_string(smb, SHOPT_RO, &tmp.shr_access_ro);
1055 (void) nvlist_lookup_string(smb, SHOPT_RW, &tmp.shr_access_rw);
1056
1057 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_ABE, SMB_SHRF_ABE);
1058 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CATIA,
1059 SMB_SHRF_CATIA);
1060 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_GUEST,
1061 SMB_SHRF_GUEST_OK);
1062 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_DFSROOT,
1063 SMB_SHRF_DFSROOT);
1064 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_QUOTAS,
1065 SMB_SHRF_QUOTAS);
1066 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_CA, SMB_SHRF_CA);
1067 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_FSO, SMB_SHRF_FSO);
1068 tmp.shr_flags |= smb_kshare_decode_bool(smb, SHOPT_AUTOHOME,
1069 SMB_SHRF_AUTOHOME);
1070
1071 if ((tmp.shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME) {
1072 rc = nvlist_lookup_uint32(smb, "uid", &tmp.shr_uid);
1073 rc |= nvlist_lookup_uint32(smb, "gid", &tmp.shr_gid);
1074 if (rc != 0) {
1075 cmn_err(CE_WARN, "kshare: failed looking up uid/gid"
1076 " (%d)", rc);
1077 return (NULL);
1078 }
1079 }
1080
1081 (void) nvlist_lookup_string(smb, SHOPT_ENCRYPT, &strbuf);
1082 smb_cfg_set_require(strbuf, &tmp.shr_encrypt);
1083
1084 (void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name);
1085 smb_kshare_csc_flags(&tmp, csc_name);
1086
1087 shr = kmem_cache_alloc(smb_kshare_cache_share, KM_SLEEP);
1088 bzero(shr, sizeof (smb_kshare_t));
1089
1090 shr->shr_magic = SMB_SHARE_MAGIC;
1091 shr->shr_refcnt = 1;
1092
1093 shr->shr_name = smb_mem_strdup(tmp.shr_name);
1094 shr->shr_path = smb_mem_strdup(tmp.shr_path);
1095 if (tmp.shr_cmnt)
1096 shr->shr_cmnt = smb_mem_strdup(tmp.shr_cmnt);
1097 if (tmp.shr_container)
1098 shr->shr_container = smb_mem_strdup(tmp.shr_container);
1099 if (tmp.shr_access_none)
1100 shr->shr_access_none = smb_mem_strdup(tmp.shr_access_none);
1101 if (tmp.shr_access_ro)
1102 shr->shr_access_ro = smb_mem_strdup(tmp.shr_access_ro);
1103 if (tmp.shr_access_rw)
1104 shr->shr_access_rw = smb_mem_strdup(tmp.shr_access_rw);
1105
1106 shr->shr_oemname = smb_kshare_oemname(shr->shr_name);
1107 shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name);
1108 shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name);
1109 shr->shr_encrypt = tmp.shr_encrypt;
1110
1111 shr->shr_uid = tmp.shr_uid;
1112 shr->shr_gid = tmp.shr_gid;
1113
1114 if ((shr->shr_flags & SMB_SHRF_AUTOHOME) == SMB_SHRF_AUTOHOME)
1115 shr->shr_autocnt = 1;
1116 return (shr);
1117 }
1118
1119 #if 0
1120 static void
1121 smb_kshare_log(smb_kshare_t *shr)
1122 {
1123 cmn_err(CE_NOTE, "Share info:");
1124 cmn_err(CE_NOTE, "\tname: %s", (shr->shr_name) ? shr->shr_name : "");
1125 cmn_err(CE_NOTE, "\tpath: %s", (shr->shr_path) ? shr->shr_path : "");
1126 cmn_err(CE_NOTE, "\tcmnt: (%s)",
1127 (shr->shr_cmnt) ? shr->shr_cmnt : "NULL");
1128 cmn_err(CE_NOTE, "\toemname: (%s)",
1129 (shr->shr_oemname) ? shr->shr_oemname : "NULL");
1130 cmn_err(CE_NOTE, "\tflags: %X", shr->shr_flags);
1131 cmn_err(CE_NOTE, "\ttype: %d", shr->shr_type);
1132 }
1133 #endif
1134
1135 /*
1136 * Compare function used by shares AVL
1137 */
1138 static int
1139 smb_kshare_cmp(const void *p1, const void *p2)
1140 {
1141 smb_kshare_t *shr1 = (smb_kshare_t *)p1;
1142 smb_kshare_t *shr2 = (smb_kshare_t *)p2;
1143 int rc;
1144
1145 ASSERT(shr1);
1146 ASSERT(shr1->shr_name);
1147
1148 ASSERT(shr2);
1149 ASSERT(shr2->shr_name);
1150
1151 rc = smb_strcasecmp(shr1->shr_name, shr2->shr_name, 0);
1152
1153 if (rc < 0)
1154 return (-1);
1155
1156 if (rc > 0)
1157 return (1);
1158
1159 return (0);
1160 }
1161
1162 /*
1163 * This function is called by smb_avl routines whenever
1164 * there is a need to take a hold on a share structure
1165 * inside AVL
1166 */
1167 static void
1168 smb_kshare_hold(const void *p)
1169 {
1170 smb_kshare_t *shr = (smb_kshare_t *)p;
1171
1172 ASSERT(shr);
1173 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1174
1175 mutex_enter(&shr->shr_mutex);
1176 shr->shr_refcnt++;
1177 mutex_exit(&shr->shr_mutex);
1178 }
1179
1180 /*
1181 * This function must be called by smb_avl routines whenever
1182 * smb_kshare_hold is called and the hold needs to be released.
1183 */
1184 static boolean_t
1185 smb_kshare_rele(const void *p)
1186 {
1187 smb_kshare_t *shr = (smb_kshare_t *)p;
1188 boolean_t destroy;
1189
1190 ASSERT(shr);
1191 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1192
1193 mutex_enter(&shr->shr_mutex);
1194 ASSERT(shr->shr_refcnt > 0);
1195 shr->shr_refcnt--;
1196 destroy = (shr->shr_refcnt == 0);
1197 mutex_exit(&shr->shr_mutex);
1198
1199 return (destroy);
1200 }
1201
1202 /*
1203 * Frees all the memory allocated for the given
1204 * share structure. It also removes the structure
1205 * from the share cache.
1206 */
1207 static void
1208 smb_kshare_destroy(void *p)
1209 {
1210 smb_kshare_t *shr = (smb_kshare_t *)p;
1211
1212 ASSERT(shr);
1213 ASSERT(shr->shr_magic == SMB_SHARE_MAGIC);
1214
1215 if (shr->shr_ksp != NULL) {
1216 kstat_delete(shr->shr_ksp);
1217 shr->shr_ksp = NULL;
1218 kshare_stats_fini(shr);
1219 }
1220
1221 if (shr->stats.ksns != NULL) {
1222 kstat_delete(shr->stats.ksns);
1223 }
1224
1225 if (shr->shr_ca_dir != NULL)
1226 smb_node_release(shr->shr_ca_dir);
1227 if (shr->shr_root_node)
1228 smb_node_release(shr->shr_root_node);
1229
1230 smb_mem_free(shr->shr_name);
1231 smb_mem_free(shr->shr_path);
1232 smb_mem_free(shr->shr_cmnt);
1233 smb_mem_free(shr->shr_container);
1234 smb_mem_free(shr->shr_oemname);
1235 smb_mem_free(shr->shr_access_none);
1236 smb_mem_free(shr->shr_access_ro);
1237 smb_mem_free(shr->shr_access_rw);
1238
1239 kmem_cache_free(smb_kshare_cache_share, shr);
1240 }
1241
1242
1243 /*
1244 * Generate an OEM name for the given share name. If the name is
1245 * shorter than 13 bytes the oemname will be returned; otherwise NULL
1246 * is returned.
1247 */
1248 static char *
1249 smb_kshare_oemname(const char *shrname)
1250 {
1251 smb_wchar_t *unibuf;
1252 char *oem_name;
1253 int length;
1254
1255 length = strlen(shrname) + 1;
1256
1257 oem_name = smb_mem_alloc(length);
1258 unibuf = smb_mem_alloc(length * sizeof (smb_wchar_t));
1259
1260 (void) smb_mbstowcs(unibuf, shrname, length);
1261
1262 if (ucstooem(oem_name, unibuf, length, OEM_CPG_850) == 0)
1263 (void) strcpy(oem_name, shrname);
1264
1265 smb_mem_free(unibuf);
1266
1267 if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
1268 smb_mem_free(oem_name);
1269 return (NULL);
1270 }
1271
1272 return (oem_name);
1273 }
1274
1275 /*
1276 * Special share reserved for interprocess communication (IPC$) or
1277 * remote administration of the server (ADMIN$). Can also refer to
1278 * administrative shares such as C$, D$, E$, and so forth.
1279 */
1280 static int
1281 smb_kshare_is_special(const char *sharename)
1282 {
1283 int len;
1284
1285 if (sharename == NULL)
1286 return (0);
1287
1288 if ((len = strlen(sharename)) == 0)
1289 return (0);
1290
1291 if (sharename[len - 1] == '$')
1292 return (STYPE_SPECIAL);
1293
1294 return (0);
1295 }
1296
1297 /*
1298 * Check whether or not this is a default admin share: C$, D$ etc.
1299 */
1300 static boolean_t
1301 smb_kshare_is_admin(const char *sharename)
1302 {
1303 if (sharename == NULL)
1304 return (B_FALSE);
1305
1306 if (strlen(sharename) == 2 &&
1307 smb_isalpha(sharename[0]) && sharename[1] == '$') {
1308 return (B_TRUE);
1309 }
1310
1311 return (B_FALSE);
1312 }
1313
1314 /*
1315 * Decodes the given boolean share option.
1316 * If the option is present in the nvlist and it's value is true
1317 * returns the corresponding flag value, otherwise returns 0.
1318 */
1319 static uint32_t
1320 smb_kshare_decode_bool(nvlist_t *nvl, const char *propname, uint32_t flag)
1321 {
1322 char *boolp;
1323
1324 if (nvlist_lookup_string(nvl, propname, &boolp) == 0)
1325 if (strcasecmp(boolp, "true") == 0)
1326 return (flag);
1327
1328 return (0);
1329 }
1330
1331 /*
1332 * Map a client-side caching (CSC) option to the appropriate share
1333 * flag. Only one option is allowed; an error will be logged if
1334 * multiple options have been specified. We don't need to do anything
1335 * about multiple values here because the SRVSVC will not recognize
1336 * a value containing multiple flags and will return the default value.
1337 *
1338 * If the option value is not recognized, it will be ignored: invalid
1339 * values will typically be caught and rejected by sharemgr.
1340 */
1341 static void
1342 smb_kshare_csc_flags(smb_kshare_t *shr, const char *value)
1343 {
1344 int i;
1345 static struct {
1346 char *value;
1347 uint32_t flag;
1348 } cscopt[] = {
1349 { "disabled", SMB_SHRF_CSC_DISABLED },
1350 { "manual", SMB_SHRF_CSC_MANUAL },
1351 { "auto", SMB_SHRF_CSC_AUTO },
1352 { "vdo", SMB_SHRF_CSC_VDO }
1353 };
1354
1355 if (value == NULL)
1356 return;
1357
1358 for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1359 if (strcasecmp(value, cscopt[i].value) == 0) {
1360 shr->shr_flags |= cscopt[i].flag;
1361 break;
1362 }
1363 }
1364
1365 switch (shr->shr_flags & SMB_SHRF_CSC_MASK) {
1366 case 0:
1367 case SMB_SHRF_CSC_DISABLED:
1368 case SMB_SHRF_CSC_MANUAL:
1369 case SMB_SHRF_CSC_AUTO:
1370 case SMB_SHRF_CSC_VDO:
1371 break;
1372
1373 default:
1374 cmn_err(CE_NOTE, "csc option conflict: 0x%08x",
1375 shr->shr_flags & SMB_SHRF_CSC_MASK);
1376 break;
1377 }
1378 }
1379
1380 /*
1381 * This function processes the unexport event list and disconnects shares
1382 * asynchronously. The function executes as a zone-specific thread.
1383 *
1384 * The server arg passed in is safe to use without a reference count, because
1385 * the server cannot be deleted until smb_thread_stop()/destroy() return,
1386 * which is also when the thread exits.
1387 */
1388 /*ARGSUSED*/
1389 static void
1390 smb_kshare_unexport_thread(smb_thread_t *thread, void *arg)
1391 {
1392 smb_server_t *sv = arg;
1393 smb_unshare_t *ux;
1394
1395 while (smb_thread_continue(thread)) {
1396 while ((ux = list_head(&sv->sv_export.e_unexport_list.sl_list))
1397 != NULL) {
1398 smb_slist_remove(&sv->sv_export.e_unexport_list, ux);
1399 (void) smb_server_unshare(ux->us_sharename);
1400 kmem_cache_free(smb_kshare_cache_unexport, ux);
1401 }
1402 }
1403 }
1404
1405 static boolean_t
1406 smb_export_isready(smb_server_t *sv)
1407 {
1408 boolean_t ready;
1409
1410 mutex_enter(&sv->sv_export.e_mutex);
1411 ready = sv->sv_export.e_ready;
1412 mutex_exit(&sv->sv_export.e_mutex);
1413
1414 return (ready);
1415 }
1416
1417 #ifdef _KERNEL
1418 /*
1419 * Return 0 upon success. Otherwise > 0
1420 */
1421 static int
1422 smb_kshare_chk_dsrv_status(int opcode, smb_dr_ctx_t *dec_ctx)
1423 {
1424 int status = smb_dr_get_int32(dec_ctx);
1425 int err;
1426
1427 switch (status) {
1428 case SMB_SHARE_DSUCCESS:
1429 return (0);
1430
1431 case SMB_SHARE_DERROR:
1432 err = smb_dr_get_uint32(dec_ctx);
1433 cmn_err(CE_WARN, "%d: Encountered door server error %d",
1434 opcode, err);
1435 (void) smb_dr_decode_finish(dec_ctx);
1436 return (err);
1437 }
1438
1439 ASSERT(0);
1440 return (EINVAL);
1441 }
1442 #endif /* _KERNEL */