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