xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision c7abf3297398d9b13da64066f799c773ff3c0513)
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  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
22  * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
23  * Copyright 2019 RackTop Systems.
24  */
25 
26 /*
27  * SMB/CIFS share cache implementation.
28  */
29 
30 #include <errno.h>
31 #include <synch.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <syslog.h>
35 #include <thread.h>
36 #include <pthread.h>
37 #include <assert.h>
38 #include <libshare.h>
39 #include <libzfs.h>
40 #include <priv_utils.h>
41 #include <sys/types.h>
42 #include <sys/wait.h>
43 #include <unistd.h>
44 #include <pwd.h>
45 #include <signal.h>
46 #include <dirent.h>
47 #include <dlfcn.h>
48 
49 #include <smbsrv/libsmb.h>
50 #include <smbsrv/libsmbns.h>
51 #include <smbsrv/libmlsvc.h>
52 #include <smbsrv/smb_share.h>
53 #include <smbsrv/smb.h>
54 #include <mlsvc.h>
55 #include <dfs.h>
56 
57 #define	SMB_SHR_ERROR_THRESHOLD		3
58 #define	SMB_SHR_CSC_BUFSZ		64
59 
60 typedef struct smb_transient {
61 	char		*name;
62 	char		*cmnt;
63 	char		*path;
64 	char		drive;
65 	boolean_t	check;
66 } smb_transient_t;
67 
68 static smb_transient_t tshare[] = {
69 	{ "IPC$", "Remote IPC",		NULL,		'\0', B_FALSE },
70 	{ "c$",   "Default Share",	SMB_CVOL,	'C',  B_FALSE },
71 	{ "vss$", "VSS",		SMB_VSS,	'V',  B_TRUE }
72 };
73 
74 static struct {
75 	char *value;
76 	uint32_t flag;
77 } cscopt[] = {
78 	{ "disabled",	SMB_SHRF_CSC_DISABLED },
79 	{ "manual",	SMB_SHRF_CSC_MANUAL },
80 	{ "auto",	SMB_SHRF_CSC_AUTO },
81 	{ "vdo",	SMB_SHRF_CSC_VDO }
82 };
83 
84 /*
85  * Cache functions and vars
86  */
87 #define	SMB_SHR_HTAB_SZ			1024
88 
89 /*
90  * Cache handle
91  *
92  * Shares cache is a hash table.
93  *
94  * sc_cache		pointer to hash table handle
95  * sc_cache_lck		synchronize cache read/write accesses
96  * sc_state		cache state machine values
97  * sc_nops		number of inflight/pending cache operations
98  * sc_mtx		protects handle fields
99  */
100 typedef struct smb_shr_cache {
101 	HT_HANDLE	*sc_cache;
102 	rwlock_t	sc_cache_lck;
103 	mutex_t		sc_mtx;
104 	cond_t		sc_cv;
105 	uint32_t	sc_state;
106 	uint32_t	sc_nops;
107 } smb_shr_cache_t;
108 
109 /*
110  * Cache states
111  */
112 #define	SMB_SHR_CACHE_STATE_NONE	0
113 #define	SMB_SHR_CACHE_STATE_CREATED	1
114 #define	SMB_SHR_CACHE_STATE_DESTROYING	2
115 
116 /*
117  * Cache lock modes
118  */
119 #define	SMB_SHR_CACHE_RDLOCK	0
120 #define	SMB_SHR_CACHE_WRLOCK	1
121 
122 static smb_shr_cache_t smb_shr_cache;
123 
124 static uint32_t smb_shr_cache_create(void);
125 static void smb_shr_cache_destroy(void);
126 static uint32_t smb_shr_cache_lock(int);
127 static void smb_shr_cache_unlock(void);
128 static int smb_shr_cache_count(void);
129 static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
130 
131 static smb_share_t *smb_shr_cache_findent(char *);
132 static uint32_t smb_shr_cache_addent(smb_share_t *);
133 static void smb_shr_cache_delent(char *);
134 static void smb_shr_cache_freent(HT_ITEM *);
135 
136 static boolean_t smb_shr_is_empty(const char *);
137 static boolean_t smb_shr_is_dot_or_dotdot(const char *);
138 
139 /*
140  * sharemgr functions
141  */
142 static void smb_shr_sa_loadgrp(sa_group_t);
143 static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
144 static uint32_t smb_shr_sa_loadbyname(char *);
145 static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
146 
147 /*
148  * .ZFS management functions
149  */
150 static void smb_shr_zfs_add(smb_share_t *);
151 static void smb_shr_zfs_remove(smb_share_t *);
152 static void smb_shr_zfs_rename(smb_share_t *, smb_share_t *);
153 
154 /*
155  * share publishing
156  */
157 #define	SMB_SHR_PUBLISH		0
158 #define	SMB_SHR_UNPUBLISH	1
159 
160 typedef struct smb_shr_pitem {
161 	list_node_t	spi_lnd;
162 	char		spi_name[MAXNAMELEN];
163 	char		spi_container[MAXPATHLEN];
164 	char		spi_op;
165 } smb_shr_pitem_t;
166 
167 /*
168  * publish queue states
169  */
170 #define	SMB_SHR_PQS_NOQUEUE	0
171 #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
172 #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
173 #define	SMB_SHR_PQS_STOPPING	3
174 
175 /*
176  * share publishing queue
177  */
178 typedef struct smb_shr_pqueue {
179 	list_t		spq_list;
180 	mutex_t		spq_mtx;
181 	cond_t		spq_cv;
182 	uint32_t	spq_state;
183 } smb_shr_pqueue_t;
184 
185 static smb_shr_pqueue_t ad_queue;
186 
187 static int smb_shr_publisher_start(void);
188 static void smb_shr_publisher_stop(void);
189 static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
190 static void smb_shr_publisher_queue(const char *, const char *, char);
191 static void *smb_shr_publisher(void *);
192 static void smb_shr_publisher_flush(list_t *);
193 static void smb_shr_publish(const char *, const char *);
194 static void smb_shr_unpublish(const char *, const char *);
195 
196 /*
197  * Utility/helper functions
198  */
199 static uint32_t smb_shr_lookup(char *, smb_share_t *);
200 static uint32_t smb_shr_add_transient(char *, char *, char *);
201 static int smb_shr_enable_all_privs(void);
202 static int smb_shr_expand_subs(char **, smb_share_t *, smb_shr_execinfo_t *);
203 static char **smb_shr_tokenize_cmd(char *);
204 static void smb_shr_sig_abnormal_term(int);
205 static void smb_shr_sig_child(int);
206 static int smb_shr_encode(smb_share_t *, nvlist_t **);
207 
208 /*
209  * libshare handle and synchronization
210  */
211 typedef struct smb_sa_handle {
212 	sa_handle_t	sa_handle;
213 	mutex_t		sa_mtx;
214 	boolean_t	sa_in_service;
215 } smb_sa_handle_t;
216 
217 static smb_sa_handle_t smb_sa_handle;
218 
219 static char smb_shr_exec_map[MAXPATHLEN];
220 static char smb_shr_exec_unmap[MAXPATHLEN];
221 static mutex_t smb_shr_exec_mtx;
222 
223 /*
224  * Semaphore held during temporary, process-wide changes
225  * such as process privileges.  It is a seamaphore and
226  * not a mutex so a child of fork can reset it.
227  */
228 static sema_t smb_proc_sem = DEFAULTSEMA;
229 
230 /*
231  * Creates and initializes the cache and starts the publisher
232  * thread.
233  */
234 int
smb_shr_start(void)235 smb_shr_start(void)
236 {
237 	smb_transient_t	*ts;
238 	uint32_t	nerr;
239 	int		i;
240 
241 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
242 	smb_sa_handle.sa_in_service = B_TRUE;
243 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
244 
245 	if (smb_shr_cache_create() != NERR_Success)
246 		return (ENOMEM);
247 
248 	for (i = 0; i < sizeof (tshare)/sizeof (tshare[0]); ++i) {
249 		ts = &tshare[i];
250 
251 		if (ts->check && smb_shr_is_empty(ts->path))
252 			continue;
253 
254 		nerr = smb_shr_add_transient(ts->name, ts->cmnt, ts->path);
255 		if (nerr != NERR_Success)
256 			return (ENOMEM);
257 	}
258 
259 	return (smb_shr_publisher_start());
260 }
261 
262 void
smb_shr_stop(void)263 smb_shr_stop(void)
264 {
265 	smb_shr_cache_destroy();
266 	smb_shr_publisher_stop();
267 
268 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
269 	smb_sa_handle.sa_in_service = B_FALSE;
270 
271 	if (smb_sa_handle.sa_handle != NULL) {
272 		sa_fini(smb_sa_handle.sa_handle);
273 		smb_sa_handle.sa_handle = NULL;
274 	}
275 
276 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
277 }
278 
279 /*
280  * Get a handle and exclusive access to the libshare API.
281  */
282 sa_handle_t
smb_shr_sa_enter(void)283 smb_shr_sa_enter(void)
284 {
285 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
286 	if (!smb_sa_handle.sa_in_service) {
287 		(void) mutex_unlock(&smb_sa_handle.sa_mtx);
288 		return (NULL);
289 	}
290 
291 	if (smb_sa_handle.sa_handle != NULL &&
292 	    sa_needs_refresh(smb_sa_handle.sa_handle)) {
293 		sa_fini(smb_sa_handle.sa_handle);
294 		smb_sa_handle.sa_handle = NULL;
295 	}
296 
297 	if (smb_sa_handle.sa_handle == NULL) {
298 		smb_sa_handle.sa_handle = sa_init(SA_INIT_SHARE_API);
299 		if (smb_sa_handle.sa_handle == NULL) {
300 			syslog(LOG_ERR, "share: failed to get libshare handle");
301 			(void) mutex_unlock(&smb_sa_handle.sa_mtx);
302 			return (NULL);
303 		}
304 	}
305 
306 	return (smb_sa_handle.sa_handle);
307 }
308 
309 /*
310  * Release exclusive access to the libshare API.
311  */
312 void
smb_shr_sa_exit(void)313 smb_shr_sa_exit(void)
314 {
315 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
316 }
317 
318 /*
319  * Return the total number of shares
320  */
321 int
smb_shr_count(void)322 smb_shr_count(void)
323 {
324 	int n_shares = 0;
325 
326 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
327 		n_shares = smb_shr_cache_count();
328 		smb_shr_cache_unlock();
329 	}
330 
331 	return (n_shares);
332 }
333 
334 /*
335  * smb_shr_iterinit
336  *
337  * Initialize given iterator for traversing hash table.
338  */
339 void
smb_shr_iterinit(smb_shriter_t * shi)340 smb_shr_iterinit(smb_shriter_t *shi)
341 {
342 	bzero(shi, sizeof (smb_shriter_t));
343 	shi->si_first = B_TRUE;
344 }
345 
346 /*
347  * smb_shr_iterate
348  *
349  * Iterate on the shares in the hash table. The iterator must be initialized
350  * before the first iteration. On subsequent calls, the iterator must be
351  * passed unchanged.
352  *
353  * Returns NULL on failure or when all shares are visited, otherwise
354  * returns information of visited share.
355  */
356 smb_share_t *
smb_shr_iterate(smb_shriter_t * shi)357 smb_shr_iterate(smb_shriter_t *shi)
358 {
359 	smb_share_t *share = NULL;
360 	smb_share_t *cached_si;
361 
362 	if (shi == NULL)
363 		return (NULL);
364 
365 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
366 		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
367 			share = &shi->si_share;
368 			bcopy(cached_si, share, sizeof (smb_share_t));
369 		}
370 		smb_shr_cache_unlock();
371 	}
372 
373 	return (share);
374 }
375 
376 /*
377  * Adds the given share to cache, publishes the share in ADS
378  * if it has an AD container, calls kernel to take a hold on
379  * the shared file system. If it can't take a hold on the
380  * shared file system, it's either because shared directory
381  * does not exist or some other error has occurred, in any
382  * case the share is removed from the cache.
383  *
384  * If the specified share is an autohome share which already
385  * exists in the cache, just increments the reference count.
386  */
387 uint32_t
smb_shr_add(smb_share_t * si)388 smb_shr_add(smb_share_t *si)
389 {
390 	struct stat st;
391 	smb_share_t *cached_si;
392 	nvlist_t *shrlist;
393 	boolean_t created_zfs = B_FALSE;
394 	uint32_t status;
395 	int rc;
396 
397 	assert(si != NULL);
398 
399 	if (smb_name_validate_share(si->shr_name) != ERROR_SUCCESS)
400 		return (ERROR_INVALID_NAME);
401 
402 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
403 		return (NERR_InternalError);
404 
405 	cached_si = smb_shr_cache_findent(si->shr_name);
406 	if (cached_si) {
407 		if (si->shr_flags & SMB_SHRF_AUTOHOME) {
408 			cached_si->shr_refcnt++;
409 			status = NERR_Success;
410 		} else {
411 			status = NERR_DuplicateShare;
412 		}
413 		smb_shr_cache_unlock();
414 		return (status);
415 	}
416 
417 	if (STYPE_ISDSK(si->shr_type)) {
418 		/*
419 		 * If share type is STYPE_DISKTREE then the path to the
420 		 * share should exist so that we can add the share to cache.
421 		 * If path is ZFS, add the .zfs/shares/<share> entry.
422 		 *
423 		 * Both actions may require privileges that main dropped,
424 		 * so we need to temporarily make those effective.
425 		 */
426 		if (smb_proc_takesem() == 0) {
427 
428 			(void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
429 			    PRIV_FILE_DAC_READ,
430 			    PRIV_FILE_DAC_SEARCH,
431 			    PRIV_FILE_DAC_WRITE,
432 			    NULL);
433 
434 			rc = stat(si->shr_path, &st);
435 			if (rc == 0) {
436 				smb_shr_zfs_add(si);
437 				created_zfs = B_TRUE;
438 			}
439 
440 			(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
441 			    PRIV_FILE_DAC_READ,
442 			    PRIV_FILE_DAC_SEARCH,
443 			    PRIV_FILE_DAC_WRITE,
444 			    NULL);
445 			smb_proc_givesem();
446 		} else {
447 			rc = NERR_InternalError;
448 		}
449 		if (rc != 0) {
450 			smb_shr_cache_unlock();
451 			return (NERR_ItemNotFound);
452 		}
453 	}
454 
455 	if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
456 		/* This error should be impossible after findent above. */
457 		smb_shr_cache_unlock();
458 		return (status);
459 	}
460 
461 	/* don't hold the lock across door call */
462 	smb_shr_cache_unlock();
463 
464 	if ((rc = smb_shr_encode(si, &shrlist)) == 0) {
465 		/* send the share to kernel */
466 		rc = smb_kmod_share(shrlist);
467 		nvlist_free(shrlist);
468 
469 		if (rc == 0) {
470 			smb_shr_publish(si->shr_name, si->shr_container);
471 
472 			if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
473 				dfs_namespace_load(si->shr_name);
474 
475 			return (NERR_Success);
476 		}
477 	}
478 
479 	/*
480 	 * Error code path, i.e. when the kernel could not accept
481 	 * the new share for some reason.
482 	 */
483 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
484 		smb_shr_cache_delent(si->shr_name);
485 		smb_shr_cache_unlock();
486 	}
487 
488 	if (created_zfs && smb_proc_takesem() == 0) {
489 
490 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
491 		    PRIV_FILE_DAC_READ,
492 		    PRIV_FILE_DAC_SEARCH,
493 		    PRIV_FILE_DAC_WRITE,
494 		    NULL);
495 
496 		smb_shr_zfs_remove(si);
497 
498 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
499 		    PRIV_FILE_DAC_READ,
500 		    PRIV_FILE_DAC_SEARCH,
501 		    PRIV_FILE_DAC_WRITE,
502 		    NULL);
503 
504 		smb_proc_givesem();
505 	}
506 
507 	/*
508 	 * rc == ENOENT means the shared directory doesn't exist
509 	 */
510 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
511 }
512 
513 /*
514  * Removes the specified share from cache, removes it from AD
515  * if it has an AD container, and calls the kernel to release
516  * the hold on the shared file system.
517  *
518  * If this is an autohome share then decrement the reference
519  * count. If it reaches 0 then it proceeds with removing steps.
520  */
521 uint32_t
smb_shr_remove(char * sharename)522 smb_shr_remove(char *sharename)
523 {
524 	smb_share_t *si;
525 	char container[MAXPATHLEN];
526 	boolean_t dfsroot;
527 	nvlist_t *shrlist;
528 
529 	assert(sharename != NULL);
530 
531 	if (smb_name_validate_share(sharename) != ERROR_SUCCESS)
532 		return (ERROR_INVALID_NAME);
533 
534 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
535 		return (NERR_InternalError);
536 
537 	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
538 		smb_shr_cache_unlock();
539 		return (NERR_NetNameNotFound);
540 	}
541 
542 	if (STYPE_ISIPC(si->shr_type)) {
543 		/* IPC$ share cannot be removed */
544 		smb_shr_cache_unlock();
545 		return (ERROR_ACCESS_DENIED);
546 	}
547 
548 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
549 		if ((--si->shr_refcnt) > 0) {
550 			smb_shr_cache_unlock();
551 			return (NERR_Success);
552 		}
553 	}
554 
555 	/*
556 	 * If path is ZFS, remove the .zfs/shares/<share> entry.  Need
557 	 * to remove before cleanup of cache occurs.  These actions
558 	 * require temporary elevation of privileges.
559 	 */
560 	if (smb_proc_takesem() == 0) {
561 
562 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
563 		    PRIV_FILE_DAC_READ,
564 		    PRIV_FILE_DAC_SEARCH,
565 		    PRIV_FILE_DAC_WRITE,
566 		    NULL);
567 
568 		smb_shr_zfs_remove(si);
569 
570 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
571 		    PRIV_FILE_DAC_READ,
572 		    PRIV_FILE_DAC_SEARCH,
573 		    PRIV_FILE_DAC_WRITE,
574 		    NULL);
575 
576 		smb_proc_givesem();
577 	}
578 
579 	(void) smb_shr_encode(si, &shrlist);
580 
581 	(void) strlcpy(container, si->shr_container, sizeof (container));
582 	dfsroot = ((si->shr_flags & SMB_SHRF_DFSROOT) != 0);
583 	smb_shr_cache_delent(sharename);
584 	smb_shr_cache_unlock();
585 
586 	smb_shr_unpublish(sharename, container);
587 
588 	/* call kernel to release the hold on the shared file system */
589 	if (shrlist != NULL) {
590 		(void) smb_kmod_unshare(shrlist);
591 		nvlist_free(shrlist);
592 	}
593 
594 	if (dfsroot)
595 		dfs_namespace_unload(sharename);
596 
597 	return (NERR_Success);
598 }
599 
600 /*
601  * Rename a share. Check that the current name exists and the new name
602  * doesn't exist. The rename is performed by deleting the current share
603  * definition and creating a new share with the new name.
604  */
605 uint32_t
smb_shr_rename(char * from_name,char * to_name)606 smb_shr_rename(char *from_name, char *to_name)
607 {
608 	smb_share_t *from_si;
609 	smb_share_t to_si;
610 	uint32_t status;
611 	nvlist_t *shrlist;
612 
613 	assert((from_name != NULL) && (to_name != NULL));
614 
615 	if (smb_name_validate_share(from_name) != ERROR_SUCCESS ||
616 	    smb_name_validate_share(to_name) != ERROR_SUCCESS)
617 		return (ERROR_INVALID_NAME);
618 
619 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
620 		return (NERR_InternalError);
621 
622 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
623 		smb_shr_cache_unlock();
624 		return (NERR_NetNameNotFound);
625 	}
626 
627 	if (STYPE_ISIPC(from_si->shr_type)) {
628 		/* IPC$ share cannot be renamed */
629 		smb_shr_cache_unlock();
630 		return (ERROR_ACCESS_DENIED);
631 	}
632 
633 	if (smb_shr_cache_findent(to_name) != NULL) {
634 		smb_shr_cache_unlock();
635 		return (NERR_DuplicateShare);
636 	}
637 
638 	bcopy(from_si, &to_si, sizeof (smb_share_t));
639 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
640 
641 	/* If path is ZFS, rename the .zfs/shares/<share> entry. */
642 	if (smb_proc_takesem() == 0) {
643 
644 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
645 		    PRIV_FILE_DAC_READ,
646 		    PRIV_FILE_DAC_SEARCH,
647 		    PRIV_FILE_DAC_WRITE,
648 		    NULL);
649 
650 		smb_shr_zfs_rename(from_si, &to_si);
651 
652 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
653 		    PRIV_FILE_DAC_READ,
654 		    PRIV_FILE_DAC_SEARCH,
655 		    PRIV_FILE_DAC_WRITE,
656 		    NULL);
657 
658 		smb_proc_givesem();
659 	}
660 
661 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
662 		smb_shr_cache_unlock();
663 		return (status);
664 	}
665 
666 	smb_shr_cache_delent(from_name);
667 	smb_shr_cache_unlock();
668 
669 	if (smb_shr_encode(from_si, &shrlist) == 0) {
670 		(void) smb_kmod_unshare(shrlist);
671 		nvlist_free(shrlist);
672 
673 		if (smb_shr_encode(&to_si, &shrlist) == 0) {
674 			(void) smb_kmod_share(shrlist);
675 			nvlist_free(shrlist);
676 		}
677 	}
678 
679 	smb_shr_unpublish(from_name, to_si.shr_container);
680 	smb_shr_publish(to_name, to_si.shr_container);
681 
682 	return (NERR_Success);
683 }
684 
685 /*
686  * Load the information for the specified share into the supplied share
687  * info structure.
688  *
689  * First looks up the cache to see if the specified share exists, if there
690  * is a miss then it looks up sharemgr.
691  */
692 uint32_t
smb_shr_get(char * sharename,smb_share_t * si)693 smb_shr_get(char *sharename, smb_share_t *si)
694 {
695 	uint32_t status;
696 
697 	if (sharename == NULL || *sharename == '\0')
698 		return (NERR_NetNameNotFound);
699 
700 	if ((status = smb_shr_lookup(sharename, si)) == NERR_Success)
701 		return (status);
702 
703 	if ((status = smb_shr_sa_loadbyname(sharename)) == NERR_Success)
704 		status = smb_shr_lookup(sharename, si);
705 
706 	return (status);
707 }
708 
709 /*
710  * Modifies an existing share. Properties that can be modified are:
711  *
712  *   o comment
713  *   o AD container
714  *   o host access
715  *   o flags
716  */
717 uint32_t
smb_shr_modify(smb_share_t * new_si)718 smb_shr_modify(smb_share_t *new_si)
719 {
720 	smb_share_t old_si;
721 	smb_share_t *si;
722 	boolean_t adc_changed = B_FALSE;
723 	boolean_t quota_flag_changed = B_FALSE;
724 	uint32_t access, flag;
725 	nvlist_t *shrlist;
726 
727 	assert(new_si != NULL);
728 
729 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
730 		return (NERR_InternalError);
731 
732 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
733 		smb_shr_cache_unlock();
734 		return (NERR_NetNameNotFound);
735 	}
736 
737 	if (STYPE_ISIPC(si->shr_type)) {
738 		/* IPC$ share cannot be modified */
739 		smb_shr_cache_unlock();
740 		return (ERROR_ACCESS_DENIED);
741 	}
742 
743 	/*
744 	 * Keep a copy of what the share entry looks like before we
745 	 * modify it.  We need this for things like unpublishing
746 	 * from the old share container, removing the quota dir.
747 	 */
748 	bcopy(si, &old_si, sizeof (old_si));
749 
750 	/* Share comment */
751 	(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
752 
753 	/* Container */
754 	(void) strlcpy(si->shr_container, new_si->shr_container,
755 	    sizeof (si->shr_container));
756 	adc_changed = (strcmp(old_si.shr_container, si->shr_container) != 0);
757 
758 	flag = (new_si->shr_flags & SMB_SHRF_ABE);
759 	si->shr_flags &= ~SMB_SHRF_ABE;
760 	si->shr_flags |= flag;
761 
762 	flag = (new_si->shr_flags & SMB_SHRF_CATIA);
763 	si->shr_flags &= ~SMB_SHRF_CATIA;
764 	si->shr_flags |= flag;
765 
766 	flag = (new_si->shr_flags & SMB_SHRF_GUEST_OK);
767 	si->shr_flags &= ~SMB_SHRF_GUEST_OK;
768 	si->shr_flags |= flag;
769 
770 	flag = (new_si->shr_flags & SMB_SHRF_DFSROOT);
771 	si->shr_flags &= ~SMB_SHRF_DFSROOT;
772 	si->shr_flags |= flag;
773 
774 	flag = (new_si->shr_flags & SMB_SHRF_CA);
775 	si->shr_flags &= ~SMB_SHRF_CA;
776 	si->shr_flags |= flag;
777 
778 	flag = (new_si->shr_flags & SMB_SHRF_FSO);
779 	si->shr_flags &= ~SMB_SHRF_FSO;
780 	si->shr_flags |= flag;
781 
782 	flag = (new_si->shr_flags & SMB_SHRF_QUOTAS);
783 	si->shr_flags &= ~SMB_SHRF_QUOTAS;
784 	si->shr_flags |= flag;
785 	if ((old_si.shr_flags ^ si->shr_flags) & SMB_SHRF_QUOTAS)
786 		quota_flag_changed = B_TRUE;
787 
788 	flag = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
789 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
790 	si->shr_flags |= flag;
791 
792 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
793 	si->shr_flags &= ~SMB_SHRF_ACC_ALL;
794 	si->shr_flags |= access;
795 
796 	si->shr_encrypt = new_si->shr_encrypt;
797 
798 	if (access & SMB_SHRF_ACC_NONE)
799 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
800 		    sizeof (si->shr_access_none));
801 
802 	if (access & SMB_SHRF_ACC_RO)
803 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
804 		    sizeof (si->shr_access_ro));
805 
806 	if (access & SMB_SHRF_ACC_RW)
807 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
808 		    sizeof (si->shr_access_rw));
809 
810 	smb_shr_cache_unlock();
811 
812 	if (smb_shr_encode(si, &shrlist) == 0) {
813 		(void) smb_kmod_unshare(shrlist);
814 		nvlist_free(shrlist);
815 
816 		if (smb_shr_encode(new_si, &shrlist) == 0) {
817 			(void) smb_kmod_share(shrlist);
818 			nvlist_free(shrlist);
819 		}
820 	}
821 
822 	if (adc_changed) {
823 		smb_shr_unpublish(old_si.shr_name, old_si.shr_container);
824 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
825 	}
826 
827 	/* The following required privileges we dropped. */
828 	if (quota_flag_changed && smb_proc_takesem() == 0) {
829 
830 		(void) priv_set(PRIV_ON, PRIV_EFFECTIVE,
831 		    PRIV_FILE_DAC_READ,
832 		    PRIV_FILE_DAC_SEARCH,
833 		    PRIV_FILE_DAC_WRITE,
834 		    NULL);
835 
836 		smb_shr_zfs_remove(&old_si);
837 		smb_shr_zfs_add(si);
838 
839 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE,
840 		    PRIV_FILE_DAC_READ,
841 		    PRIV_FILE_DAC_SEARCH,
842 		    PRIV_FILE_DAC_WRITE,
843 		    NULL);
844 
845 		smb_proc_givesem();
846 	}
847 
848 	return (NERR_Success);
849 }
850 
851 /*
852  * smb_shr_exists
853  *
854  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
855  */
856 boolean_t
smb_shr_exists(char * sharename)857 smb_shr_exists(char *sharename)
858 {
859 	boolean_t exists = B_FALSE;
860 
861 	if (sharename == NULL || *sharename == '\0')
862 		return (B_FALSE);
863 
864 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
865 		exists = (smb_shr_cache_findent(sharename) != NULL);
866 		smb_shr_cache_unlock();
867 	}
868 
869 	return (exists);
870 }
871 
872 /*
873  * If the shared directory does not begin with a /, one will be
874  * inserted as a prefix. If ipaddr is not zero, then also return
875  * information about access based on the host level access lists, if
876  * present. Also return access check if there is an IP address and
877  * shr_accflags.
878  *
879  * The value of smb_chk_hostaccess is checked for an access match.
880  * -1 is wildcard match
881  * 0 is no match
882  * 1 is match
883  *
884  * Precedence is none is checked first followed by ro then rw if
885  * needed.  If x is wildcard (< 0) then check to see if the other
886  * values are a match. If a match, that wins.
887  */
888 uint32_t
smb_shr_hostaccess(smb_inaddr_t * ipaddr,char * none_list,char * ro_list,char * rw_list,uint32_t flag)889 smb_shr_hostaccess(smb_inaddr_t *ipaddr, char *none_list, char *ro_list,
890     char *rw_list, uint32_t flag)
891 {
892 	uint32_t acc = SMB_SHRF_ACC_NONE;
893 	int none = 0;
894 	int ro = 0;
895 	int rw = 0;
896 
897 	if (!smb_inet_iszero(ipaddr)) {
898 		if ((flag & SMB_SHRF_ACC_NONE) != 0)
899 			none = smb_chk_hostaccess(ipaddr, none_list);
900 		if ((flag & SMB_SHRF_ACC_RO) != 0)
901 			ro = smb_chk_hostaccess(ipaddr, ro_list);
902 		if ((flag & SMB_SHRF_ACC_RW) != 0)
903 			rw = smb_chk_hostaccess(ipaddr, rw_list);
904 
905 		/* make first pass to get basic value */
906 		if (none != 0)
907 			acc = SMB_SHRF_ACC_NONE;
908 		else if (ro != 0)
909 			acc = SMB_SHRF_ACC_RO;
910 		else if (rw != 0)
911 			acc = SMB_SHRF_ACC_RW;
912 
913 		/* make second pass to handle '*' case */
914 		if (none < 0) {
915 			acc = SMB_SHRF_ACC_NONE;
916 			if (ro > 0)
917 				acc = SMB_SHRF_ACC_RO;
918 			else if (rw > 0)
919 				acc = SMB_SHRF_ACC_RW;
920 		} else if (ro < 0) {
921 			acc = SMB_SHRF_ACC_RO;
922 			if (none > 0)
923 				acc = SMB_SHRF_ACC_NONE;
924 			else if (rw > 0)
925 				acc = SMB_SHRF_ACC_RW;
926 		} else if (rw < 0) {
927 			acc = SMB_SHRF_ACC_RW;
928 			if (none > 0)
929 				acc = SMB_SHRF_ACC_NONE;
930 			else if (ro > 0)
931 				acc = SMB_SHRF_ACC_RO;
932 		}
933 	}
934 
935 	return (acc);
936 }
937 
938 /*
939  * smb_shr_is_special
940  *
941  * Special share reserved for interprocess communication (IPC$) or
942  * remote administration of the server (ADMIN$). Can also refer to
943  * administrative shares such as C$, D$, E$, and so forth.
944  */
945 int
smb_shr_is_special(char * sharename)946 smb_shr_is_special(char *sharename)
947 {
948 	int len;
949 
950 	if (sharename == NULL)
951 		return (0);
952 
953 	if ((len = strlen(sharename)) == 0)
954 		return (0);
955 
956 	if (sharename[len - 1] == '$')
957 		return (STYPE_SPECIAL);
958 
959 	return (0);
960 }
961 
962 /*
963  * smb_shr_is_restricted
964  *
965  * Check whether or not there is a restriction on a share. Restricted
966  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
967  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
968  * if the share is restricted. Otherwise B_FALSE is returned to indicate
969  * that there are no restrictions.
970  */
971 boolean_t
smb_shr_is_restricted(char * sharename)972 smb_shr_is_restricted(char *sharename)
973 {
974 	static char *restricted[] = {
975 		"IPC$"
976 	};
977 
978 	int i;
979 
980 	if (sharename == NULL)
981 		return (B_FALSE);
982 
983 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
984 		if (smb_strcasecmp(restricted[i], sharename, 0) == 0)
985 			return (B_TRUE);
986 	}
987 
988 	return (smb_shr_is_admin(sharename));
989 }
990 
991 /*
992  * smb_shr_is_admin
993  *
994  * Check whether or not access to the share should be restricted to
995  * administrators. This is a bit of a hack because what we're doing
996  * is checking for the default admin shares: C$, D$ etc.. There are
997  * other shares that have restrictions: see smb_shr_is_restricted().
998  *
999  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
1000  * is returned to indicate that there are no restrictions.
1001  */
1002 boolean_t
smb_shr_is_admin(char * sharename)1003 smb_shr_is_admin(char *sharename)
1004 {
1005 	if (sharename == NULL)
1006 		return (B_FALSE);
1007 
1008 	if (strlen(sharename) == 2 &&
1009 	    smb_isalpha(sharename[0]) && sharename[1] == '$') {
1010 		return (B_TRUE);
1011 	}
1012 
1013 	return (B_FALSE);
1014 }
1015 
1016 char
smb_shr_drive_letter(const char * path)1017 smb_shr_drive_letter(const char *path)
1018 {
1019 	smb_transient_t	*ts;
1020 	int i;
1021 
1022 	if (path == NULL)
1023 		return ('\0');
1024 
1025 	for (i = 0; i < sizeof (tshare)/sizeof (tshare[0]); ++i) {
1026 		ts = &tshare[i];
1027 
1028 		if (ts->path == NULL)
1029 			continue;
1030 
1031 		if (strcasecmp(ts->path, path) == 0)
1032 			return (ts->drive);
1033 	}
1034 
1035 	return ('\0');
1036 }
1037 
1038 /*
1039  * Returns true if the specified directory is empty,
1040  * otherwise returns false.
1041  */
1042 static boolean_t
smb_shr_is_empty(const char * path)1043 smb_shr_is_empty(const char *path)
1044 {
1045 	DIR *dirp;
1046 	struct dirent *dp;
1047 
1048 	if (path == NULL)
1049 		return (B_TRUE);
1050 
1051 	if ((dirp = opendir(path)) == NULL)
1052 		return (B_TRUE);
1053 
1054 	while ((dp = readdir(dirp)) != NULL) {
1055 		if (!smb_shr_is_dot_or_dotdot(dp->d_name))
1056 			return (B_FALSE);
1057 	}
1058 
1059 	(void) closedir(dirp);
1060 	return (B_TRUE);
1061 }
1062 
1063 /*
1064  * Returns true if name is "." or "..", otherwise returns false.
1065  */
1066 static boolean_t
smb_shr_is_dot_or_dotdot(const char * name)1067 smb_shr_is_dot_or_dotdot(const char *name)
1068 {
1069 	if (*name != '.')
1070 		return (B_FALSE);
1071 
1072 	if ((name[1] == '\0') || (name[1] == '.' && name[2] == '\0'))
1073 		return (B_TRUE);
1074 
1075 	return (B_FALSE);
1076 }
1077 
1078 /*
1079  * smb_shr_get_realpath
1080  *
1081  * Derive the real path for a share from the path provided by a client.
1082  * For instance, the real path of C:\ may be /cvol or the real path of
1083  * F:\home may be /vol1/home.
1084  *
1085  * clntpath - path provided by the Windows client is in the
1086  *            format of <drive letter>:\<dir>
1087  * realpath - path that will be stored as the directory field of
1088  *            the smb_share_t structure of the share.
1089  * maxlen   - maximum length of the realpath buffer
1090  *
1091  * Return LAN Manager network error code.
1092  */
1093 uint32_t
smb_shr_get_realpath(const char * clntpath,char * realpath,int maxlen)1094 smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
1095 {
1096 	const char *p;
1097 	int len;
1098 
1099 	if ((p = strchr(clntpath, ':')) != NULL)
1100 		++p;
1101 	else
1102 		p = clntpath;
1103 
1104 	(void) strlcpy(realpath, p, maxlen);
1105 	(void) strcanon(realpath, "/\\");
1106 	(void) strsubst(realpath, '\\', '/');
1107 
1108 	len = strlen(realpath);
1109 	if ((len > 1) && (realpath[len - 1] == '/'))
1110 		realpath[len - 1] = '\0';
1111 
1112 	return (NERR_Success);
1113 }
1114 
1115 void
smb_shr_list(int offset,smb_shrlist_t * list)1116 smb_shr_list(int offset, smb_shrlist_t *list)
1117 {
1118 	smb_shriter_t iterator;
1119 	smb_share_t *si;
1120 	int n = 0;
1121 
1122 	bzero(list, sizeof (smb_shrlist_t));
1123 	smb_shr_iterinit(&iterator);
1124 
1125 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
1126 		if (--offset > 0)
1127 			continue;
1128 
1129 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
1130 		    (!STYPE_ISIPC(si->shr_type))) {
1131 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
1132 			if (++n == LMSHARES_PER_REQUEST)
1133 				break;
1134 		}
1135 	}
1136 
1137 	list->sl_cnt = n;
1138 }
1139 
1140 /*
1141  * Executes the map/unmap command associated with a share.
1142  *
1143  * Returns 0 on success.  Otherwise non-zero for errors.
1144  */
1145 int
smb_shr_exec(smb_shr_execinfo_t * subs)1146 smb_shr_exec(smb_shr_execinfo_t *subs)
1147 {
1148 	char cmd[MAXPATHLEN], **cmd_tokens, *path, *ptr;
1149 	pid_t child_pid;
1150 	int child_status;
1151 	struct sigaction pact, cact;
1152 	smb_share_t si;
1153 
1154 	if (smb_shr_get(subs->e_sharename, &si) != 0)
1155 		return (-1);
1156 
1157 	*cmd = '\0';
1158 
1159 	(void) mutex_lock(&smb_shr_exec_mtx);
1160 
1161 	switch (subs->e_type) {
1162 	case SMB_EXEC_MAP:
1163 		(void) strlcpy(cmd, smb_shr_exec_map, sizeof (cmd));
1164 		break;
1165 	case SMB_EXEC_UNMAP:
1166 		(void) strlcpy(cmd, smb_shr_exec_unmap, sizeof (cmd));
1167 		break;
1168 	default:
1169 		(void) mutex_unlock(&smb_shr_exec_mtx);
1170 		return (-1);
1171 	}
1172 
1173 	(void) mutex_unlock(&smb_shr_exec_mtx);
1174 
1175 	if (*cmd == '\0')
1176 		return (0);
1177 
1178 	if (smb_proc_takesem() != 0)
1179 		return (-1);
1180 
1181 	pact.sa_handler = smb_shr_sig_child;
1182 	pact.sa_flags = 0;
1183 	(void) sigemptyset(&pact.sa_mask);
1184 	sigaction(SIGCHLD, &pact, NULL);
1185 
1186 	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
1187 
1188 	if ((child_pid = fork()) == -1) {
1189 		(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
1190 		smb_proc_givesem();
1191 		return (-1);
1192 	}
1193 
1194 	if (child_pid == 0) {
1195 
1196 		/* child process */
1197 
1198 		cact.sa_handler = smb_shr_sig_abnormal_term;
1199 		cact.sa_flags = 0;
1200 		(void) sigemptyset(&cact.sa_mask);
1201 		sigaction(SIGTERM, &cact, NULL);
1202 		sigaction(SIGABRT, &cact, NULL);
1203 		sigaction(SIGSEGV, &cact, NULL);
1204 
1205 		if (priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_PROC_EXEC,
1206 		    PRIV_FILE_DAC_EXECUTE, NULL))
1207 			_exit(-1);
1208 
1209 		if (smb_shr_enable_all_privs())
1210 			_exit(-1);
1211 
1212 		smb_proc_initsem();
1213 
1214 		(void) trim_whitespace(cmd);
1215 		(void) strcanon(cmd, " ");
1216 
1217 		if ((cmd_tokens = smb_shr_tokenize_cmd(cmd)) != NULL) {
1218 
1219 			if (smb_shr_expand_subs(cmd_tokens, &si, subs) != 0) {
1220 				free(cmd_tokens[0]);
1221 				free(cmd_tokens);
1222 				_exit(-1);
1223 			}
1224 
1225 			ptr = cmd;
1226 			path = strsep(&ptr, " ");
1227 
1228 			(void) execv(path, cmd_tokens);
1229 		}
1230 
1231 		_exit(-1);
1232 	}
1233 
1234 	(void) priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_PROC_FORK, NULL);
1235 	smb_proc_givesem();
1236 
1237 	/* parent process */
1238 
1239 	while (waitpid(child_pid, &child_status, 0) < 0) {
1240 		if (errno != EINTR)
1241 			break;
1242 
1243 		/* continue if waitpid got interrupted by a signal */
1244 		errno = 0;
1245 		continue;
1246 	}
1247 
1248 	if (WIFEXITED(child_status))
1249 		return (WEXITSTATUS(child_status));
1250 
1251 	return (child_status);
1252 }
1253 
1254 /*
1255  * Locking for process-wide settings (i.e. privileges)
1256  */
1257 void
smb_proc_initsem(void)1258 smb_proc_initsem(void)
1259 {
1260 	(void) sema_init(&smb_proc_sem, 1, USYNC_THREAD, NULL);
1261 }
1262 
1263 int
smb_proc_takesem(void)1264 smb_proc_takesem(void)
1265 {
1266 	return (sema_wait(&smb_proc_sem));
1267 }
1268 
1269 void
smb_proc_givesem(void)1270 smb_proc_givesem(void)
1271 {
1272 	(void) sema_post(&smb_proc_sem);
1273 }
1274 
1275 /*
1276  * ============================================
1277  * Private helper/utility functions
1278  * ============================================
1279  */
1280 
1281 /*
1282  * Looks up the given share in the cache and return
1283  * the info in 'si'
1284  */
1285 static uint32_t
smb_shr_lookup(char * sharename,smb_share_t * si)1286 smb_shr_lookup(char *sharename, smb_share_t *si)
1287 {
1288 	smb_share_t *cached_si;
1289 	uint32_t status = NERR_NetNameNotFound;
1290 
1291 	if (sharename == NULL || *sharename == '\0')
1292 		return (NERR_NetNameNotFound);
1293 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
1294 		cached_si = smb_shr_cache_findent(sharename);
1295 		if (cached_si != NULL) {
1296 			bcopy(cached_si, si, sizeof (smb_share_t));
1297 			status = NERR_Success;
1298 		}
1299 
1300 		smb_shr_cache_unlock();
1301 	}
1302 	return (status);
1303 }
1304 
1305 /*
1306  * Add IPC$ or Admin shares to the cache upon startup.
1307  */
1308 static uint32_t
smb_shr_add_transient(char * name,char * cmnt,char * path)1309 smb_shr_add_transient(char *name, char *cmnt, char *path)
1310 {
1311 	smb_share_t trans;
1312 	uint32_t status = NERR_InternalError;
1313 
1314 	if (name == NULL)
1315 		return (status);
1316 
1317 	bzero(&trans, sizeof (smb_share_t));
1318 	(void) strlcpy(trans.shr_name, name, MAXNAMELEN);
1319 	if (cmnt)
1320 		(void) strlcpy(trans.shr_cmnt, cmnt, SMB_SHARE_CMNT_MAX);
1321 
1322 	if (path)
1323 		(void) strlcpy(trans.shr_path, path, MAXPATHLEN);
1324 
1325 	if (strcasecmp(name, "IPC$") == 0)
1326 		trans.shr_type = STYPE_IPC;
1327 
1328 	trans.shr_flags = SMB_SHRF_TRANS;
1329 
1330 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
1331 		status = smb_shr_cache_addent(&trans);
1332 		smb_shr_cache_unlock();
1333 	}
1334 
1335 	return (status);
1336 }
1337 
1338 /*
1339  * ============================================
1340  * Cache management functions
1341  *
1342  * All cache functions are private
1343  * ============================================
1344  */
1345 
1346 /*
1347  * Create the share cache (hash table).
1348  */
1349 static uint32_t
smb_shr_cache_create(void)1350 smb_shr_cache_create(void)
1351 {
1352 	uint32_t status = NERR_Success;
1353 
1354 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
1355 	switch (smb_shr_cache.sc_state) {
1356 	case SMB_SHR_CACHE_STATE_NONE:
1357 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
1358 		    MAXNAMELEN, 0);
1359 		if (smb_shr_cache.sc_cache == NULL) {
1360 			status = NERR_InternalError;
1361 			break;
1362 		}
1363 
1364 		(void) ht_set_cmpfn(smb_shr_cache.sc_cache,
1365 		    (HT_CMP)smb_strcasecmp);
1366 		(void) ht_register_callback(smb_shr_cache.sc_cache,
1367 		    smb_shr_cache_freent);
1368 		smb_shr_cache.sc_nops = 0;
1369 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
1370 		break;
1371 
1372 	default:
1373 		assert(0);
1374 		status = NERR_InternalError;
1375 		break;
1376 	}
1377 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1378 
1379 	return (status);
1380 }
1381 
1382 /*
1383  * Destroy the share cache (hash table).
1384  * Wait for inflight/pending operations to finish or abort before
1385  * destroying the cache.
1386  */
1387 static void
smb_shr_cache_destroy(void)1388 smb_shr_cache_destroy(void)
1389 {
1390 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
1391 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
1392 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
1393 		while (smb_shr_cache.sc_nops > 0)
1394 			(void) cond_wait(&smb_shr_cache.sc_cv,
1395 			    &smb_shr_cache.sc_mtx);
1396 
1397 		smb_shr_cache.sc_cache = NULL;
1398 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
1399 	}
1400 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1401 }
1402 
1403 /*
1404  * If the cache is in "created" state, lock the cache for read
1405  * or read/write based on the specified mode.
1406  *
1407  * Whenever a lock is granted, the number of inflight cache
1408  * operations is incremented.
1409  */
1410 static uint32_t
smb_shr_cache_lock(int mode)1411 smb_shr_cache_lock(int mode)
1412 {
1413 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
1414 	if (smb_shr_cache.sc_state != SMB_SHR_CACHE_STATE_CREATED) {
1415 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1416 		return (NERR_InternalError);
1417 	}
1418 	smb_shr_cache.sc_nops++;
1419 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1420 
1421 	/*
1422 	 * Lock has to be taken outside the mutex otherwise
1423 	 * there could be a deadlock
1424 	 */
1425 	if (mode == SMB_SHR_CACHE_RDLOCK)
1426 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
1427 	else
1428 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
1429 
1430 	return (NERR_Success);
1431 }
1432 
1433 /*
1434  * Decrement the number of inflight operations and then unlock.
1435  */
1436 static void
smb_shr_cache_unlock(void)1437 smb_shr_cache_unlock(void)
1438 {
1439 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
1440 	assert(smb_shr_cache.sc_nops > 0);
1441 	smb_shr_cache.sc_nops--;
1442 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
1443 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1444 
1445 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
1446 }
1447 
1448 /*
1449  * Return the total number of shares
1450  */
1451 static int
smb_shr_cache_count(void)1452 smb_shr_cache_count(void)
1453 {
1454 	return (ht_get_total_items(smb_shr_cache.sc_cache));
1455 }
1456 
1457 /*
1458  * looks up the given share name in the cache and if it
1459  * finds a match returns a pointer to the cached entry.
1460  * Note that since a pointer is returned this function
1461  * MUST be protected by smb_shr_cache_lock/unlock pair
1462  */
1463 static smb_share_t *
smb_shr_cache_findent(char * sharename)1464 smb_shr_cache_findent(char *sharename)
1465 {
1466 	HT_ITEM *item;
1467 
1468 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
1469 	if (item && item->hi_data)
1470 		return ((smb_share_t *)item->hi_data);
1471 
1472 	return (NULL);
1473 }
1474 
1475 /*
1476  * Return a pointer to the first/next entry in
1477  * the cache based on the given iterator.
1478  *
1479  * Calls to this function MUST be protected by
1480  * smb_shr_cache_lock/unlock.
1481  */
1482 static smb_share_t *
smb_shr_cache_iterate(smb_shriter_t * shi)1483 smb_shr_cache_iterate(smb_shriter_t *shi)
1484 {
1485 	HT_ITEM *item;
1486 
1487 	if (shi->si_first) {
1488 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
1489 		shi->si_first = B_FALSE;
1490 	} else {
1491 		item = ht_findnext(&shi->si_hashiter);
1492 	}
1493 
1494 	if (item && item->hi_data)
1495 		return ((smb_share_t *)item->hi_data);
1496 
1497 	return (NULL);
1498 }
1499 
1500 /*
1501  * Add the specified share to the cache.  Memory needs to be allocated
1502  * for the cache entry and the passed information is copied to the
1503  * allocated space.
1504  *
1505  * Note: This modifies *si (an intentional side-effect), adding bits
1506  * to shr_type and shr_flags, which the caller expects, eg. so that
1507  * smb_shr_add() and smb_shr_rename() use the updated smb_share_t
1508  * when they call smb_kmod_share().
1509  */
1510 static uint32_t
smb_shr_cache_addent(smb_share_t * si)1511 smb_shr_cache_addent(smb_share_t *si)
1512 {
1513 	smb_share_t *cache_ent;
1514 	uint32_t status = NERR_Success;
1515 
1516 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
1517 		return (ERROR_NOT_ENOUGH_MEMORY);
1518 
1519 	si->shr_type |= smb_shr_is_special(si->shr_name);
1520 
1521 	if (smb_shr_is_admin(si->shr_name))
1522 		si->shr_flags |= SMB_SHRF_ADMIN;
1523 
1524 	bcopy(si, cache_ent, sizeof (smb_share_t));
1525 
1526 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
1527 		cache_ent->shr_refcnt = 1;
1528 
1529 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
1530 	    == NULL) {
1531 		syslog(LOG_DEBUG, "share: %s: cache update failed",
1532 		    cache_ent->shr_name);
1533 		free(cache_ent);
1534 		status = NERR_InternalError;
1535 	}
1536 
1537 	return (status);
1538 }
1539 
1540 /*
1541  * Delete the specified share from the cache.
1542  */
1543 static void
smb_shr_cache_delent(char * sharename)1544 smb_shr_cache_delent(char *sharename)
1545 {
1546 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
1547 }
1548 
1549 /*
1550  * Call back to free the given cache entry.
1551  */
1552 static void
smb_shr_cache_freent(HT_ITEM * item)1553 smb_shr_cache_freent(HT_ITEM *item)
1554 {
1555 	if (item && item->hi_data)
1556 		free(item->hi_data);
1557 }
1558 
1559 /*
1560  * ============================================
1561  * Interfaces to sharemgr
1562  *
1563  * All functions in this section are private
1564  * ============================================
1565  */
1566 
1567 /*
1568  * Loads the SMB shares, from sharemgr, then:
1569  *     - calls smb_shr_add which:
1570  *         - adds the share into the share cache
1571  *         - adds the share into in-kernel kshare table
1572  *         - publishes the share in ADS
1573  *     - updates the share list in sharefs/sharetab
1574  */
1575 /*ARGSUSED*/
1576 void *
smb_shr_load(void * args)1577 smb_shr_load(void *args)
1578 {
1579 	sa_handle_t handle;
1580 	sa_group_t group, subgroup;
1581 	char *gstate;
1582 	boolean_t gdisabled;
1583 
1584 	smb_shr_load_execinfo();
1585 
1586 	if ((handle = smb_shr_sa_enter()) == NULL) {
1587 		syslog(LOG_ERR, "smb_shr_load: load failed");
1588 		return (NULL);
1589 	}
1590 
1591 	for (group = sa_get_group(handle, NULL);
1592 	    group != NULL; group = sa_get_next_group(group)) {
1593 		gstate = sa_get_group_attr(group, "state");
1594 		if (gstate == NULL)
1595 			continue;
1596 
1597 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
1598 		sa_free_attr_string(gstate);
1599 		if (gdisabled)
1600 			continue;
1601 
1602 		smb_shr_sa_loadgrp(group);
1603 
1604 		for (subgroup = sa_get_sub_group(group);
1605 		    subgroup != NULL;
1606 		    subgroup = sa_get_next_group(subgroup)) {
1607 			smb_shr_sa_loadgrp(subgroup);
1608 		}
1609 
1610 	}
1611 	smb_shr_sa_exit();
1612 	return (NULL);
1613 }
1614 
1615 void
smb_shr_load_execinfo()1616 smb_shr_load_execinfo()
1617 {
1618 	(void) mutex_lock(&smb_shr_exec_mtx);
1619 	(void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
1620 	    MAXPATHLEN);
1621 	(void) mutex_unlock(&smb_shr_exec_mtx);
1622 }
1623 
1624 /*
1625  * Handles disabling shares in sharefs when stoping smbd
1626  */
1627 void
smb_shr_unload()1628 smb_shr_unload()
1629 {
1630 	smb_shriter_t iterator;
1631 	smb_share_t *si;
1632 	sa_handle_t handle;
1633 	int rc;
1634 
1635 	if ((handle = smb_shr_sa_enter()) == NULL) {
1636 		syslog(LOG_ERR, "smb_shr_unload: failed");
1637 		return;
1638 	}
1639 
1640 	smb_shr_iterinit(&iterator);
1641 
1642 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
1643 
1644 		/* Skip transient shares, IPC$, ... */
1645 		if ((si->shr_flags & SMB_SHRF_TRANS) ||
1646 		    STYPE_ISIPC(si->shr_type))
1647 			continue;
1648 
1649 		rc = sa_delete_sharetab(handle, si->shr_path, "smb");
1650 		if (rc) {
1651 			syslog(LOG_ERR,
1652 			    "sharefs remove %s failed, rc=%d, err=%d",
1653 			    si->shr_path, rc, errno);
1654 		}
1655 	}
1656 	smb_shr_sa_exit();
1657 }
1658 
1659 /*
1660  * Load the shares contained in the specified group.
1661  *
1662  * Don't process groups on which the smb protocol is disabled.
1663  * The top level ZFS group won't have the smb protocol enabled
1664  * but sub-groups will.
1665  *
1666  * We will tolerate a limited number of errors and then give
1667  * up on the current group.  A typical error might be that the
1668  * shared directory no longer exists.
1669  */
1670 static void
smb_shr_sa_loadgrp(sa_group_t group)1671 smb_shr_sa_loadgrp(sa_group_t group)
1672 {
1673 	sa_share_t share;
1674 	sa_resource_t resource;
1675 	int error_count = 0;
1676 
1677 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
1678 		return;
1679 
1680 	for (share = sa_get_share(group, NULL);
1681 	    share != NULL;
1682 	    share = sa_get_next_share(share)) {
1683 		for (resource = sa_get_share_resource(share, NULL);
1684 		    resource != NULL;
1685 		    resource = sa_get_next_resource(resource)) {
1686 			if (smb_shr_sa_load(share, resource))
1687 				++error_count;
1688 
1689 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
1690 				break;
1691 		}
1692 
1693 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
1694 			break;
1695 	}
1696 }
1697 
1698 /*
1699  * Load a share definition from sharemgr and add it to the cache.
1700  * If the share is already in the cache then it doesn't do anything.
1701  *
1702  * This function does not report duplicate shares as error since
1703  * a share might have been added by smb_shr_get() while load is
1704  * in progress.
1705  */
1706 static uint32_t
smb_shr_sa_load(sa_share_t share,sa_resource_t resource)1707 smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
1708 {
1709 	smb_share_t si;
1710 	char *sharename;
1711 	uint32_t status;
1712 	boolean_t loaded;
1713 	int rc;
1714 
1715 	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
1716 		return (NERR_InternalError);
1717 
1718 	loaded = smb_shr_exists(sharename);
1719 	sa_free_attr_string(sharename);
1720 
1721 	if (loaded)
1722 		return (NERR_Success);
1723 
1724 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
1725 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
1726 		    si.shr_name, status);
1727 		return (status);
1728 	}
1729 
1730 	status = smb_shr_add(&si);
1731 	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
1732 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
1733 		    si.shr_name, status);
1734 		return (status);
1735 	}
1736 
1737 	rc = sa_update_sharetab(share, "smb");
1738 	if (rc) {
1739 		syslog(LOG_ERR, "sharefs add %s failed, rc=%d, err=%d",
1740 		    sharename, rc, errno);
1741 	}
1742 
1743 	return (NERR_Success);
1744 }
1745 
1746 static char *
smb_shr_sa_getprop(sa_optionset_t opts,char * propname)1747 smb_shr_sa_getprop(sa_optionset_t opts, char *propname)
1748 {
1749 	sa_property_t prop;
1750 	char *val = NULL;
1751 
1752 	prop = sa_get_property(opts, propname);
1753 	if (prop != NULL)
1754 		val = sa_get_property_attr(prop, "value");
1755 
1756 	return (val);
1757 }
1758 
1759 /*
1760  * Read the specified share information from sharemgr and return
1761  * it in the given smb_share_t structure.
1762  *
1763  * Shares read from sharemgr are marked as permanent/persistent.
1764  */
1765 static uint32_t
smb_shr_sa_get(sa_share_t share,sa_resource_t resource,smb_share_t * si)1766 smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
1767 {
1768 	sa_optionset_t opts;
1769 	char *val = NULL;
1770 	char *path;
1771 	char *rname;
1772 
1773 	if ((path = sa_get_share_attr(share, "path")) == NULL)
1774 		return (NERR_InternalError);
1775 
1776 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
1777 		sa_free_attr_string(path);
1778 		return (NERR_InternalError);
1779 	}
1780 
1781 	bzero(si, sizeof (smb_share_t));
1782 	si->shr_flags = SMB_SHRF_PERM;
1783 
1784 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
1785 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
1786 	sa_free_attr_string(path);
1787 	sa_free_attr_string(rname);
1788 
1789 	val = sa_get_resource_description(resource);
1790 	if (val == NULL)
1791 		val = sa_get_share_description(share);
1792 
1793 	if (val != NULL) {
1794 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
1795 		sa_free_share_description(val);
1796 	}
1797 
1798 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
1799 	if (opts == NULL)
1800 		return (NERR_Success);
1801 
1802 	val = smb_shr_sa_getprop(opts, SHOPT_AD_CONTAINER);
1803 	if (val != NULL) {
1804 		(void) strlcpy(si->shr_container, val,
1805 		    sizeof (si->shr_container));
1806 		free(val);
1807 	}
1808 
1809 	val = smb_shr_sa_getprop(opts, SHOPT_CATIA);
1810 	if (val != NULL) {
1811 		smb_shr_sa_setflag(val, si, SMB_SHRF_CATIA);
1812 		free(val);
1813 	}
1814 
1815 	val = smb_shr_sa_getprop(opts, SHOPT_ABE);
1816 	if (val != NULL) {
1817 		smb_shr_sa_setflag(val, si, SMB_SHRF_ABE);
1818 		free(val);
1819 	}
1820 
1821 	val = smb_shr_sa_getprop(opts, SHOPT_GUEST);
1822 	if (val != NULL) {
1823 		smb_shr_sa_setflag(val, si, SMB_SHRF_GUEST_OK);
1824 		free(val);
1825 	}
1826 
1827 	val = smb_shr_sa_getprop(opts, SHOPT_DFSROOT);
1828 	if (val != NULL) {
1829 		smb_shr_sa_setflag(val, si, SMB_SHRF_DFSROOT);
1830 		free(val);
1831 	}
1832 
1833 	val = smb_shr_sa_getprop(opts, SHOPT_CA);
1834 	if (val != NULL) {
1835 		smb_shr_sa_setflag(val, si, SMB_SHRF_CA);
1836 		free(val);
1837 	}
1838 
1839 	val = smb_shr_sa_getprop(opts, SHOPT_FSO);
1840 	if (val != NULL) {
1841 		smb_shr_sa_setflag(val, si, SMB_SHRF_FSO);
1842 		free(val);
1843 	}
1844 
1845 	val = smb_shr_sa_getprop(opts, SHOPT_QUOTAS);
1846 	if (val != NULL) {
1847 		/* Turn the flag on or off */
1848 		smb_shr_sa_setflag(val, si, SMB_SHRF_QUOTAS);
1849 		free(val);
1850 	} else {
1851 		/* Default for this is enabled. */
1852 		si->shr_flags |= SMB_SHRF_QUOTAS;
1853 	}
1854 
1855 	val = smb_shr_sa_getprop(opts, SHOPT_ENCRYPT);
1856 	if (val != NULL) {
1857 		smb_cfg_set_require(val, &si->shr_encrypt);
1858 		free(val);
1859 	}
1860 
1861 	val = smb_shr_sa_getprop(opts, SHOPT_CSC);
1862 	if (val != NULL) {
1863 		smb_shr_sa_csc_option(val, si);
1864 		free(val);
1865 	}
1866 
1867 	val = smb_shr_sa_getprop(opts, SHOPT_NONE);
1868 	if (val != NULL) {
1869 		(void) strlcpy(si->shr_access_none, val,
1870 		    sizeof (si->shr_access_none));
1871 		free(val);
1872 		si->shr_flags |= SMB_SHRF_ACC_NONE;
1873 	}
1874 
1875 	val = smb_shr_sa_getprop(opts, SHOPT_RO);
1876 	if (val != NULL) {
1877 		(void) strlcpy(si->shr_access_ro, val,
1878 		    sizeof (si->shr_access_ro));
1879 		free(val);
1880 		si->shr_flags |= SMB_SHRF_ACC_RO;
1881 	}
1882 
1883 	val = smb_shr_sa_getprop(opts, SHOPT_RW);
1884 	if (val != NULL) {
1885 		(void) strlcpy(si->shr_access_rw, val,
1886 		    sizeof (si->shr_access_rw));
1887 		free(val);
1888 		si->shr_flags |= SMB_SHRF_ACC_RW;
1889 	}
1890 
1891 	sa_free_derived_optionset(opts);
1892 	return (NERR_Success);
1893 }
1894 
1895 /*
1896  * Map a client-side caching (CSC) option to the appropriate share
1897  * flag.  Only one option is allowed; an error will be logged if
1898  * multiple options have been specified.  We don't need to do anything
1899  * about multiple values here because the SRVSVC will not recognize
1900  * a value containing multiple flags and will return the default value.
1901  *
1902  * If the option value is not recognized, it will be ignored: invalid
1903  * values will typically be caught and rejected by sharemgr.
1904  */
1905 void
smb_shr_sa_csc_option(const char * value,smb_share_t * si)1906 smb_shr_sa_csc_option(const char *value, smb_share_t *si)
1907 {
1908 	int i;
1909 
1910 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1911 		if (strcasecmp(value, cscopt[i].value) == 0) {
1912 			si->shr_flags |= cscopt[i].flag;
1913 			break;
1914 		}
1915 	}
1916 
1917 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
1918 	case 0:
1919 	case SMB_SHRF_CSC_DISABLED:
1920 	case SMB_SHRF_CSC_MANUAL:
1921 	case SMB_SHRF_CSC_AUTO:
1922 	case SMB_SHRF_CSC_VDO:
1923 		break;
1924 
1925 	default:
1926 		syslog(LOG_INFO, "csc option conflict: 0x%08x",
1927 		    si->shr_flags & SMB_SHRF_CSC_MASK);
1928 		break;
1929 	}
1930 }
1931 
1932 /*
1933  * Return the option name for the first CSC flag (there should be only
1934  * one) encountered in the share flags.
1935  */
1936 char *
smb_shr_sa_csc_name(const smb_share_t * si)1937 smb_shr_sa_csc_name(const smb_share_t *si)
1938 {
1939 	int i;
1940 
1941 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1942 		if (si->shr_flags & cscopt[i].flag)
1943 			return (cscopt[i].value);
1944 	}
1945 
1946 	return (NULL);
1947 }
1948 
1949 /*
1950  * Takes the value of a boolean share property and set/clear the
1951  * specified flag based on the property's value.
1952  */
1953 void
smb_shr_sa_setflag(const char * value,smb_share_t * si,uint32_t flag)1954 smb_shr_sa_setflag(const char *value, smb_share_t *si, uint32_t flag)
1955 {
1956 	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0))
1957 		si->shr_flags |= flag;
1958 	else
1959 		si->shr_flags &= ~flag;
1960 }
1961 
1962 /*
1963  * looks up sharemgr for the given share (resource) and loads
1964  * the definition into cache if lookup is successful
1965  */
1966 static uint32_t
smb_shr_sa_loadbyname(char * sharename)1967 smb_shr_sa_loadbyname(char *sharename)
1968 {
1969 	sa_handle_t handle;
1970 	sa_share_t share;
1971 	sa_resource_t resource;
1972 	uint32_t status;
1973 
1974 	if ((handle = smb_shr_sa_enter()) == NULL)
1975 		return (NERR_InternalError);
1976 
1977 	resource = sa_find_resource(handle, sharename);
1978 	if (resource == NULL) {
1979 		smb_shr_sa_exit();
1980 		return (NERR_NetNameNotFound);
1981 	}
1982 
1983 	share = sa_get_resource_parent(resource);
1984 	if (share == NULL) {
1985 		smb_shr_sa_exit();
1986 		return (NERR_InternalError);
1987 	}
1988 
1989 	status = smb_shr_sa_load(share, resource);
1990 
1991 	smb_shr_sa_exit();
1992 	return (status);
1993 }
1994 
1995 /*
1996  * ============================================
1997  * Share publishing functions
1998  *
1999  * All the functions are private
2000  * ============================================
2001  */
2002 
2003 static void
smb_shr_publish(const char * sharename,const char * container)2004 smb_shr_publish(const char *sharename, const char *container)
2005 {
2006 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
2007 }
2008 
2009 static void
smb_shr_unpublish(const char * sharename,const char * container)2010 smb_shr_unpublish(const char *sharename, const char *container)
2011 {
2012 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
2013 }
2014 
2015 /*
2016  * In domain mode, put a share on the publisher queue.
2017  * This is a no-op if the smb service is in Workgroup mode.
2018  */
2019 static void
smb_shr_publisher_queue(const char * sharename,const char * container,char op)2020 smb_shr_publisher_queue(const char *sharename, const char *container, char op)
2021 {
2022 	smb_shr_pitem_t *item = NULL;
2023 
2024 	if (container == NULL || *container == '\0')
2025 		return;
2026 
2027 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
2028 		return;
2029 
2030 	(void) mutex_lock(&ad_queue.spq_mtx);
2031 	switch (ad_queue.spq_state) {
2032 	case SMB_SHR_PQS_READY:
2033 	case SMB_SHR_PQS_PUBLISHING:
2034 		break;
2035 	default:
2036 		(void) mutex_unlock(&ad_queue.spq_mtx);
2037 		return;
2038 	}
2039 	(void) mutex_unlock(&ad_queue.spq_mtx);
2040 
2041 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
2042 		return;
2043 
2044 	item->spi_op = op;
2045 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
2046 	(void) strlcpy(item->spi_container, container,
2047 	    sizeof (item->spi_container));
2048 
2049 	(void) mutex_lock(&ad_queue.spq_mtx);
2050 	list_insert_tail(&ad_queue.spq_list, item);
2051 	(void) cond_signal(&ad_queue.spq_cv);
2052 	(void) mutex_unlock(&ad_queue.spq_mtx);
2053 }
2054 
2055 /*
2056  * Publishing won't be activated if the smb service is running in
2057  * Workgroup mode.
2058  */
2059 static int
smb_shr_publisher_start(void)2060 smb_shr_publisher_start(void)
2061 {
2062 	pthread_t publish_thr;
2063 	pthread_attr_t tattr;
2064 	int rc;
2065 
2066 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
2067 		return (0);
2068 
2069 	(void) mutex_lock(&ad_queue.spq_mtx);
2070 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
2071 		(void) mutex_unlock(&ad_queue.spq_mtx);
2072 		errno = EINVAL;
2073 		return (-1);
2074 	}
2075 
2076 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
2077 	    offsetof(smb_shr_pitem_t, spi_lnd));
2078 	ad_queue.spq_state = SMB_SHR_PQS_READY;
2079 	(void) mutex_unlock(&ad_queue.spq_mtx);
2080 
2081 	(void) pthread_attr_init(&tattr);
2082 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
2083 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
2084 	(void) pthread_attr_destroy(&tattr);
2085 
2086 	return (rc);
2087 }
2088 
2089 static void
smb_shr_publisher_stop(void)2090 smb_shr_publisher_stop(void)
2091 {
2092 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
2093 		return;
2094 
2095 	(void) mutex_lock(&ad_queue.spq_mtx);
2096 	switch (ad_queue.spq_state) {
2097 	case SMB_SHR_PQS_READY:
2098 	case SMB_SHR_PQS_PUBLISHING:
2099 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
2100 		(void) cond_signal(&ad_queue.spq_cv);
2101 		break;
2102 	default:
2103 		break;
2104 	}
2105 	(void) mutex_unlock(&ad_queue.spq_mtx);
2106 }
2107 
2108 /*
2109  * This is the publisher daemon thread.  While running, the thread waits
2110  * on a conditional variable until notified that a share needs to be
2111  * [un]published or that the thread should be terminated.
2112  *
2113  * Entries may remain in the outgoing queue if the Active Directory
2114  * service is inaccessible, in which case the thread wakes up every 60
2115  * seconds to retry.
2116  */
2117 /*ARGSUSED*/
2118 static void *
smb_shr_publisher(void * arg)2119 smb_shr_publisher(void *arg)
2120 {
2121 	smb_ads_handle_t *ah;
2122 	smb_shr_pitem_t *shr;
2123 	list_t publist;
2124 	timestruc_t pubretry;
2125 	char hostname[MAXHOSTNAMELEN];
2126 
2127 	(void) mutex_lock(&ad_queue.spq_mtx);
2128 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
2129 		(void) mutex_unlock(&ad_queue.spq_mtx);
2130 		return (NULL);
2131 	}
2132 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
2133 	(void) mutex_unlock(&ad_queue.spq_mtx);
2134 
2135 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN,
2136 	    SMB_CASE_PRESERVE);
2137 
2138 	list_create(&publist, sizeof (smb_shr_pitem_t),
2139 	    offsetof(smb_shr_pitem_t, spi_lnd));
2140 
2141 	for (;;) {
2142 		(void) mutex_lock(&ad_queue.spq_mtx);
2143 
2144 		while (list_is_empty(&ad_queue.spq_list) &&
2145 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
2146 			if (list_is_empty(&publist)) {
2147 				(void) cond_wait(&ad_queue.spq_cv,
2148 				    &ad_queue.spq_mtx);
2149 			} else {
2150 				pubretry.tv_sec = 60;
2151 				pubretry.tv_nsec = 0;
2152 				(void) cond_reltimedwait(&ad_queue.spq_cv,
2153 				    &ad_queue.spq_mtx, &pubretry);
2154 				break;
2155 			}
2156 		}
2157 
2158 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
2159 			(void) mutex_unlock(&ad_queue.spq_mtx);
2160 			break;
2161 		}
2162 
2163 		/*
2164 		 * Transfer queued items to the local list so that
2165 		 * the mutex can be released.
2166 		 */
2167 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
2168 			list_remove(&ad_queue.spq_list, shr);
2169 			list_insert_tail(&publist, shr);
2170 		}
2171 
2172 		(void) mutex_unlock(&ad_queue.spq_mtx);
2173 
2174 		if ((ah = smb_ads_open()) != NULL) {
2175 			smb_shr_publisher_send(ah, &publist, hostname);
2176 			smb_ads_close(ah);
2177 		}
2178 	}
2179 
2180 	(void) mutex_lock(&ad_queue.spq_mtx);
2181 	smb_shr_publisher_flush(&ad_queue.spq_list);
2182 	list_destroy(&ad_queue.spq_list);
2183 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
2184 	(void) mutex_unlock(&ad_queue.spq_mtx);
2185 
2186 	smb_shr_publisher_flush(&publist);
2187 	list_destroy(&publist);
2188 	return (NULL);
2189 }
2190 
2191 /*
2192  * Remove items from the specified queue and [un]publish them.
2193  */
2194 static void
smb_shr_publisher_send(smb_ads_handle_t * ah,list_t * publist,const char * host)2195 smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
2196 {
2197 	smb_shr_pitem_t *shr;
2198 
2199 	while ((shr = list_head(publist)) != NULL) {
2200 		(void) mutex_lock(&ad_queue.spq_mtx);
2201 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
2202 			(void) mutex_unlock(&ad_queue.spq_mtx);
2203 			return;
2204 		}
2205 		(void) mutex_unlock(&ad_queue.spq_mtx);
2206 
2207 		list_remove(publist, shr);
2208 
2209 		if (shr->spi_op == SMB_SHR_PUBLISH)
2210 			(void) smb_ads_publish_share(ah, shr->spi_name,
2211 			    NULL, shr->spi_container, host);
2212 		else
2213 			(void) smb_ads_remove_share(ah, shr->spi_name,
2214 			    NULL, shr->spi_container, host);
2215 
2216 		free(shr);
2217 	}
2218 }
2219 
2220 /*
2221  * Flush all remaining items from the specified list/queue.
2222  */
2223 static void
smb_shr_publisher_flush(list_t * lst)2224 smb_shr_publisher_flush(list_t *lst)
2225 {
2226 	smb_shr_pitem_t *shr;
2227 
2228 	while ((shr = list_head(lst)) != NULL) {
2229 		list_remove(lst, shr);
2230 		free(shr);
2231 	}
2232 }
2233 
2234 /*
2235  * If the share path refers to a ZFS file system, add the
2236  * .zfs/shares/<share> object and add or remove the special
2237  * directory and file telling clients about quota support.
2238  */
2239 static void
smb_shr_zfs_add(smb_share_t * si)2240 smb_shr_zfs_add(smb_share_t *si)
2241 {
2242 	libzfs_handle_t *libhd;
2243 	zfs_handle_t *zfshd;
2244 	int ret;
2245 	char buf[MAXPATHLEN];	/* dataset or mountpoint */
2246 
2247 	if ((libhd = libzfs_init()) == NULL)
2248 		return;
2249 
2250 	if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
2251 		libzfs_fini(libhd);
2252 		return;
2253 	}
2254 
2255 	if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
2256 		libzfs_fini(libhd);
2257 		return;
2258 	}
2259 
2260 	errno = 0;
2261 	ret = zfs_smb_acl_add(libhd, buf, si->shr_path, si->shr_name);
2262 	if (ret != 0 && errno != EAGAIN && errno != EEXIST)
2263 		syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
2264 		    si->shr_name, strerror(errno));
2265 
2266 	ret = zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT,
2267 	    buf, MAXPATHLEN, NULL, NULL, 0, B_FALSE);
2268 	if (ret != 0) {
2269 		syslog(LOG_INFO, "share: failed to get mountpoint: "
2270 		    "%s\n", si->shr_name);
2271 	} else {
2272 		if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0) {
2273 			smb_quota_add_fs(buf);
2274 		} else {
2275 			smb_quota_remove_fs(buf);
2276 		}
2277 	}
2278 
2279 	zfs_close(zfshd);
2280 	libzfs_fini(libhd);
2281 }
2282 
2283 /*
2284  * If the share path refers to a ZFS file system, remove the
2285  * .zfs/shares/<share> object.
2286  */
2287 static void
smb_shr_zfs_remove(smb_share_t * si)2288 smb_shr_zfs_remove(smb_share_t *si)
2289 {
2290 	libzfs_handle_t *libhd;
2291 	int ret;
2292 	char buf[MAXPATHLEN];	/* dataset or mountpoint */
2293 
2294 	if ((libhd = libzfs_init()) == NULL)
2295 		return;
2296 
2297 	if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
2298 		libzfs_fini(libhd);
2299 		return;
2300 	}
2301 
2302 	errno = 0;
2303 	ret = zfs_smb_acl_remove(libhd, buf, si->shr_path, si->shr_name);
2304 	if (ret != 0 && errno != EAGAIN)
2305 		syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
2306 		    si->shr_name, strerror(errno));
2307 
2308 	/*
2309 	 * We could remove the quotas directory here, but that adds
2310 	 * significantly to the time required for a zpool export,
2311 	 * so just leave it here and fixup when we share next.
2312 	 */
2313 
2314 	libzfs_fini(libhd);
2315 }
2316 
2317 /*
2318  * If the share path refers to a ZFS file system, rename the
2319  * .zfs/shares/<share> object.
2320  */
2321 static void
smb_shr_zfs_rename(smb_share_t * from,smb_share_t * to)2322 smb_shr_zfs_rename(smb_share_t *from, smb_share_t *to)
2323 {
2324 	libzfs_handle_t *libhd;
2325 	zfs_handle_t *zfshd;
2326 	int ret;
2327 	char dataset[MAXPATHLEN];
2328 
2329 	if ((libhd = libzfs_init()) == NULL)
2330 		return;
2331 
2332 	if (smb_getdataset(libhd, from->shr_path, dataset, MAXPATHLEN) != 0) {
2333 		libzfs_fini(libhd);
2334 		return;
2335 	}
2336 
2337 	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
2338 		libzfs_fini(libhd);
2339 		return;
2340 	}
2341 
2342 	errno = 0;
2343 	ret = zfs_smb_acl_rename(libhd, dataset, from->shr_path,
2344 	    from->shr_name, to->shr_name);
2345 	if (ret != 0 && errno != EAGAIN)
2346 		syslog(LOG_INFO, "share: failed to rename ACL object: %s: %s\n",
2347 		    from->shr_name, strerror(errno));
2348 
2349 	zfs_close(zfshd);
2350 	libzfs_fini(libhd);
2351 }
2352 
2353 /*
2354  * Enable all privileges in the inheritable set to execute command.
2355  */
2356 static int
smb_shr_enable_all_privs(void)2357 smb_shr_enable_all_privs(void)
2358 {
2359 	priv_set_t *pset;
2360 
2361 	pset = priv_allocset();
2362 	if (pset == NULL)
2363 		return (-1);
2364 
2365 	if (getppriv(PRIV_LIMIT, pset)) {
2366 		priv_freeset(pset);
2367 		return (-1);
2368 	}
2369 
2370 	if (setppriv(PRIV_ON, PRIV_INHERITABLE, pset)) {
2371 		priv_freeset(pset);
2372 		return (-1);
2373 	}
2374 
2375 	priv_freeset(pset);
2376 	return (0);
2377 }
2378 
2379 /*
2380  * Tokenizes the command string and returns the list of tokens in an array.
2381  *
2382  * Returns NULL if there are no tokens.
2383  */
2384 static char **
smb_shr_tokenize_cmd(char * cmdstr)2385 smb_shr_tokenize_cmd(char *cmdstr)
2386 {
2387 	char *cmd, *buf, *bp, *value;
2388 	char **argv, **ap;
2389 	int argc, i;
2390 
2391 	if (cmdstr == NULL || *cmdstr == '\0')
2392 		return (NULL);
2393 
2394 	if ((buf = malloc(MAXPATHLEN)) == NULL)
2395 		return (NULL);
2396 
2397 	(void) strlcpy(buf, cmdstr, MAXPATHLEN);
2398 
2399 	for (argc = 2, bp = cmdstr; *bp != '\0'; ++bp)
2400 		if (*bp == ' ')
2401 			++argc;
2402 
2403 	if ((argv = calloc(argc, sizeof (char *))) == NULL) {
2404 		free(buf);
2405 		return (NULL);
2406 	}
2407 
2408 	ap = argv;
2409 	for (bp = buf, i = 0; i < argc; ++i) {
2410 		do {
2411 			if ((value = strsep(&bp, " ")) == NULL)
2412 				break;
2413 		} while (*value == '\0');
2414 
2415 		if (value == NULL)
2416 			break;
2417 
2418 		*ap++ = value;
2419 	}
2420 
2421 	/* get the filename of the command from the path */
2422 	if ((cmd = strrchr(argv[0], '/')) != NULL)
2423 		(void) strlcpy(argv[0], ++cmd, strlen(argv[0]));
2424 
2425 	return (argv);
2426 }
2427 
2428 /*
2429  * Expands the command string for the following substitution tokens:
2430  *
2431  * %U - Windows username
2432  * %D - Name of the domain or workgroup of %U
2433  * %h - The server hostname
2434  * %M - The client hostname
2435  * %L - The server NetBIOS name
2436  * %m - The client NetBIOS name. This option is only valid for NetBIOS
2437  *      connections (port 139).
2438  * %I - The IP address of the client machine
2439  * %i - The local IP address to which the client is connected
2440  * %S - The name of the share
2441  * %P - The root directory of the share
2442  * %u - The UID of the Unix user
2443  *
2444  * Returns 0 on success.  Otherwise -1.
2445  */
2446 static int
smb_shr_expand_subs(char ** cmd_toks,smb_share_t * si,smb_shr_execinfo_t * subs)2447 smb_shr_expand_subs(char **cmd_toks, smb_share_t *si, smb_shr_execinfo_t *subs)
2448 {
2449 	char *fmt, *sub_chr, *ptr;
2450 	boolean_t unknown;
2451 	char hostname[MAXHOSTNAMELEN];
2452 	char ip_str[INET6_ADDRSTRLEN];
2453 	char name[SMB_PI_MAX_HOST];
2454 	smb_wchar_t wbuf[SMB_PI_MAX_HOST];
2455 	int i;
2456 
2457 	if (cmd_toks == NULL || *cmd_toks == NULL)
2458 		return (-1);
2459 
2460 	for (i = 1; cmd_toks[i]; i++) {
2461 		fmt = cmd_toks[i];
2462 		if (*fmt == '%') {
2463 			sub_chr = fmt + 1;
2464 			unknown = B_FALSE;
2465 
2466 			switch (*sub_chr) {
2467 			case 'U':
2468 				ptr = strdup(subs->e_winname);
2469 				break;
2470 			case 'D':
2471 				ptr = strdup(subs->e_userdom);
2472 				break;
2473 			case 'h':
2474 				if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
2475 					unknown = B_TRUE;
2476 				else
2477 					ptr = strdup(hostname);
2478 				break;
2479 			case 'M':
2480 				if (smb_getnameinfo(&subs->e_cli_ipaddr,
2481 				    hostname, sizeof (hostname), 0) != 0)
2482 					unknown = B_TRUE;
2483 				else
2484 					ptr = strdup(hostname);
2485 				break;
2486 			case 'L':
2487 				if (smb_getnetbiosname(hostname,
2488 				    NETBIOS_NAME_SZ) != 0)
2489 					unknown = B_TRUE;
2490 				else
2491 					ptr = strdup(hostname);
2492 				break;
2493 			case 'm':
2494 				if (*subs->e_cli_netbiosname == '\0')
2495 					unknown = B_TRUE;
2496 				else {
2497 					(void) smb_mbstowcs(wbuf,
2498 					    subs->e_cli_netbiosname,
2499 					    SMB_PI_MAX_HOST - 1);
2500 
2501 					if (ucstooem(name, wbuf,
2502 					    SMB_PI_MAX_HOST, OEM_CPG_850) == 0)
2503 						(void) strlcpy(name,
2504 						    subs->e_cli_netbiosname,
2505 						    SMB_PI_MAX_HOST);
2506 
2507 					ptr = strdup(name);
2508 				}
2509 				break;
2510 			case 'I':
2511 				if (smb_inet_ntop(&subs->e_cli_ipaddr, ip_str,
2512 				    SMB_IPSTRLEN(subs->e_cli_ipaddr.a_family))
2513 				    != NULL)
2514 					ptr = strdup(ip_str);
2515 				else
2516 					unknown = B_TRUE;
2517 				break;
2518 			case 'i':
2519 				if (smb_inet_ntop(&subs->e_srv_ipaddr, ip_str,
2520 				    SMB_IPSTRLEN(subs->e_srv_ipaddr.a_family))
2521 				    != NULL)
2522 					ptr = strdup(ip_str);
2523 				else
2524 					unknown = B_TRUE;
2525 				break;
2526 			case 'S':
2527 				ptr = strdup(si->shr_name);
2528 				break;
2529 			case 'P':
2530 				ptr = strdup(si->shr_path);
2531 				break;
2532 			case 'u':
2533 				(void) snprintf(name, sizeof (name), "%u",
2534 				    subs->e_uid);
2535 				ptr = strdup(name);
2536 				break;
2537 			default:
2538 				/* unknown sub char */
2539 				unknown = B_TRUE;
2540 				break;
2541 			}
2542 
2543 			if (unknown)
2544 				ptr = strdup("");
2545 
2546 		} else  /* first char of cmd's arg is not '%' char */
2547 			ptr = strdup("");
2548 
2549 		cmd_toks[i] = ptr;
2550 
2551 		if (ptr == NULL) {
2552 			for (i = 1; cmd_toks[i]; i++)
2553 				free(cmd_toks[i]);
2554 
2555 			return (-1);
2556 		}
2557 	}
2558 
2559 	return (0);
2560 }
2561 
2562 /*ARGSUSED*/
2563 static void
smb_shr_sig_abnormal_term(int sig_val)2564 smb_shr_sig_abnormal_term(int sig_val)
2565 {
2566 	/*
2567 	 * Calling _exit() prevents parent process from getting SIGTERM/SIGINT
2568 	 * signal.
2569 	 */
2570 	_exit(-1);
2571 }
2572 
2573 /*ARGSUSED*/
2574 static void
smb_shr_sig_child(int sig_val)2575 smb_shr_sig_child(int sig_val)
2576 {
2577 	/*
2578 	 * Catch the signal and allow the exit status of the child process
2579 	 * to be available for reaping.
2580 	 */
2581 }
2582 
2583 /*
2584  * This is a temporary function which converts the given smb_share_t
2585  * structure to the nvlist format that will be provided by libsharev2
2586  */
2587 static int
smb_shr_encode(smb_share_t * si,nvlist_t ** nvlist)2588 smb_shr_encode(smb_share_t *si, nvlist_t **nvlist)
2589 {
2590 	nvlist_t *list;
2591 	nvlist_t *share;
2592 	nvlist_t *smb;
2593 	char *csc;
2594 	int rc = 0;
2595 
2596 	*nvlist = NULL;
2597 
2598 	if ((rc = nvlist_alloc(&list, NV_UNIQUE_NAME, 0)) != 0)
2599 		return (rc);
2600 
2601 	if ((rc = nvlist_alloc(&share, NV_UNIQUE_NAME, 0)) != 0) {
2602 		nvlist_free(list);
2603 		return (rc);
2604 	}
2605 
2606 	if ((rc = nvlist_alloc(&smb, NV_UNIQUE_NAME, 0)) != 0) {
2607 		nvlist_free(share);
2608 		nvlist_free(list);
2609 		return (rc);
2610 	}
2611 
2612 	/* global share properties */
2613 	rc |= nvlist_add_string(share, "name", si->shr_name);
2614 	rc |= nvlist_add_string(share, "path", si->shr_path);
2615 	rc |= nvlist_add_string(share, "desc", si->shr_cmnt);
2616 
2617 	/* smb protocol properties */
2618 	rc = nvlist_add_string(smb, SHOPT_AD_CONTAINER, si->shr_container);
2619 	if ((si->shr_flags & SMB_SHRF_ACC_NONE) != 0)
2620 		rc |= nvlist_add_string(smb, SHOPT_NONE, si->shr_access_none);
2621 	if ((si->shr_flags & SMB_SHRF_ACC_RO) != 0)
2622 		rc |= nvlist_add_string(smb, SHOPT_RO, si->shr_access_ro);
2623 	if ((si->shr_flags & SMB_SHRF_ACC_RW) != 0)
2624 		rc |= nvlist_add_string(smb, SHOPT_RW, si->shr_access_rw);
2625 
2626 	if ((si->shr_flags & SMB_SHRF_ABE) != 0)
2627 		rc |= nvlist_add_string(smb, SHOPT_ABE, "true");
2628 	if ((si->shr_flags & SMB_SHRF_CATIA) != 0)
2629 		rc |= nvlist_add_string(smb, SHOPT_CATIA, "true");
2630 	if ((si->shr_flags & SMB_SHRF_GUEST_OK) != 0)
2631 		rc |= nvlist_add_string(smb, SHOPT_GUEST, "true");
2632 	if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
2633 		rc |= nvlist_add_string(smb, SHOPT_DFSROOT, "true");
2634 	if ((si->shr_flags & SMB_SHRF_CA) != 0)
2635 		rc |= nvlist_add_string(smb, SHOPT_CA, "true");
2636 	if ((si->shr_flags & SMB_SHRF_FSO) != 0)
2637 		rc |= nvlist_add_string(smb, SHOPT_FSO, "true");
2638 	if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0)
2639 		rc |= nvlist_add_string(smb, SHOPT_QUOTAS, "true");
2640 
2641 	if (si->shr_encrypt == SMB_CONFIG_REQUIRED)
2642 		rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "required");
2643 	else if (si->shr_encrypt == SMB_CONFIG_ENABLED)
2644 		rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "enabled");
2645 	else
2646 		rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "disabled");
2647 
2648 	if ((si->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
2649 		rc |= nvlist_add_string(smb, SHOPT_AUTOHOME, "true");
2650 		rc |= nvlist_add_uint32(smb, "uid", si->shr_uid);
2651 		rc |= nvlist_add_uint32(smb, "gid", si->shr_gid);
2652 	}
2653 
2654 	if ((csc = smb_shr_sa_csc_name(si)) != NULL)
2655 		rc |= nvlist_add_string(smb, SHOPT_CSC, csc);
2656 
2657 	rc |= nvlist_add_uint32(smb, "type", si->shr_type);
2658 
2659 	rc |= nvlist_add_nvlist(share, "smb", smb);
2660 	rc |= nvlist_add_nvlist(list, si->shr_name, share);
2661 
2662 	nvlist_free(share);
2663 	nvlist_free(smb);
2664 
2665 	if (rc != 0)
2666 		nvlist_free(list);
2667 	else
2668 		*nvlist = list;
2669 
2670 	return (rc);
2671 }
2672