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