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
60typedef struct smb_transient {
61	char		*name;
62	char		*cmnt;
63	char		*path;
64	char		drive;
65	boolean_t	check;
66} smb_transient_t;
67
68static 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
74static 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 */
100typedef 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
122static smb_shr_cache_t smb_shr_cache;
123
124static uint32_t smb_shr_cache_create(void);
125static void smb_shr_cache_destroy(void);
126static uint32_t smb_shr_cache_lock(int);
127static void smb_shr_cache_unlock(void);
128static int smb_shr_cache_count(void);
129static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
130
131static smb_share_t *smb_shr_cache_findent(char *);
132static uint32_t smb_shr_cache_addent(smb_share_t *);
133static void smb_shr_cache_delent(char *);
134static void smb_shr_cache_freent(HT_ITEM *);
135
136static boolean_t smb_shr_is_empty(const char *);
137static boolean_t smb_shr_is_dot_or_dotdot(const char *);
138
139/*
140 * sharemgr functions
141 */
142static void smb_shr_sa_loadgrp(sa_group_t);
143static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
144static uint32_t smb_shr_sa_loadbyname(char *);
145static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
146
147/*
148 * .ZFS management functions
149 */
150static void smb_shr_zfs_add(smb_share_t *);
151static void smb_shr_zfs_remove(smb_share_t *);
152static 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
160typedef 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 */
178typedef 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
185static smb_shr_pqueue_t ad_queue;
186
187static int smb_shr_publisher_start(void);
188static void smb_shr_publisher_stop(void);
189static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
190static void smb_shr_publisher_queue(const char *, const char *, char);
191static void *smb_shr_publisher(void *);
192static void smb_shr_publisher_flush(list_t *);
193static void smb_shr_publish(const char *, const char *);
194static void smb_shr_unpublish(const char *, const char *);
195
196/*
197 * Utility/helper functions
198 */
199static uint32_t smb_shr_lookup(char *, smb_share_t *);
200static uint32_t smb_shr_add_transient(char *, char *, char *);
201static int smb_shr_enable_all_privs(void);
202static int smb_shr_expand_subs(char **, smb_share_t *, smb_shr_execinfo_t *);
203static char **smb_shr_tokenize_cmd(char *);
204static void smb_shr_sig_abnormal_term(int);
205static void smb_shr_sig_child(int);
206static int smb_shr_encode(smb_share_t *, nvlist_t **);
207
208/*
209 * libshare handle and synchronization
210 */
211typedef 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
217static smb_sa_handle_t smb_sa_handle;
218
219static char smb_shr_exec_map[MAXPATHLEN];
220static char smb_shr_exec_unmap[MAXPATHLEN];
221static 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 */
228static sema_t smb_proc_sem = DEFAULTSEMA;
229
230/*
231 * Creates and initializes the cache and starts the publisher
232 * thread.
233 */
234int
235smb_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
262void
263smb_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 */
282sa_handle_t
283smb_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 */
312void
313smb_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 */
321int
322smb_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 */
339void
340smb_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 */
356smb_share_t *
357smb_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 */
387uint32_t
388smb_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 */
521uint32_t
522smb_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 */
605uint32_t
606smb_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 */
692uint32_t
693smb_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 */
717uint32_t
718smb_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 */
856boolean_t
857smb_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 */
888uint32_t
889smb_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 */
945int
946smb_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 */
971boolean_t
972smb_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 */
1002boolean_t
1003smb_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
1016char
1017smb_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 */
1042static boolean_t
1043smb_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 */
1066static boolean_t
1067smb_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 */
1093uint32_t
1094smb_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
1115void
1116smb_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 */
1145int
1146smb_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 */
1257void
1258smb_proc_initsem(void)
1259{
1260	(void) sema_init(&smb_proc_sem, 1, USYNC_THREAD, NULL);
1261}
1262
1263int
1264smb_proc_takesem(void)
1265{
1266	return (sema_wait(&smb_proc_sem));
1267}
1268
1269void
1270smb_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 */
1285static uint32_t
1286smb_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 */
1308static uint32_t
1309smb_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 */
1349static uint32_t
1350smb_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 */
1387static void
1388smb_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 */
1410static uint32_t
1411smb_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 */
1436static void
1437smb_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 */
1451static int
1452smb_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 */
1463static smb_share_t *
1464smb_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 */
1482static smb_share_t *
1483smb_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 */
1505static uint32_t
1506smb_shr_cache_addent(smb_share_t *si)
1507{
1508	smb_share_t *cache_ent;
1509	uint32_t status = NERR_Success;
1510
1511	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
1512		return (ERROR_NOT_ENOUGH_MEMORY);
1513
1514	si->shr_type |= smb_shr_is_special(cache_ent->shr_name);
1515
1516	if (smb_shr_is_admin(cache_ent->shr_name))
1517		si->shr_flags |= SMB_SHRF_ADMIN;
1518
1519	bcopy(si, cache_ent, sizeof (smb_share_t));
1520
1521	if (si->shr_flags & SMB_SHRF_AUTOHOME)
1522		cache_ent->shr_refcnt = 1;
1523
1524	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
1525	    == NULL) {
1526		syslog(LOG_DEBUG, "share: %s: cache update failed",
1527		    cache_ent->shr_name);
1528		free(cache_ent);
1529		status = NERR_InternalError;
1530	}
1531
1532	return (status);
1533}
1534
1535/*
1536 * Delete the specified share from the cache.
1537 */
1538static void
1539smb_shr_cache_delent(char *sharename)
1540{
1541	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
1542}
1543
1544/*
1545 * Call back to free the given cache entry.
1546 */
1547static void
1548smb_shr_cache_freent(HT_ITEM *item)
1549{
1550	if (item && item->hi_data)
1551		free(item->hi_data);
1552}
1553
1554/*
1555 * ============================================
1556 * Interfaces to sharemgr
1557 *
1558 * All functions in this section are private
1559 * ============================================
1560 */
1561
1562/*
1563 * Loads the SMB shares, from sharemgr, then:
1564 *     - calls smb_shr_add which:
1565 *         - adds the share into the share cache
1566 *         - adds the share into in-kernel kshare table
1567 *         - publishes the share in ADS
1568 *     - updates the share list in sharefs/sharetab
1569 */
1570/*ARGSUSED*/
1571void *
1572smb_shr_load(void *args)
1573{
1574	sa_handle_t handle;
1575	sa_group_t group, subgroup;
1576	char *gstate;
1577	boolean_t gdisabled;
1578
1579	smb_shr_load_execinfo();
1580
1581	if ((handle = smb_shr_sa_enter()) == NULL) {
1582		syslog(LOG_ERR, "smb_shr_load: load failed");
1583		return (NULL);
1584	}
1585
1586	for (group = sa_get_group(handle, NULL);
1587	    group != NULL; group = sa_get_next_group(group)) {
1588		gstate = sa_get_group_attr(group, "state");
1589		if (gstate == NULL)
1590			continue;
1591
1592		gdisabled = (strcasecmp(gstate, "disabled") == 0);
1593		sa_free_attr_string(gstate);
1594		if (gdisabled)
1595			continue;
1596
1597		smb_shr_sa_loadgrp(group);
1598
1599		for (subgroup = sa_get_sub_group(group);
1600		    subgroup != NULL;
1601		    subgroup = sa_get_next_group(subgroup)) {
1602			smb_shr_sa_loadgrp(subgroup);
1603		}
1604
1605	}
1606	smb_shr_sa_exit();
1607	return (NULL);
1608}
1609
1610void
1611smb_shr_load_execinfo()
1612{
1613	(void) mutex_lock(&smb_shr_exec_mtx);
1614	(void) smb_config_get_execinfo(smb_shr_exec_map, smb_shr_exec_unmap,
1615	    MAXPATHLEN);
1616	(void) mutex_unlock(&smb_shr_exec_mtx);
1617}
1618
1619/*
1620 * Handles disabling shares in sharefs when stoping smbd
1621 */
1622void
1623smb_shr_unload()
1624{
1625	smb_shriter_t iterator;
1626	smb_share_t *si;
1627	sa_handle_t handle;
1628	int rc;
1629
1630	if ((handle = smb_shr_sa_enter()) == NULL) {
1631		syslog(LOG_ERR, "smb_shr_unload: failed");
1632		return;
1633	}
1634
1635	smb_shr_iterinit(&iterator);
1636
1637	while ((si = smb_shr_iterate(&iterator)) != NULL) {
1638
1639		/* Skip transient shares, IPC$, ... */
1640		if ((si->shr_flags & SMB_SHRF_TRANS) ||
1641		    STYPE_ISIPC(si->shr_type))
1642			continue;
1643
1644		rc = sa_delete_sharetab(handle, si->shr_path, "smb");
1645		if (rc) {
1646			syslog(LOG_ERR,
1647			    "sharefs remove %s failed, rc=%d, err=%d",
1648			    si->shr_path, rc, errno);
1649		}
1650	}
1651	smb_shr_sa_exit();
1652}
1653
1654/*
1655 * Load the shares contained in the specified group.
1656 *
1657 * Don't process groups on which the smb protocol is disabled.
1658 * The top level ZFS group won't have the smb protocol enabled
1659 * but sub-groups will.
1660 *
1661 * We will tolerate a limited number of errors and then give
1662 * up on the current group.  A typical error might be that the
1663 * shared directory no longer exists.
1664 */
1665static void
1666smb_shr_sa_loadgrp(sa_group_t group)
1667{
1668	sa_share_t share;
1669	sa_resource_t resource;
1670	int error_count = 0;
1671
1672	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
1673		return;
1674
1675	for (share = sa_get_share(group, NULL);
1676	    share != NULL;
1677	    share = sa_get_next_share(share)) {
1678		for (resource = sa_get_share_resource(share, NULL);
1679		    resource != NULL;
1680		    resource = sa_get_next_resource(resource)) {
1681			if (smb_shr_sa_load(share, resource))
1682				++error_count;
1683
1684			if (error_count > SMB_SHR_ERROR_THRESHOLD)
1685				break;
1686		}
1687
1688		if (error_count > SMB_SHR_ERROR_THRESHOLD)
1689			break;
1690	}
1691}
1692
1693/*
1694 * Load a share definition from sharemgr and add it to the cache.
1695 * If the share is already in the cache then it doesn't do anything.
1696 *
1697 * This function does not report duplicate shares as error since
1698 * a share might have been added by smb_shr_get() while load is
1699 * in progress.
1700 */
1701static uint32_t
1702smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
1703{
1704	smb_share_t si;
1705	char *sharename;
1706	uint32_t status;
1707	boolean_t loaded;
1708	int rc;
1709
1710	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
1711		return (NERR_InternalError);
1712
1713	loaded = smb_shr_exists(sharename);
1714	sa_free_attr_string(sharename);
1715
1716	if (loaded)
1717		return (NERR_Success);
1718
1719	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
1720		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
1721		    si.shr_name, status);
1722		return (status);
1723	}
1724
1725	status = smb_shr_add(&si);
1726	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
1727		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
1728		    si.shr_name, status);
1729		return (status);
1730	}
1731
1732	rc = sa_update_sharetab(share, "smb");
1733	if (rc) {
1734		syslog(LOG_ERR, "sharefs add %s failed, rc=%d, err=%d",
1735		    sharename, rc, errno);
1736	}
1737
1738	return (NERR_Success);
1739}
1740
1741static char *
1742smb_shr_sa_getprop(sa_optionset_t opts, char *propname)
1743{
1744	sa_property_t prop;
1745	char *val = NULL;
1746
1747	prop = sa_get_property(opts, propname);
1748	if (prop != NULL)
1749		val = sa_get_property_attr(prop, "value");
1750
1751	return (val);
1752}
1753
1754/*
1755 * Read the specified share information from sharemgr and return
1756 * it in the given smb_share_t structure.
1757 *
1758 * Shares read from sharemgr are marked as permanent/persistent.
1759 */
1760static uint32_t
1761smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
1762{
1763	sa_optionset_t opts;
1764	char *val = NULL;
1765	char *path;
1766	char *rname;
1767
1768	if ((path = sa_get_share_attr(share, "path")) == NULL)
1769		return (NERR_InternalError);
1770
1771	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
1772		sa_free_attr_string(path);
1773		return (NERR_InternalError);
1774	}
1775
1776	bzero(si, sizeof (smb_share_t));
1777	si->shr_flags = SMB_SHRF_PERM;
1778
1779	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
1780	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
1781	sa_free_attr_string(path);
1782	sa_free_attr_string(rname);
1783
1784	val = sa_get_resource_description(resource);
1785	if (val == NULL)
1786		val = sa_get_share_description(share);
1787
1788	if (val != NULL) {
1789		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
1790		sa_free_share_description(val);
1791	}
1792
1793	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
1794	if (opts == NULL)
1795		return (NERR_Success);
1796
1797	val = smb_shr_sa_getprop(opts, SHOPT_AD_CONTAINER);
1798	if (val != NULL) {
1799		(void) strlcpy(si->shr_container, val,
1800		    sizeof (si->shr_container));
1801		free(val);
1802	}
1803
1804	val = smb_shr_sa_getprop(opts, SHOPT_CATIA);
1805	if (val != NULL) {
1806		smb_shr_sa_setflag(val, si, SMB_SHRF_CATIA);
1807		free(val);
1808	}
1809
1810	val = smb_shr_sa_getprop(opts, SHOPT_ABE);
1811	if (val != NULL) {
1812		smb_shr_sa_setflag(val, si, SMB_SHRF_ABE);
1813		free(val);
1814	}
1815
1816	val = smb_shr_sa_getprop(opts, SHOPT_GUEST);
1817	if (val != NULL) {
1818		smb_shr_sa_setflag(val, si, SMB_SHRF_GUEST_OK);
1819		free(val);
1820	}
1821
1822	val = smb_shr_sa_getprop(opts, SHOPT_DFSROOT);
1823	if (val != NULL) {
1824		smb_shr_sa_setflag(val, si, SMB_SHRF_DFSROOT);
1825		free(val);
1826	}
1827
1828	val = smb_shr_sa_getprop(opts, SHOPT_CA);
1829	if (val != NULL) {
1830		smb_shr_sa_setflag(val, si, SMB_SHRF_CA);
1831		free(val);
1832	}
1833
1834	val = smb_shr_sa_getprop(opts, SHOPT_FSO);
1835	if (val != NULL) {
1836		smb_shr_sa_setflag(val, si, SMB_SHRF_FSO);
1837		free(val);
1838	}
1839
1840	val = smb_shr_sa_getprop(opts, SHOPT_QUOTAS);
1841	if (val != NULL) {
1842		/* Turn the flag on or off */
1843		smb_shr_sa_setflag(val, si, SMB_SHRF_QUOTAS);
1844		free(val);
1845	} else {
1846		/* Default for this is enabled. */
1847		si->shr_flags |= SMB_SHRF_QUOTAS;
1848	}
1849
1850	val = smb_shr_sa_getprop(opts, SHOPT_ENCRYPT);
1851	if (val != NULL) {
1852		smb_cfg_set_require(val, &si->shr_encrypt);
1853		free(val);
1854	}
1855
1856	val = smb_shr_sa_getprop(opts, SHOPT_CSC);
1857	if (val != NULL) {
1858		smb_shr_sa_csc_option(val, si);
1859		free(val);
1860	}
1861
1862	val = smb_shr_sa_getprop(opts, SHOPT_NONE);
1863	if (val != NULL) {
1864		(void) strlcpy(si->shr_access_none, val,
1865		    sizeof (si->shr_access_none));
1866		free(val);
1867		si->shr_flags |= SMB_SHRF_ACC_NONE;
1868	}
1869
1870	val = smb_shr_sa_getprop(opts, SHOPT_RO);
1871	if (val != NULL) {
1872		(void) strlcpy(si->shr_access_ro, val,
1873		    sizeof (si->shr_access_ro));
1874		free(val);
1875		si->shr_flags |= SMB_SHRF_ACC_RO;
1876	}
1877
1878	val = smb_shr_sa_getprop(opts, SHOPT_RW);
1879	if (val != NULL) {
1880		(void) strlcpy(si->shr_access_rw, val,
1881		    sizeof (si->shr_access_rw));
1882		free(val);
1883		si->shr_flags |= SMB_SHRF_ACC_RW;
1884	}
1885
1886	sa_free_derived_optionset(opts);
1887	return (NERR_Success);
1888}
1889
1890/*
1891 * Map a client-side caching (CSC) option to the appropriate share
1892 * flag.  Only one option is allowed; an error will be logged if
1893 * multiple options have been specified.  We don't need to do anything
1894 * about multiple values here because the SRVSVC will not recognize
1895 * a value containing multiple flags and will return the default value.
1896 *
1897 * If the option value is not recognized, it will be ignored: invalid
1898 * values will typically be caught and rejected by sharemgr.
1899 */
1900void
1901smb_shr_sa_csc_option(const char *value, smb_share_t *si)
1902{
1903	int i;
1904
1905	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1906		if (strcasecmp(value, cscopt[i].value) == 0) {
1907			si->shr_flags |= cscopt[i].flag;
1908			break;
1909		}
1910	}
1911
1912	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
1913	case 0:
1914	case SMB_SHRF_CSC_DISABLED:
1915	case SMB_SHRF_CSC_MANUAL:
1916	case SMB_SHRF_CSC_AUTO:
1917	case SMB_SHRF_CSC_VDO:
1918		break;
1919
1920	default:
1921		syslog(LOG_INFO, "csc option conflict: 0x%08x",
1922		    si->shr_flags & SMB_SHRF_CSC_MASK);
1923		break;
1924	}
1925}
1926
1927/*
1928 * Return the option name for the first CSC flag (there should be only
1929 * one) encountered in the share flags.
1930 */
1931char *
1932smb_shr_sa_csc_name(const smb_share_t *si)
1933{
1934	int i;
1935
1936	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1937		if (si->shr_flags & cscopt[i].flag)
1938			return (cscopt[i].value);
1939	}
1940
1941	return (NULL);
1942}
1943
1944/*
1945 * Takes the value of a boolean share property and set/clear the
1946 * specified flag based on the property's value.
1947 */
1948void
1949smb_shr_sa_setflag(const char *value, smb_share_t *si, uint32_t flag)
1950{
1951	if ((strcasecmp(value, "true") == 0) || (strcmp(value, "1") == 0))
1952		si->shr_flags |= flag;
1953	else
1954		si->shr_flags &= ~flag;
1955}
1956
1957/*
1958 * looks up sharemgr for the given share (resource) and loads
1959 * the definition into cache if lookup is successful
1960 */
1961static uint32_t
1962smb_shr_sa_loadbyname(char *sharename)
1963{
1964	sa_handle_t handle;
1965	sa_share_t share;
1966	sa_resource_t resource;
1967	uint32_t status;
1968
1969	if ((handle = smb_shr_sa_enter()) == NULL)
1970		return (NERR_InternalError);
1971
1972	resource = sa_find_resource(handle, sharename);
1973	if (resource == NULL) {
1974		smb_shr_sa_exit();
1975		return (NERR_NetNameNotFound);
1976	}
1977
1978	share = sa_get_resource_parent(resource);
1979	if (share == NULL) {
1980		smb_shr_sa_exit();
1981		return (NERR_InternalError);
1982	}
1983
1984	status = smb_shr_sa_load(share, resource);
1985
1986	smb_shr_sa_exit();
1987	return (status);
1988}
1989
1990/*
1991 * ============================================
1992 * Share publishing functions
1993 *
1994 * All the functions are private
1995 * ============================================
1996 */
1997
1998static void
1999smb_shr_publish(const char *sharename, const char *container)
2000{
2001	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
2002}
2003
2004static void
2005smb_shr_unpublish(const char *sharename, const char *container)
2006{
2007	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
2008}
2009
2010/*
2011 * In domain mode, put a share on the publisher queue.
2012 * This is a no-op if the smb service is in Workgroup mode.
2013 */
2014static void
2015smb_shr_publisher_queue(const char *sharename, const char *container, char op)
2016{
2017	smb_shr_pitem_t *item = NULL;
2018
2019	if (container == NULL || *container == '\0')
2020		return;
2021
2022	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
2023		return;
2024
2025	(void) mutex_lock(&ad_queue.spq_mtx);
2026	switch (ad_queue.spq_state) {
2027	case SMB_SHR_PQS_READY:
2028	case SMB_SHR_PQS_PUBLISHING:
2029		break;
2030	default:
2031		(void) mutex_unlock(&ad_queue.spq_mtx);
2032		return;
2033	}
2034	(void) mutex_unlock(&ad_queue.spq_mtx);
2035
2036	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
2037		return;
2038
2039	item->spi_op = op;
2040	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
2041	(void) strlcpy(item->spi_container, container,
2042	    sizeof (item->spi_container));
2043
2044	(void) mutex_lock(&ad_queue.spq_mtx);
2045	list_insert_tail(&ad_queue.spq_list, item);
2046	(void) cond_signal(&ad_queue.spq_cv);
2047	(void) mutex_unlock(&ad_queue.spq_mtx);
2048}
2049
2050/*
2051 * Publishing won't be activated if the smb service is running in
2052 * Workgroup mode.
2053 */
2054static int
2055smb_shr_publisher_start(void)
2056{
2057	pthread_t publish_thr;
2058	pthread_attr_t tattr;
2059	int rc;
2060
2061	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
2062		return (0);
2063
2064	(void) mutex_lock(&ad_queue.spq_mtx);
2065	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
2066		(void) mutex_unlock(&ad_queue.spq_mtx);
2067		errno = EINVAL;
2068		return (-1);
2069	}
2070
2071	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
2072	    offsetof(smb_shr_pitem_t, spi_lnd));
2073	ad_queue.spq_state = SMB_SHR_PQS_READY;
2074	(void) mutex_unlock(&ad_queue.spq_mtx);
2075
2076	(void) pthread_attr_init(&tattr);
2077	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
2078	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
2079	(void) pthread_attr_destroy(&tattr);
2080
2081	return (rc);
2082}
2083
2084static void
2085smb_shr_publisher_stop(void)
2086{
2087	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
2088		return;
2089
2090	(void) mutex_lock(&ad_queue.spq_mtx);
2091	switch (ad_queue.spq_state) {
2092	case SMB_SHR_PQS_READY:
2093	case SMB_SHR_PQS_PUBLISHING:
2094		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
2095		(void) cond_signal(&ad_queue.spq_cv);
2096		break;
2097	default:
2098		break;
2099	}
2100	(void) mutex_unlock(&ad_queue.spq_mtx);
2101}
2102
2103/*
2104 * This is the publisher daemon thread.  While running, the thread waits
2105 * on a conditional variable until notified that a share needs to be
2106 * [un]published or that the thread should be terminated.
2107 *
2108 * Entries may remain in the outgoing queue if the Active Directory
2109 * service is inaccessible, in which case the thread wakes up every 60
2110 * seconds to retry.
2111 */
2112/*ARGSUSED*/
2113static void *
2114smb_shr_publisher(void *arg)
2115{
2116	smb_ads_handle_t *ah;
2117	smb_shr_pitem_t *shr;
2118	list_t publist;
2119	timestruc_t pubretry;
2120	char hostname[MAXHOSTNAMELEN];
2121
2122	(void) mutex_lock(&ad_queue.spq_mtx);
2123	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
2124		(void) mutex_unlock(&ad_queue.spq_mtx);
2125		return (NULL);
2126	}
2127	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
2128	(void) mutex_unlock(&ad_queue.spq_mtx);
2129
2130	(void) smb_gethostname(hostname, MAXHOSTNAMELEN,
2131	    SMB_CASE_PRESERVE);
2132
2133	list_create(&publist, sizeof (smb_shr_pitem_t),
2134	    offsetof(smb_shr_pitem_t, spi_lnd));
2135
2136	for (;;) {
2137		(void) mutex_lock(&ad_queue.spq_mtx);
2138
2139		while (list_is_empty(&ad_queue.spq_list) &&
2140		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
2141			if (list_is_empty(&publist)) {
2142				(void) cond_wait(&ad_queue.spq_cv,
2143				    &ad_queue.spq_mtx);
2144			} else {
2145				pubretry.tv_sec = 60;
2146				pubretry.tv_nsec = 0;
2147				(void) cond_reltimedwait(&ad_queue.spq_cv,
2148				    &ad_queue.spq_mtx, &pubretry);
2149				break;
2150			}
2151		}
2152
2153		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
2154			(void) mutex_unlock(&ad_queue.spq_mtx);
2155			break;
2156		}
2157
2158		/*
2159		 * Transfer queued items to the local list so that
2160		 * the mutex can be released.
2161		 */
2162		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
2163			list_remove(&ad_queue.spq_list, shr);
2164			list_insert_tail(&publist, shr);
2165		}
2166
2167		(void) mutex_unlock(&ad_queue.spq_mtx);
2168
2169		if ((ah = smb_ads_open()) != NULL) {
2170			smb_shr_publisher_send(ah, &publist, hostname);
2171			smb_ads_close(ah);
2172		}
2173	}
2174
2175	(void) mutex_lock(&ad_queue.spq_mtx);
2176	smb_shr_publisher_flush(&ad_queue.spq_list);
2177	list_destroy(&ad_queue.spq_list);
2178	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
2179	(void) mutex_unlock(&ad_queue.spq_mtx);
2180
2181	smb_shr_publisher_flush(&publist);
2182	list_destroy(&publist);
2183	return (NULL);
2184}
2185
2186/*
2187 * Remove items from the specified queue and [un]publish them.
2188 */
2189static void
2190smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
2191{
2192	smb_shr_pitem_t *shr;
2193
2194	while ((shr = list_head(publist)) != NULL) {
2195		(void) mutex_lock(&ad_queue.spq_mtx);
2196		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
2197			(void) mutex_unlock(&ad_queue.spq_mtx);
2198			return;
2199		}
2200		(void) mutex_unlock(&ad_queue.spq_mtx);
2201
2202		list_remove(publist, shr);
2203
2204		if (shr->spi_op == SMB_SHR_PUBLISH)
2205			(void) smb_ads_publish_share(ah, shr->spi_name,
2206			    NULL, shr->spi_container, host);
2207		else
2208			(void) smb_ads_remove_share(ah, shr->spi_name,
2209			    NULL, shr->spi_container, host);
2210
2211		free(shr);
2212	}
2213}
2214
2215/*
2216 * Flush all remaining items from the specified list/queue.
2217 */
2218static void
2219smb_shr_publisher_flush(list_t *lst)
2220{
2221	smb_shr_pitem_t *shr;
2222
2223	while ((shr = list_head(lst)) != NULL) {
2224		list_remove(lst, shr);
2225		free(shr);
2226	}
2227}
2228
2229/*
2230 * If the share path refers to a ZFS file system, add the
2231 * .zfs/shares/<share> object and add or remove the special
2232 * directory and file telling clients about quota support.
2233 */
2234static void
2235smb_shr_zfs_add(smb_share_t *si)
2236{
2237	libzfs_handle_t *libhd;
2238	zfs_handle_t *zfshd;
2239	int ret;
2240	char buf[MAXPATHLEN];	/* dataset or mountpoint */
2241
2242	if ((libhd = libzfs_init()) == NULL)
2243		return;
2244
2245	if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
2246		libzfs_fini(libhd);
2247		return;
2248	}
2249
2250	if ((zfshd = zfs_open(libhd, buf, ZFS_TYPE_FILESYSTEM)) == NULL) {
2251		libzfs_fini(libhd);
2252		return;
2253	}
2254
2255	errno = 0;
2256	ret = zfs_smb_acl_add(libhd, buf, si->shr_path, si->shr_name);
2257	if (ret != 0 && errno != EAGAIN && errno != EEXIST)
2258		syslog(LOG_INFO, "share: failed to add ACL object: %s: %s\n",
2259		    si->shr_name, strerror(errno));
2260
2261	ret = zfs_prop_get(zfshd, ZFS_PROP_MOUNTPOINT,
2262	    buf, MAXPATHLEN, NULL, NULL, 0, B_FALSE);
2263	if (ret != 0) {
2264		syslog(LOG_INFO, "share: failed to get mountpoint: "
2265		    "%s\n", si->shr_name);
2266	} else {
2267		if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0) {
2268			smb_quota_add_fs(buf);
2269		} else {
2270			smb_quota_remove_fs(buf);
2271		}
2272	}
2273
2274	zfs_close(zfshd);
2275	libzfs_fini(libhd);
2276}
2277
2278/*
2279 * If the share path refers to a ZFS file system, remove the
2280 * .zfs/shares/<share> object.
2281 */
2282static void
2283smb_shr_zfs_remove(smb_share_t *si)
2284{
2285	libzfs_handle_t *libhd;
2286	int ret;
2287	char buf[MAXPATHLEN];	/* dataset or mountpoint */
2288
2289	if ((libhd = libzfs_init()) == NULL)
2290		return;
2291
2292	if (smb_getdataset(libhd, si->shr_path, buf, MAXPATHLEN) != 0) {
2293		libzfs_fini(libhd);
2294		return;
2295	}
2296
2297	errno = 0;
2298	ret = zfs_smb_acl_remove(libhd, buf, si->shr_path, si->shr_name);
2299	if (ret != 0 && errno != EAGAIN)
2300		syslog(LOG_INFO, "share: failed to remove ACL object: %s: %s\n",
2301		    si->shr_name, strerror(errno));
2302
2303	/*
2304	 * We could remove the quotas directory here, but that adds
2305	 * significantly to the time required for a zpool export,
2306	 * so just leave it here and fixup when we share next.
2307	 */
2308
2309	libzfs_fini(libhd);
2310}
2311
2312/*
2313 * If the share path refers to a ZFS file system, rename the
2314 * .zfs/shares/<share> object.
2315 */
2316static void
2317smb_shr_zfs_rename(smb_share_t *from, smb_share_t *to)
2318{
2319	libzfs_handle_t *libhd;
2320	zfs_handle_t *zfshd;
2321	int ret;
2322	char dataset[MAXPATHLEN];
2323
2324	if ((libhd = libzfs_init()) == NULL)
2325		return;
2326
2327	if (smb_getdataset(libhd, from->shr_path, dataset, MAXPATHLEN) != 0) {
2328		libzfs_fini(libhd);
2329		return;
2330	}
2331
2332	if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_FILESYSTEM)) == NULL) {
2333		libzfs_fini(libhd);
2334		return;
2335	}
2336
2337	errno = 0;
2338	ret = zfs_smb_acl_rename(libhd, dataset, from->shr_path,
2339	    from->shr_name, to->shr_name);
2340	if (ret != 0 && errno != EAGAIN)
2341		syslog(LOG_INFO, "share: failed to rename ACL object: %s: %s\n",
2342		    from->shr_name, strerror(errno));
2343
2344	zfs_close(zfshd);
2345	libzfs_fini(libhd);
2346}
2347
2348/*
2349 * Enable all privileges in the inheritable set to execute command.
2350 */
2351static int
2352smb_shr_enable_all_privs(void)
2353{
2354	priv_set_t *pset;
2355
2356	pset = priv_allocset();
2357	if (pset == NULL)
2358		return (-1);
2359
2360	if (getppriv(PRIV_LIMIT, pset)) {
2361		priv_freeset(pset);
2362		return (-1);
2363	}
2364
2365	if (setppriv(PRIV_ON, PRIV_INHERITABLE, pset)) {
2366		priv_freeset(pset);
2367		return (-1);
2368	}
2369
2370	priv_freeset(pset);
2371	return (0);
2372}
2373
2374/*
2375 * Tokenizes the command string and returns the list of tokens in an array.
2376 *
2377 * Returns NULL if there are no tokens.
2378 */
2379static char **
2380smb_shr_tokenize_cmd(char *cmdstr)
2381{
2382	char *cmd, *buf, *bp, *value;
2383	char **argv, **ap;
2384	int argc, i;
2385
2386	if (cmdstr == NULL || *cmdstr == '\0')
2387		return (NULL);
2388
2389	if ((buf = malloc(MAXPATHLEN)) == NULL)
2390		return (NULL);
2391
2392	(void) strlcpy(buf, cmdstr, MAXPATHLEN);
2393
2394	for (argc = 2, bp = cmdstr; *bp != '\0'; ++bp)
2395		if (*bp == ' ')
2396			++argc;
2397
2398	if ((argv = calloc(argc, sizeof (char *))) == NULL) {
2399		free(buf);
2400		return (NULL);
2401	}
2402
2403	ap = argv;
2404	for (bp = buf, i = 0; i < argc; ++i) {
2405		do {
2406			if ((value = strsep(&bp, " ")) == NULL)
2407				break;
2408		} while (*value == '\0');
2409
2410		if (value == NULL)
2411			break;
2412
2413		*ap++ = value;
2414	}
2415
2416	/* get the filename of the command from the path */
2417	if ((cmd = strrchr(argv[0], '/')) != NULL)
2418		(void) strlcpy(argv[0], ++cmd, strlen(argv[0]));
2419
2420	return (argv);
2421}
2422
2423/*
2424 * Expands the command string for the following substitution tokens:
2425 *
2426 * %U - Windows username
2427 * %D - Name of the domain or workgroup of %U
2428 * %h - The server hostname
2429 * %M - The client hostname
2430 * %L - The server NetBIOS name
2431 * %m - The client NetBIOS name. This option is only valid for NetBIOS
2432 *      connections (port 139).
2433 * %I - The IP address of the client machine
2434 * %i - The local IP address to which the client is connected
2435 * %S - The name of the share
2436 * %P - The root directory of the share
2437 * %u - The UID of the Unix user
2438 *
2439 * Returns 0 on success.  Otherwise -1.
2440 */
2441static int
2442smb_shr_expand_subs(char **cmd_toks, smb_share_t *si, smb_shr_execinfo_t *subs)
2443{
2444	char *fmt, *sub_chr, *ptr;
2445	boolean_t unknown;
2446	char hostname[MAXHOSTNAMELEN];
2447	char ip_str[INET6_ADDRSTRLEN];
2448	char name[SMB_PI_MAX_HOST];
2449	smb_wchar_t wbuf[SMB_PI_MAX_HOST];
2450	int i;
2451
2452	if (cmd_toks == NULL || *cmd_toks == NULL)
2453		return (-1);
2454
2455	for (i = 1; cmd_toks[i]; i++) {
2456		fmt = cmd_toks[i];
2457		if (*fmt == '%') {
2458			sub_chr = fmt + 1;
2459			unknown = B_FALSE;
2460
2461			switch (*sub_chr) {
2462			case 'U':
2463				ptr = strdup(subs->e_winname);
2464				break;
2465			case 'D':
2466				ptr = strdup(subs->e_userdom);
2467				break;
2468			case 'h':
2469				if (gethostname(hostname, MAXHOSTNAMELEN) != 0)
2470					unknown = B_TRUE;
2471				else
2472					ptr = strdup(hostname);
2473				break;
2474			case 'M':
2475				if (smb_getnameinfo(&subs->e_cli_ipaddr,
2476				    hostname, sizeof (hostname), 0) != 0)
2477					unknown = B_TRUE;
2478				else
2479					ptr = strdup(hostname);
2480				break;
2481			case 'L':
2482				if (smb_getnetbiosname(hostname,
2483				    NETBIOS_NAME_SZ) != 0)
2484					unknown = B_TRUE;
2485				else
2486					ptr = strdup(hostname);
2487				break;
2488			case 'm':
2489				if (*subs->e_cli_netbiosname == '\0')
2490					unknown = B_TRUE;
2491				else {
2492					(void) smb_mbstowcs(wbuf,
2493					    subs->e_cli_netbiosname,
2494					    SMB_PI_MAX_HOST - 1);
2495
2496					if (ucstooem(name, wbuf,
2497					    SMB_PI_MAX_HOST, OEM_CPG_850) == 0)
2498						(void) strlcpy(name,
2499						    subs->e_cli_netbiosname,
2500						    SMB_PI_MAX_HOST);
2501
2502					ptr = strdup(name);
2503				}
2504				break;
2505			case 'I':
2506				if (smb_inet_ntop(&subs->e_cli_ipaddr, ip_str,
2507				    SMB_IPSTRLEN(subs->e_cli_ipaddr.a_family))
2508				    != NULL)
2509					ptr = strdup(ip_str);
2510				else
2511					unknown = B_TRUE;
2512				break;
2513			case 'i':
2514				if (smb_inet_ntop(&subs->e_srv_ipaddr, ip_str,
2515				    SMB_IPSTRLEN(subs->e_srv_ipaddr.a_family))
2516				    != NULL)
2517					ptr = strdup(ip_str);
2518				else
2519					unknown = B_TRUE;
2520				break;
2521			case 'S':
2522				ptr = strdup(si->shr_name);
2523				break;
2524			case 'P':
2525				ptr = strdup(si->shr_path);
2526				break;
2527			case 'u':
2528				(void) snprintf(name, sizeof (name), "%u",
2529				    subs->e_uid);
2530				ptr = strdup(name);
2531				break;
2532			default:
2533				/* unknown sub char */
2534				unknown = B_TRUE;
2535				break;
2536			}
2537
2538			if (unknown)
2539				ptr = strdup("");
2540
2541		} else  /* first char of cmd's arg is not '%' char */
2542			ptr = strdup("");
2543
2544		cmd_toks[i] = ptr;
2545
2546		if (ptr == NULL) {
2547			for (i = 1; cmd_toks[i]; i++)
2548				free(cmd_toks[i]);
2549
2550			return (-1);
2551		}
2552	}
2553
2554	return (0);
2555}
2556
2557/*ARGSUSED*/
2558static void
2559smb_shr_sig_abnormal_term(int sig_val)
2560{
2561	/*
2562	 * Calling _exit() prevents parent process from getting SIGTERM/SIGINT
2563	 * signal.
2564	 */
2565	_exit(-1);
2566}
2567
2568/*ARGSUSED*/
2569static void
2570smb_shr_sig_child(int sig_val)
2571{
2572	/*
2573	 * Catch the signal and allow the exit status of the child process
2574	 * to be available for reaping.
2575	 */
2576}
2577
2578/*
2579 * This is a temporary function which converts the given smb_share_t
2580 * structure to the nvlist format that will be provided by libsharev2
2581 */
2582static int
2583smb_shr_encode(smb_share_t *si, nvlist_t **nvlist)
2584{
2585	nvlist_t *list;
2586	nvlist_t *share;
2587	nvlist_t *smb;
2588	char *csc;
2589	int rc = 0;
2590
2591	*nvlist = NULL;
2592
2593	if ((rc = nvlist_alloc(&list, NV_UNIQUE_NAME, 0)) != 0)
2594		return (rc);
2595
2596	if ((rc = nvlist_alloc(&share, NV_UNIQUE_NAME, 0)) != 0) {
2597		nvlist_free(list);
2598		return (rc);
2599	}
2600
2601	if ((rc = nvlist_alloc(&smb, NV_UNIQUE_NAME, 0)) != 0) {
2602		nvlist_free(share);
2603		nvlist_free(list);
2604		return (rc);
2605	}
2606
2607	/* global share properties */
2608	rc |= nvlist_add_string(share, "name", si->shr_name);
2609	rc |= nvlist_add_string(share, "path", si->shr_path);
2610	rc |= nvlist_add_string(share, "desc", si->shr_cmnt);
2611
2612	/* smb protocol properties */
2613	rc = nvlist_add_string(smb, SHOPT_AD_CONTAINER, si->shr_container);
2614	if ((si->shr_flags & SMB_SHRF_ACC_NONE) != 0)
2615		rc |= nvlist_add_string(smb, SHOPT_NONE, si->shr_access_none);
2616	if ((si->shr_flags & SMB_SHRF_ACC_RO) != 0)
2617		rc |= nvlist_add_string(smb, SHOPT_RO, si->shr_access_ro);
2618	if ((si->shr_flags & SMB_SHRF_ACC_RW) != 0)
2619		rc |= nvlist_add_string(smb, SHOPT_RW, si->shr_access_rw);
2620
2621	if ((si->shr_flags & SMB_SHRF_ABE) != 0)
2622		rc |= nvlist_add_string(smb, SHOPT_ABE, "true");
2623	if ((si->shr_flags & SMB_SHRF_CATIA) != 0)
2624		rc |= nvlist_add_string(smb, SHOPT_CATIA, "true");
2625	if ((si->shr_flags & SMB_SHRF_GUEST_OK) != 0)
2626		rc |= nvlist_add_string(smb, SHOPT_GUEST, "true");
2627	if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0)
2628		rc |= nvlist_add_string(smb, SHOPT_DFSROOT, "true");
2629	if ((si->shr_flags & SMB_SHRF_CA) != 0)
2630		rc |= nvlist_add_string(smb, SHOPT_CA, "true");
2631	if ((si->shr_flags & SMB_SHRF_FSO) != 0)
2632		rc |= nvlist_add_string(smb, SHOPT_FSO, "true");
2633	if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0)
2634		rc |= nvlist_add_string(smb, SHOPT_QUOTAS, "true");
2635
2636	if (si->shr_encrypt == SMB_CONFIG_REQUIRED)
2637		rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "required");
2638	else if (si->shr_encrypt == SMB_CONFIG_ENABLED)
2639		rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "enabled");
2640	else
2641		rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "disabled");
2642
2643	if ((si->shr_flags & SMB_SHRF_AUTOHOME) != 0) {
2644		rc |= nvlist_add_string(smb, SHOPT_AUTOHOME, "true");
2645		rc |= nvlist_add_uint32(smb, "uid", si->shr_uid);
2646		rc |= nvlist_add_uint32(smb, "gid", si->shr_gid);
2647	}
2648
2649	if ((csc = smb_shr_sa_csc_name(si)) != NULL)
2650		rc |= nvlist_add_string(smb, SHOPT_CSC, csc);
2651
2652	rc |= nvlist_add_uint32(smb, "type", si->shr_type);
2653
2654	rc |= nvlist_add_nvlist(share, "smb", smb);
2655	rc |= nvlist_add_nvlist(list, si->shr_name, share);
2656
2657	nvlist_free(share);
2658	nvlist_free(smb);
2659
2660	if (rc != 0)
2661		nvlist_free(list);
2662	else
2663		*nvlist = list;
2664
2665	return (rc);
2666}
2667