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
smb_kshare_door_init(int door_id)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
smb_kshare_door_fini(door_handle_t dhdl)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
smb_kshare_upcall(door_handle_t dhdl,void * arg,boolean_t add_share)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
smb_kshare_exec(smb_server_t * sv,smb_shr_execinfo_t * execinfo)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
smb_kshare_hostaccess(smb_kshare_t * shr,smb_session_t * session)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
smb_export_start(smb_server_t * sv)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
smb_export_stop(smb_server_t * sv)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
smb_kshare_g_init(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
smb_kshare_init(smb_server_t * sv)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
smb_kshare_start(smb_server_t * sv)324 smb_kshare_start(smb_server_t *sv)
325 {
326 smb_thread_init(&sv->sv_export.e_unexport_thread, "smb_thread_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
smb_kshare_stop(smb_server_t * sv)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
smb_kshare_fini(smb_server_t * sv)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
smb_kshare_g_fini(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
smb_kshare_export_list(smb_ioc_share_t * ioc)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
smb_kshare_unexport_list(smb_ioc_share_t * ioc)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
smb_kshare_info(smb_ioc_shareinfo_t * ioc)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
smb_kshare_enum(smb_server_t * sv,smb_enumshare_info_t * esi)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 *
smb_kshare_lookup(smb_server_t * sv,const char * shrname)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
smb_kshare_release(smb_server_t * sv,smb_kshare_t * shr)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
smb_kshare_export(smb_server_t * sv,smb_kshare_t * shr)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
smb_kshare_unexport(smb_server_t * sv,const char * shrname)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
smb_kshare_export_trans(smb_server_t * sv,char * name,char * path,char * cmnt)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 *
smb_kshare_decode(nvlist_t * share)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
smb_kshare_cmp(const void * p1,const void * p2)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
smb_kshare_hold(const void * p)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
smb_kshare_rele(const void * p)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
smb_kshare_destroy(void * p)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 *
smb_kshare_oemname(const char * shrname)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
smb_kshare_is_special(const char * sharename)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
smb_kshare_is_admin(const char * sharename)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
smb_kshare_decode_bool(nvlist_t * nvl,const char * propname,uint32_t flag)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
smb_kshare_csc_flags(smb_kshare_t * shr,const char * value)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
smb_kshare_unexport_thread(smb_thread_t * thread,void * arg)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
smb_export_isready(smb_server_t * sv)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
smb_kshare_chk_dsrv_status(int opcode,smb_dr_ctx_t * dec_ctx)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 */
1232