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