xref: /illumos-gate/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c (revision 47842382d52f28aa3173aa6b511781c322ccb6a2)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
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 
40 #include <smbsrv/libsmb.h>
41 #include <smbsrv/libsmbns.h>
42 #include <smbsrv/libmlsvc.h>
43 
44 #include <smbsrv/lm.h>
45 #include <smbsrv/smb_share.h>
46 #include <smbsrv/cifs.h>
47 #include <smbsrv/nterror.h>
48 
49 #define	SMB_SHR_ERROR_THRESHOLD		3
50 
51 #define	SMB_SHR_CSC_BUFSZ		64
52 
53 /*
54  * Cache functions and vars
55  */
56 #define	SMB_SHR_HTAB_SZ			1024
57 
58 /*
59  * Cache handle
60  *
61  * Shares cache is a hash table.
62  *
63  * sc_cache		pointer to hash table handle
64  * sc_cache_lck		synchronize cache read/write accesses
65  * sc_state		cache state machine values
66  * sc_nops		number of inflight/pending cache operations
67  * sc_mtx		protects handle fields
68  */
69 typedef struct smb_shr_cache {
70 	HT_HANDLE	*sc_cache;
71 	rwlock_t	sc_cache_lck;
72 	mutex_t		sc_mtx;
73 	cond_t		sc_cv;
74 	uint32_t	sc_state;
75 	uint32_t	sc_nops;
76 } smb_shr_cache_t;
77 
78 /*
79  * Cache states
80  */
81 #define	SMB_SHR_CACHE_STATE_NONE	0
82 #define	SMB_SHR_CACHE_STATE_CREATED	1
83 #define	SMB_SHR_CACHE_STATE_DESTROYING	2
84 
85 /*
86  * Cache lock modes
87  */
88 #define	SMB_SHR_CACHE_RDLOCK	0
89 #define	SMB_SHR_CACHE_WRLOCK	1
90 
91 static smb_shr_cache_t smb_shr_cache;
92 
93 static uint32_t smb_shr_cache_create(void);
94 static void smb_shr_cache_destroy(void);
95 static uint32_t smb_shr_cache_lock(int);
96 static void smb_shr_cache_unlock(void);
97 static int smb_shr_cache_count(void);
98 static smb_share_t *smb_shr_cache_iterate(smb_shriter_t *);
99 
100 static smb_share_t *smb_shr_cache_findent(char *);
101 static uint32_t smb_shr_cache_addent(smb_share_t *);
102 static void smb_shr_cache_delent(char *);
103 static void smb_shr_cache_freent(HT_ITEM *);
104 
105 /*
106  * sharemgr functions
107  */
108 static void *smb_shr_sa_loadall(void *);
109 static void smb_shr_sa_loadgrp(sa_group_t);
110 static uint32_t smb_shr_sa_load(sa_share_t, sa_resource_t);
111 static uint32_t smb_shr_sa_loadbyname(char *);
112 static uint32_t smb_shr_sa_get(sa_share_t, sa_resource_t, smb_share_t *);
113 
114 /*
115  * share publishing
116  */
117 #define	SMB_SHR_PUBLISH		0
118 #define	SMB_SHR_UNPUBLISH	1
119 
120 typedef struct smb_shr_pitem {
121 	list_node_t	spi_lnd;
122 	char		spi_name[MAXNAMELEN];
123 	char		spi_container[MAXPATHLEN];
124 	char		spi_op;
125 } smb_shr_pitem_t;
126 
127 /*
128  * publish queue states
129  */
130 #define	SMB_SHR_PQS_NOQUEUE	0
131 #define	SMB_SHR_PQS_READY	1	/* the queue is ready */
132 #define	SMB_SHR_PQS_PUBLISHING	2	/* publisher thread is running */
133 #define	SMB_SHR_PQS_STOPPING	3
134 
135 /*
136  * share publishing queue
137  */
138 typedef struct smb_shr_pqueue {
139 	list_t		spq_list;
140 	mutex_t		spq_mtx;
141 	cond_t		spq_cv;
142 	uint32_t	spq_state;
143 } smb_shr_pqueue_t;
144 
145 static smb_shr_pqueue_t ad_queue;
146 
147 static int smb_shr_publisher_start(void);
148 static void smb_shr_publisher_stop(void);
149 static void smb_shr_publisher_send(smb_ads_handle_t *, list_t *, const char *);
150 static void smb_shr_publisher_queue(const char *, const char *, char);
151 static void *smb_shr_publisher(void *);
152 static void smb_shr_publisher_flush(list_t *);
153 static void smb_shr_publish(const char *, const char *);
154 static void smb_shr_unpublish(const char *, const char *);
155 
156 /*
157  * Utility/helper functions
158  */
159 static uint32_t smb_shr_lookup(char *, smb_share_t *);
160 static uint32_t smb_shr_addipc(void);
161 static void smb_shr_set_oemname(smb_share_t *);
162 
163 
164 /*
165  * libshare handle and synchronization
166  */
167 typedef struct smb_sa_handle {
168 	sa_handle_t	sa_handle;
169 	mutex_t		sa_mtx;
170 	boolean_t	sa_in_service;
171 } smb_sa_handle_t;
172 
173 static smb_sa_handle_t smb_sa_handle;
174 
175 /*
176  * Creates and initializes the cache and starts the publisher
177  * thread.
178  */
179 int
180 smb_shr_start(void)
181 {
182 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
183 	smb_sa_handle.sa_in_service = B_TRUE;
184 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
185 
186 	if (smb_shr_cache_create() != NERR_Success)
187 		return (ENOMEM);
188 
189 	if (smb_shr_addipc() != NERR_Success)
190 		return (ENOMEM);
191 
192 	return (smb_shr_publisher_start());
193 }
194 
195 void
196 smb_shr_stop(void)
197 {
198 	smb_shr_cache_destroy();
199 	smb_shr_publisher_stop();
200 
201 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
202 	smb_sa_handle.sa_in_service = B_FALSE;
203 
204 	if (smb_sa_handle.sa_handle != NULL) {
205 		sa_fini(smb_sa_handle.sa_handle);
206 		smb_sa_handle.sa_handle = NULL;
207 	}
208 
209 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
210 }
211 
212 /*
213  * Get a handle and exclusive access to the libshare API.
214  */
215 sa_handle_t
216 smb_shr_sa_enter(void)
217 {
218 	(void) mutex_lock(&smb_sa_handle.sa_mtx);
219 	if (!smb_sa_handle.sa_in_service) {
220 		(void) mutex_unlock(&smb_sa_handle.sa_mtx);
221 		return (NULL);
222 	}
223 
224 	if (smb_sa_handle.sa_handle == NULL) {
225 		smb_sa_handle.sa_handle = sa_init(SA_INIT_SHARE_API);
226 		if (smb_sa_handle.sa_handle == NULL) {
227 			syslog(LOG_ERR, "share: failed to get libshare handle");
228 			(void) mutex_unlock(&smb_sa_handle.sa_mtx);
229 			return (NULL);
230 		}
231 	}
232 
233 	return (smb_sa_handle.sa_handle);
234 }
235 
236 /*
237  * Release exclusive access to the libshare API.
238  */
239 void
240 smb_shr_sa_exit(void)
241 {
242 	(void) mutex_unlock(&smb_sa_handle.sa_mtx);
243 }
244 
245 /*
246  * Launches a thread to populate the share cache by share information
247  * stored in sharemgr
248  */
249 int
250 smb_shr_load(void)
251 {
252 	pthread_t load_thr;
253 	pthread_attr_t tattr;
254 	int rc;
255 
256 	(void) pthread_attr_init(&tattr);
257 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
258 	rc = pthread_create(&load_thr, &tattr, smb_shr_sa_loadall, 0);
259 	(void) pthread_attr_destroy(&tattr);
260 
261 	return (rc);
262 }
263 
264 /*
265  * Return the total number of shares
266  */
267 int
268 smb_shr_count(void)
269 {
270 	int n_shares = 0;
271 
272 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
273 		n_shares = smb_shr_cache_count();
274 		smb_shr_cache_unlock();
275 	}
276 
277 	return (n_shares);
278 }
279 
280 /*
281  * smb_shr_iterinit
282  *
283  * Initialize given iterator for traversing hash table.
284  */
285 void
286 smb_shr_iterinit(smb_shriter_t *shi)
287 {
288 	bzero(shi, sizeof (smb_shriter_t));
289 	shi->si_first = B_TRUE;
290 }
291 
292 /*
293  * smb_shr_iterate
294  *
295  * Iterate on the shares in the hash table. The iterator must be initialized
296  * before the first iteration. On subsequent calls, the iterator must be
297  * passed unchanged.
298  *
299  * Returns NULL on failure or when all shares are visited, otherwise
300  * returns information of visited share.
301  */
302 smb_share_t *
303 smb_shr_iterate(smb_shriter_t *shi)
304 {
305 	smb_share_t *share = NULL;
306 	smb_share_t *cached_si;
307 
308 	if (shi == NULL)
309 		return (NULL);
310 
311 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
312 		if ((cached_si = smb_shr_cache_iterate(shi)) != NULL) {
313 			share = &shi->si_share;
314 			bcopy(cached_si, share, sizeof (smb_share_t));
315 		}
316 		smb_shr_cache_unlock();
317 	}
318 
319 	return (share);
320 }
321 
322 /*
323  * Adds the given share to cache, publishes the share in ADS
324  * if it has an AD container, calls kernel to take a hold on
325  * the shared file system. If it can't take a hold on the
326  * shared file system, it's either because shared directory
327  * does not exist or some other error has occurred, in any
328  * case the share is removed from the cache.
329  *
330  * If the specified share is an autohome share which already
331  * exists in the cache, just increments the reference count.
332  */
333 uint32_t
334 smb_shr_add(smb_share_t *si)
335 {
336 	smb_share_t *cached_si;
337 	uint32_t status;
338 	int rc;
339 
340 	assert(si != NULL);
341 
342 	if (!smb_shr_chkname(si->shr_name))
343 		return (ERROR_INVALID_NAME);
344 
345 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
346 		return (NERR_InternalError);
347 
348 	cached_si = smb_shr_cache_findent(si->shr_name);
349 	if (cached_si) {
350 		if (si->shr_flags & SMB_SHRF_AUTOHOME) {
351 			cached_si->shr_refcnt++;
352 			status = NERR_Success;
353 		} else {
354 			status = NERR_DuplicateShare;
355 		}
356 		smb_shr_cache_unlock();
357 		return (status);
358 	}
359 
360 	if ((status = smb_shr_cache_addent(si)) != NERR_Success) {
361 		smb_shr_cache_unlock();
362 		return (status);
363 	}
364 
365 	/* don't hold the lock across door call */
366 	smb_shr_cache_unlock();
367 
368 	/* call kernel to take a hold on the shared file system */
369 	rc = mlsvc_set_share(SMB_SHROP_ADD, si->shr_path, si->shr_name);
370 
371 	if (rc == 0) {
372 		smb_shr_publish(si->shr_name, si->shr_container);
373 		return (NERR_Success);
374 	}
375 
376 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
377 		smb_shr_cache_delent(si->shr_name);
378 		smb_shr_cache_unlock();
379 	}
380 
381 	/*
382 	 * rc == ENOENT means the shared directory doesn't exist
383 	 */
384 	return ((rc == ENOENT) ? NERR_UnknownDevDir : NERR_InternalError);
385 }
386 
387 /*
388  * Removes the specified share from cache, removes it from AD
389  * if it has an AD container, and calls the kernel to release
390  * the hold on the shared file system.
391  *
392  * If this is an autohome share then decrement the reference
393  * count. If it reaches 0 then it proceeds with removing steps.
394  */
395 uint32_t
396 smb_shr_remove(char *sharename)
397 {
398 	smb_share_t *si;
399 	char path[MAXPATHLEN];
400 	char container[MAXPATHLEN];
401 
402 	assert(sharename != NULL);
403 
404 	if (!smb_shr_chkname(sharename))
405 		return (ERROR_INVALID_NAME);
406 
407 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
408 		return (NERR_InternalError);
409 
410 	if ((si = smb_shr_cache_findent(sharename)) == NULL) {
411 		smb_shr_cache_unlock();
412 		return (NERR_NetNameNotFound);
413 	}
414 
415 	if (si->shr_type & STYPE_IPC) {
416 		/* IPC$ share cannot be removed */
417 		smb_shr_cache_unlock();
418 		return (ERROR_ACCESS_DENIED);
419 	}
420 
421 	if (si->shr_flags & SMB_SHRF_AUTOHOME) {
422 		if ((--si->shr_refcnt) > 0) {
423 			smb_shr_cache_unlock();
424 			return (NERR_Success);
425 		}
426 	}
427 
428 	(void) strlcpy(path, si->shr_path, sizeof (path));
429 	(void) strlcpy(container, si->shr_container, sizeof (container));
430 	smb_shr_cache_delent(sharename);
431 	smb_shr_cache_unlock();
432 
433 	smb_shr_unpublish(sharename, container);
434 
435 	/* call kernel to release the hold on the shared file system */
436 	(void) mlsvc_set_share(SMB_SHROP_DELETE, path, sharename);
437 
438 	return (NERR_Success);
439 }
440 
441 /*
442  * Rename a share. Check that the current name exists and the new name
443  * doesn't exist. The rename is performed by deleting the current share
444  * definition and creating a new share with the new name.
445  */
446 uint32_t
447 smb_shr_rename(char *from_name, char *to_name)
448 {
449 	smb_share_t *from_si;
450 	smb_share_t to_si;
451 	uint32_t status;
452 
453 	assert((from_name != NULL) && (to_name != NULL));
454 
455 	if (!smb_shr_chkname(from_name) || !smb_shr_chkname(to_name))
456 		return (ERROR_INVALID_NAME);
457 
458 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
459 		return (NERR_InternalError);
460 
461 	if ((from_si = smb_shr_cache_findent(from_name)) == NULL) {
462 		smb_shr_cache_unlock();
463 		return (NERR_NetNameNotFound);
464 	}
465 
466 	if (from_si->shr_type & STYPE_IPC) {
467 		/* IPC$ share cannot be renamed */
468 		smb_shr_cache_unlock();
469 		return (ERROR_ACCESS_DENIED);
470 	}
471 
472 	if (smb_shr_cache_findent(to_name) != NULL) {
473 		smb_shr_cache_unlock();
474 		return (NERR_DuplicateShare);
475 	}
476 
477 	bcopy(from_si, &to_si, sizeof (smb_share_t));
478 	(void) strlcpy(to_si.shr_name, to_name, sizeof (to_si.shr_name));
479 
480 	if ((status = smb_shr_cache_addent(&to_si)) != NERR_Success) {
481 		smb_shr_cache_unlock();
482 		return (status);
483 	}
484 
485 	smb_shr_cache_delent(from_name);
486 	smb_shr_cache_unlock();
487 
488 	smb_shr_unpublish(from_name, to_si.shr_container);
489 	smb_shr_publish(to_name, to_si.shr_container);
490 
491 	return (NERR_Success);
492 }
493 
494 /*
495  * Load the information for the specified share into the supplied share
496  * info structure.
497  *
498  * First looks up the cache to see if the specified share exists, if there
499  * is a miss then it looks up sharemgr.
500  */
501 uint32_t
502 smb_shr_get(char *sharename, smb_share_t *si)
503 {
504 	uint32_t status;
505 
506 	if (sharename == NULL || *sharename == '\0')
507 		return (NERR_NetNameNotFound);
508 
509 	if ((status = smb_shr_lookup(sharename, si)) == NERR_Success)
510 		return (status);
511 
512 	if ((status = smb_shr_sa_loadbyname(sharename)) == NERR_Success)
513 		status = smb_shr_lookup(sharename, si);
514 
515 	return (status);
516 }
517 
518 /*
519  * Modifies an existing share. Properties that can be modified are:
520  *
521  *   o comment
522  *   o AD container
523  *   o host access
524  */
525 uint32_t
526 smb_shr_modify(smb_share_t *new_si)
527 {
528 	smb_share_t *si;
529 	boolean_t adc_changed = B_FALSE;
530 	char old_container[MAXPATHLEN];
531 	uint32_t cscopt;
532 	uint32_t access;
533 
534 	assert(new_si != NULL);
535 
536 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) != NERR_Success)
537 		return (NERR_InternalError);
538 
539 	if ((si = smb_shr_cache_findent(new_si->shr_name)) == NULL) {
540 		smb_shr_cache_unlock();
541 		return (NERR_NetNameNotFound);
542 	}
543 
544 	if (si->shr_type & STYPE_IPC) {
545 		/* IPC$ share cannot be modified */
546 		smb_shr_cache_unlock();
547 		return (ERROR_ACCESS_DENIED);
548 	}
549 
550 	(void) strlcpy(si->shr_cmnt, new_si->shr_cmnt, sizeof (si->shr_cmnt));
551 
552 	adc_changed = (strcmp(new_si->shr_container, si->shr_container) != 0);
553 	if (adc_changed) {
554 		/* save current container - needed for unpublishing */
555 		(void) strlcpy(old_container, si->shr_container,
556 		    sizeof (old_container));
557 		(void) strlcpy(si->shr_container, new_si->shr_container,
558 		    sizeof (si->shr_container));
559 	}
560 
561 	cscopt = (new_si->shr_flags & SMB_SHRF_CSC_MASK);
562 	si->shr_flags &= ~SMB_SHRF_CSC_MASK;
563 	si->shr_flags |= cscopt;
564 
565 	access = (new_si->shr_flags & SMB_SHRF_ACC_ALL);
566 	si->shr_flags &= ~SMB_SHRF_ACC_ALL;
567 	si->shr_flags |= access;
568 
569 	if (access & SMB_SHRF_ACC_NONE)
570 		(void) strlcpy(si->shr_access_none, new_si->shr_access_none,
571 		    sizeof (si->shr_access_none));
572 
573 	if (access & SMB_SHRF_ACC_RO)
574 		(void) strlcpy(si->shr_access_ro, new_si->shr_access_ro,
575 		    sizeof (si->shr_access_ro));
576 
577 	if (access & SMB_SHRF_ACC_RW)
578 		(void) strlcpy(si->shr_access_rw, new_si->shr_access_rw,
579 		    sizeof (si->shr_access_rw));
580 
581 	smb_shr_cache_unlock();
582 
583 	if (adc_changed) {
584 		smb_shr_unpublish(new_si->shr_name, old_container);
585 		smb_shr_publish(new_si->shr_name, new_si->shr_container);
586 	}
587 
588 	return (NERR_Success);
589 }
590 
591 /*
592  * smb_shr_exists
593  *
594  * Returns B_TRUE if the share exists. Otherwise returns B_FALSE
595  */
596 boolean_t
597 smb_shr_exists(char *sharename)
598 {
599 	boolean_t exists = B_FALSE;
600 
601 	if (sharename == NULL || *sharename == '\0')
602 		return (B_FALSE);
603 
604 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
605 		exists = (smb_shr_cache_findent(sharename) != NULL);
606 		smb_shr_cache_unlock();
607 	}
608 
609 	return (exists);
610 }
611 
612 /*
613  * If the shared directory does not begin with a /, one will be
614  * inserted as a prefix. If ipaddr is not zero, then also return
615  * information about access based on the host level access lists, if
616  * present. Also return access check if there is an IP address and
617  * shr_accflags.
618  *
619  * The value of smb_chk_hostaccess is checked for an access match.
620  * -1 is wildcard match
621  * 0 is no match
622  * 1 is match
623  *
624  * Precedence is none is checked first followed by ro then rw if
625  * needed.  If x is wildcard (< 0) then check to see if the other
626  * values are a match. If a match, that wins.
627  *
628  * ipv6 is wide open for now, see smb_chk_hostaccess
629  */
630 void
631 smb_shr_hostaccess(smb_share_t *si, smb_inaddr_t *ipaddr)
632 {
633 	int acc = SMB_SHRF_ACC_OPEN;
634 
635 	/*
636 	 * Check to see if there area any share level access
637 	 * restrictions.
638 	 */
639 	if ((!smb_inet_iszero(ipaddr)) &&
640 	    (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) {
641 		int none = SMB_SHRF_ACC_OPEN;
642 		int rw = SMB_SHRF_ACC_OPEN;
643 		int ro = SMB_SHRF_ACC_OPEN;
644 
645 		if (si->shr_flags & SMB_SHRF_ACC_NONE)
646 			none = smb_chk_hostaccess(ipaddr, si->shr_access_none);
647 		if (si->shr_flags & SMB_SHRF_ACC_RW)
648 			rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw);
649 		if (si->shr_flags & SMB_SHRF_ACC_RO)
650 			ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro);
651 		/* make first pass to get basic value */
652 		if (none != 0)
653 			acc = SMB_SHRF_ACC_NONE;
654 		else if (ro != 0)
655 			acc = SMB_SHRF_ACC_RO;
656 		else if (rw != 0)
657 			acc = SMB_SHRF_ACC_RW;
658 
659 		/* make second pass to handle '*' case */
660 		if (none < 0) {
661 			acc = SMB_SHRF_ACC_NONE;
662 			if (ro > 0)
663 				acc = SMB_SHRF_ACC_RO;
664 			else if (rw > 0)
665 				acc = SMB_SHRF_ACC_RW;
666 		} else if (ro < 0) {
667 			acc = SMB_SHRF_ACC_RO;
668 			if (none > 0)
669 				acc = SMB_SHRF_ACC_NONE;
670 			else if (rw > 0)
671 				acc = SMB_SHRF_ACC_RW;
672 		} else if (rw < 0) {
673 			acc = SMB_SHRF_ACC_RW;
674 			if (none > 0)
675 				acc = SMB_SHRF_ACC_NONE;
676 			else if (ro > 0)
677 				acc = SMB_SHRF_ACC_RO;
678 		}
679 	}
680 	si->shr_access_value = acc;	/* return access here */
681 }
682 
683 /*
684  * smb_shr_is_special
685  *
686  * Special share reserved for interprocess communication (IPC$) or
687  * remote administration of the server (ADMIN$). Can also refer to
688  * administrative shares such as C$, D$, E$, and so forth.
689  */
690 int
691 smb_shr_is_special(char *sharename)
692 {
693 	int len;
694 
695 	if (sharename == NULL)
696 		return (0);
697 
698 	if ((len = strlen(sharename)) == 0)
699 		return (0);
700 
701 	if (sharename[len - 1] == '$')
702 		return (STYPE_SPECIAL);
703 
704 	return (0);
705 }
706 
707 /*
708  * smb_shr_is_restricted
709  *
710  * Check whether or not there is a restriction on a share. Restricted
711  * shares are generally STYPE_SPECIAL, for example, IPC$. All the
712  * administration share names are restricted: C$, D$ etc. Returns B_TRUE
713  * if the share is restricted. Otherwise B_FALSE is returned to indicate
714  * that there are no restrictions.
715  */
716 boolean_t
717 smb_shr_is_restricted(char *sharename)
718 {
719 	static char *restricted[] = {
720 		"IPC$"
721 	};
722 
723 	int i;
724 
725 	if (sharename == NULL)
726 		return (B_FALSE);
727 
728 	for (i = 0; i < sizeof (restricted)/sizeof (restricted[0]); i++) {
729 		if (utf8_strcasecmp(restricted[i], sharename) == 0)
730 			return (B_TRUE);
731 	}
732 
733 	return (smb_shr_is_admin(sharename));
734 }
735 
736 /*
737  * smb_shr_is_admin
738  *
739  * Check whether or not access to the share should be restricted to
740  * administrators. This is a bit of a hack because what we're doing
741  * is checking for the default admin shares: C$, D$ etc.. There are
742  * other shares that have restrictions: see smb_shr_is_restricted().
743  *
744  * Returns B_TRUE if the shares is an admin share. Otherwise B_FALSE
745  * is returned to indicate that there are no restrictions.
746  */
747 boolean_t
748 smb_shr_is_admin(char *sharename)
749 {
750 	if (sharename == NULL)
751 		return (B_FALSE);
752 
753 	if (strlen(sharename) == 2 &&
754 	    mts_isalpha(sharename[0]) && sharename[1] == '$') {
755 		return (B_TRUE);
756 	}
757 
758 	return (B_FALSE);
759 }
760 
761 /*
762  * smb_shr_chkname
763  *
764  * Check for invalid characters in a share name.  The list of invalid
765  * characters includes control characters and the following:
766  *
767  * " / \ [ ] : | < > + ; , ? * =
768  */
769 boolean_t
770 smb_shr_chkname(char *sharename)
771 {
772 	char *invalid = "\"/\\[]:|<>+;,?*=";
773 	char *cp;
774 
775 	if (sharename == NULL)
776 		return (B_FALSE);
777 
778 	if (strpbrk(sharename, invalid))
779 		return (B_FALSE);
780 
781 	for (cp = sharename; *cp != '\0'; cp++) {
782 		if (iscntrl(*cp))
783 			return (B_FALSE);
784 	}
785 
786 	return (B_TRUE);
787 }
788 
789 /*
790  * smb_shr_get_realpath
791  *
792  * Derive the real path for a share from the path provided by a client.
793  * For instance, the real path of C:\ may be /cvol or the real path of
794  * F:\home may be /vol1/home.
795  *
796  * clntpath - path provided by the Windows client is in the
797  *            format of <drive letter>:\<dir>
798  * realpath - path that will be stored as the directory field of
799  *            the smb_share_t structure of the share.
800  * maxlen   - maximum length of the realpath buffer
801  *
802  * Return LAN Manager network error code.
803  */
804 uint32_t
805 smb_shr_get_realpath(const char *clntpath, char *realpath, int maxlen)
806 {
807 	const char *p;
808 	int len;
809 
810 	if ((p = strchr(clntpath, ':')) != NULL)
811 		++p;
812 	else
813 		p = clntpath;
814 
815 	(void) strlcpy(realpath, p, maxlen);
816 	(void) strcanon(realpath, "/\\");
817 	(void) strsubst(realpath, '\\', '/');
818 
819 	len = strlen(realpath);
820 	if ((len > 1) && (realpath[len - 1] == '/'))
821 		realpath[len - 1] = '\0';
822 
823 	return (NERR_Success);
824 }
825 
826 void
827 smb_shr_list(int offset, smb_shrlist_t *list)
828 {
829 	smb_shriter_t iterator;
830 	smb_share_t *si;
831 	int n = 0;
832 
833 	bzero(list, sizeof (smb_shrlist_t));
834 	smb_shr_iterinit(&iterator);
835 
836 	while ((si = smb_shr_iterate(&iterator)) != NULL) {
837 		if (--offset > 0)
838 			continue;
839 
840 		if ((si->shr_flags & SMB_SHRF_TRANS) &&
841 		    ((si->shr_type & STYPE_IPC) == 0)) {
842 			bcopy(si, &list->sl_shares[n], sizeof (smb_share_t));
843 			if (++n == LMSHARES_PER_REQUEST)
844 				break;
845 		}
846 	}
847 
848 	list->sl_cnt = n;
849 }
850 
851 /*
852  * ============================================
853  * Private helper/utility functions
854  * ============================================
855  */
856 
857 /*
858  * Looks up the given share in the cache and return
859  * the info in 'si'
860  */
861 static uint32_t
862 smb_shr_lookup(char *sharename, smb_share_t *si)
863 {
864 	smb_share_t *cached_si;
865 	uint32_t status = NERR_NetNameNotFound;
866 
867 	if (sharename == NULL || *sharename == '\0')
868 		return (NERR_NetNameNotFound);
869 	if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) {
870 		cached_si = smb_shr_cache_findent(sharename);
871 		if (cached_si != NULL) {
872 			bcopy(cached_si, si, sizeof (smb_share_t));
873 			status = NERR_Success;
874 		}
875 
876 		smb_shr_cache_unlock();
877 	}
878 	return (status);
879 }
880 
881 /*
882  * Add IPC$ to the cache upon startup.
883  */
884 static uint32_t
885 smb_shr_addipc(void)
886 {
887 	smb_share_t ipc;
888 	uint32_t status = NERR_InternalError;
889 
890 	bzero(&ipc, sizeof (smb_share_t));
891 	(void) strcpy(ipc.shr_name, "IPC$");
892 	(void) strcpy(ipc.shr_cmnt, "Remote IPC");
893 	ipc.shr_flags = SMB_SHRF_TRANS;
894 	ipc.shr_type = STYPE_IPC;
895 
896 	if (smb_shr_cache_lock(SMB_SHR_CACHE_WRLOCK) == NERR_Success) {
897 		status = smb_shr_cache_addent(&ipc);
898 		smb_shr_cache_unlock();
899 	}
900 
901 	return (status);
902 }
903 
904 /*
905  * smb_shr_set_oemname
906  *
907  * Generate the OEM name for the specified share.  If the name is
908  * shorter than 13 bytes the oemname will be saved in si->shr_oemname.
909  * Otherwise si->shr_oemname will be empty and SMB_SHRF_LONGNAME will
910  * be set in si->shr_flags.
911  */
912 static void
913 smb_shr_set_oemname(smb_share_t *si)
914 {
915 	unsigned int cpid = oem_get_smb_cpid();
916 	mts_wchar_t *unibuf;
917 	char *oem_name;
918 	int length;
919 
920 	length = strlen(si->shr_name) + 1;
921 
922 	oem_name = malloc(length);
923 	unibuf = malloc(length * sizeof (mts_wchar_t));
924 	if ((oem_name == NULL) || (unibuf == NULL)) {
925 		free(oem_name);
926 		free(unibuf);
927 		return;
928 	}
929 
930 	(void) mts_mbstowcs(unibuf, si->shr_name, length);
931 
932 	if (unicodestooems(oem_name, unibuf, length, cpid) == 0)
933 		(void) strcpy(oem_name, si->shr_name);
934 
935 	free(unibuf);
936 
937 	if (strlen(oem_name) + 1 > SMB_SHARE_OEMNAME_MAX) {
938 		si->shr_flags |= SMB_SHRF_LONGNAME;
939 		*si->shr_oemname = '\0';
940 	} else {
941 		si->shr_flags &= ~SMB_SHRF_LONGNAME;
942 		(void) strlcpy(si->shr_oemname, oem_name,
943 		    SMB_SHARE_OEMNAME_MAX);
944 	}
945 
946 	free(oem_name);
947 }
948 
949 /*
950  * ============================================
951  * Cache management functions
952  *
953  * All cache functions are private
954  * ============================================
955  */
956 
957 /*
958  * Create the share cache (hash table).
959  */
960 static uint32_t
961 smb_shr_cache_create(void)
962 {
963 	uint32_t status = NERR_Success;
964 
965 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
966 	switch (smb_shr_cache.sc_state) {
967 	case SMB_SHR_CACHE_STATE_NONE:
968 		smb_shr_cache.sc_cache = ht_create_table(SMB_SHR_HTAB_SZ,
969 		    MAXNAMELEN, 0);
970 		if (smb_shr_cache.sc_cache == NULL) {
971 			status = NERR_InternalError;
972 			break;
973 		}
974 
975 		(void) ht_register_callback(smb_shr_cache.sc_cache,
976 		    smb_shr_cache_freent);
977 		smb_shr_cache.sc_nops = 0;
978 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_CREATED;
979 		break;
980 
981 	default:
982 		assert(0);
983 		status = NERR_InternalError;
984 		break;
985 	}
986 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
987 
988 	return (status);
989 }
990 
991 /*
992  * Destroy the share cache (hash table).
993  * Wait for inflight/pending operations to finish or abort before
994  * destroying the cache.
995  */
996 static void
997 smb_shr_cache_destroy(void)
998 {
999 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
1000 	if (smb_shr_cache.sc_state == SMB_SHR_CACHE_STATE_CREATED) {
1001 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_DESTROYING;
1002 		while (smb_shr_cache.sc_nops > 0)
1003 			(void) cond_wait(&smb_shr_cache.sc_cv,
1004 			    &smb_shr_cache.sc_mtx);
1005 
1006 		smb_shr_cache.sc_cache = NULL;
1007 		smb_shr_cache.sc_state = SMB_SHR_CACHE_STATE_NONE;
1008 	}
1009 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1010 }
1011 
1012 /*
1013  * If the cache is in "created" state, lock the cache for read
1014  * or read/write based on the specified mode.
1015  *
1016  * Whenever a lock is granted, the number of inflight cache
1017  * operations is incremented.
1018  */
1019 static uint32_t
1020 smb_shr_cache_lock(int mode)
1021 {
1022 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
1023 	if (smb_shr_cache.sc_state != SMB_SHR_CACHE_STATE_CREATED) {
1024 		(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1025 		return (NERR_InternalError);
1026 	}
1027 	smb_shr_cache.sc_nops++;
1028 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1029 
1030 	/*
1031 	 * Lock has to be taken outside the mutex otherwise
1032 	 * there could be a deadlock
1033 	 */
1034 	if (mode == SMB_SHR_CACHE_RDLOCK)
1035 		(void) rw_rdlock(&smb_shr_cache.sc_cache_lck);
1036 	else
1037 		(void) rw_wrlock(&smb_shr_cache.sc_cache_lck);
1038 
1039 	return (NERR_Success);
1040 }
1041 
1042 /*
1043  * Decrement the number of inflight operations and then unlock.
1044  */
1045 static void
1046 smb_shr_cache_unlock(void)
1047 {
1048 	(void) mutex_lock(&smb_shr_cache.sc_mtx);
1049 	assert(smb_shr_cache.sc_nops > 0);
1050 	smb_shr_cache.sc_nops--;
1051 	(void) cond_broadcast(&smb_shr_cache.sc_cv);
1052 	(void) mutex_unlock(&smb_shr_cache.sc_mtx);
1053 
1054 	(void) rw_unlock(&smb_shr_cache.sc_cache_lck);
1055 }
1056 
1057 /*
1058  * Return the total number of shares
1059  */
1060 static int
1061 smb_shr_cache_count(void)
1062 {
1063 	return (ht_get_total_items(smb_shr_cache.sc_cache));
1064 }
1065 
1066 /*
1067  * looks up the given share name in the cache and if it
1068  * finds a match returns a pointer to the cached entry.
1069  * Note that since a pointer is returned this function
1070  * MUST be protected by smb_shr_cache_lock/unlock pair
1071  */
1072 static smb_share_t *
1073 smb_shr_cache_findent(char *sharename)
1074 {
1075 	HT_ITEM *item;
1076 
1077 	(void) utf8_strlwr(sharename);
1078 	item = ht_find_item(smb_shr_cache.sc_cache, sharename);
1079 	if (item && item->hi_data)
1080 		return ((smb_share_t *)item->hi_data);
1081 
1082 	return (NULL);
1083 }
1084 
1085 /*
1086  * Return a pointer to the first/next entry in
1087  * the cache based on the given iterator.
1088  *
1089  * Calls to this function MUST be protected by
1090  * smb_shr_cache_lock/unlock.
1091  */
1092 static smb_share_t *
1093 smb_shr_cache_iterate(smb_shriter_t *shi)
1094 {
1095 	HT_ITEM *item;
1096 
1097 	if (shi->si_first) {
1098 		item = ht_findfirst(smb_shr_cache.sc_cache, &shi->si_hashiter);
1099 		shi->si_first = B_FALSE;
1100 	} else {
1101 		item = ht_findnext(&shi->si_hashiter);
1102 	}
1103 
1104 	if (item && item->hi_data)
1105 		return ((smb_share_t *)item->hi_data);
1106 
1107 	return (NULL);
1108 }
1109 
1110 /*
1111  * Add the specified share to the cache.  Memory needs to be allocated
1112  * for the cache entry and the passed information is copied to the
1113  * allocated space.
1114  */
1115 static uint32_t
1116 smb_shr_cache_addent(smb_share_t *si)
1117 {
1118 	smb_share_t *cache_ent;
1119 	uint32_t status = NERR_Success;
1120 
1121 	if ((cache_ent = malloc(sizeof (smb_share_t))) == NULL)
1122 		return (ERROR_NOT_ENOUGH_MEMORY);
1123 
1124 	bcopy(si, cache_ent, sizeof (smb_share_t));
1125 
1126 	(void) utf8_strlwr(cache_ent->shr_name);
1127 	smb_shr_set_oemname(cache_ent);
1128 
1129 	if ((si->shr_type & STYPE_IPC) == 0)
1130 		cache_ent->shr_type = STYPE_DISKTREE;
1131 	cache_ent->shr_type |= smb_shr_is_special(cache_ent->shr_name);
1132 
1133 	if (smb_shr_is_admin(cache_ent->shr_name))
1134 		cache_ent->shr_flags |= SMB_SHRF_ADMIN;
1135 
1136 	if (si->shr_flags & SMB_SHRF_AUTOHOME)
1137 		cache_ent->shr_refcnt = 1;
1138 
1139 	if (ht_add_item(smb_shr_cache.sc_cache, cache_ent->shr_name, cache_ent)
1140 	    == NULL) {
1141 		syslog(LOG_DEBUG, "share: %s: cache update failed",
1142 		    cache_ent->shr_name);
1143 		free(cache_ent);
1144 		status = NERR_InternalError;
1145 	}
1146 
1147 	return (status);
1148 }
1149 
1150 /*
1151  * Delete the specified share from the cache.
1152  */
1153 static void
1154 smb_shr_cache_delent(char *sharename)
1155 {
1156 	(void) utf8_strlwr(sharename);
1157 	(void) ht_remove_item(smb_shr_cache.sc_cache, sharename);
1158 }
1159 
1160 /*
1161  * Call back to free the given cache entry.
1162  */
1163 static void
1164 smb_shr_cache_freent(HT_ITEM *item)
1165 {
1166 	if (item && item->hi_data)
1167 		free(item->hi_data);
1168 }
1169 
1170 /*
1171  * ============================================
1172  * Interfaces to sharemgr
1173  *
1174  * All functions in this section are private
1175  * ============================================
1176  */
1177 
1178 /*
1179  * Load shares from sharemgr
1180  */
1181 /*ARGSUSED*/
1182 static void *
1183 smb_shr_sa_loadall(void *args)
1184 {
1185 	sa_handle_t handle;
1186 	sa_group_t group, subgroup;
1187 	char *gstate;
1188 	boolean_t gdisabled;
1189 
1190 	if ((handle = smb_shr_sa_enter()) == NULL)
1191 		return (NULL);
1192 
1193 	for (group = sa_get_group(handle, NULL);
1194 	    group != NULL; group = sa_get_next_group(group)) {
1195 		gstate = sa_get_group_attr(group, "state");
1196 		if (gstate == NULL)
1197 			continue;
1198 
1199 		gdisabled = (strcasecmp(gstate, "disabled") == 0);
1200 		sa_free_attr_string(gstate);
1201 		if (gdisabled)
1202 			continue;
1203 
1204 		smb_shr_sa_loadgrp(group);
1205 
1206 		for (subgroup = sa_get_sub_group(group);
1207 		    subgroup != NULL;
1208 		    subgroup = sa_get_next_group(subgroup)) {
1209 			smb_shr_sa_loadgrp(subgroup);
1210 		}
1211 
1212 	}
1213 
1214 	smb_shr_sa_exit();
1215 	return (NULL);
1216 }
1217 
1218 /*
1219  * Load the shares contained in the specified group.
1220  *
1221  * Don't process groups on which the smb protocol is disabled.
1222  * The top level ZFS group won't have the smb protocol enabled
1223  * but sub-groups will.
1224  *
1225  * We will tolerate a limited number of errors and then give
1226  * up on the current group.  A typical error might be that the
1227  * shared directory no longer exists.
1228  */
1229 static void
1230 smb_shr_sa_loadgrp(sa_group_t group)
1231 {
1232 	sa_share_t share;
1233 	sa_resource_t resource;
1234 	int error_count = 0;
1235 
1236 	if (sa_get_optionset(group, SMB_PROTOCOL_NAME) == NULL)
1237 		return;
1238 
1239 	for (share = sa_get_share(group, NULL);
1240 	    share != NULL;
1241 	    share = sa_get_next_share(share)) {
1242 		for (resource = sa_get_share_resource(share, NULL);
1243 		    resource != NULL;
1244 		    resource = sa_get_next_resource(resource)) {
1245 			if (smb_shr_sa_load(share, resource))
1246 				++error_count;
1247 
1248 			if (error_count > SMB_SHR_ERROR_THRESHOLD)
1249 				break;
1250 		}
1251 
1252 		if (error_count > SMB_SHR_ERROR_THRESHOLD)
1253 			break;
1254 	}
1255 }
1256 
1257 /*
1258  * Load a share definition from sharemgr and add it to the cache.
1259  * If the share is already in the cache then it doesn't do anything.
1260  *
1261  * This function does not report duplicate shares as error since
1262  * a share might have been added by smb_shr_get() while load is
1263  * in progress.
1264  */
1265 static uint32_t
1266 smb_shr_sa_load(sa_share_t share, sa_resource_t resource)
1267 {
1268 	smb_share_t si;
1269 	char *sharename;
1270 	uint32_t status;
1271 	boolean_t loaded;
1272 
1273 	if ((sharename = sa_get_resource_attr(resource, "name")) == NULL)
1274 		return (NERR_InternalError);
1275 
1276 	loaded = smb_shr_exists(sharename);
1277 	sa_free_attr_string(sharename);
1278 
1279 	if (loaded)
1280 		return (NERR_Success);
1281 
1282 	if ((status = smb_shr_sa_get(share, resource, &si)) != NERR_Success) {
1283 		syslog(LOG_DEBUG, "share: failed to load %s (%d)",
1284 		    si.shr_name, status);
1285 		return (status);
1286 	}
1287 
1288 	status = smb_shr_add(&si);
1289 	if ((status != NERR_Success) && (status != NERR_DuplicateShare)) {
1290 		syslog(LOG_DEBUG, "share: failed to cache %s (%d)",
1291 		    si.shr_name, status);
1292 		return (status);
1293 	}
1294 
1295 	return (NERR_Success);
1296 }
1297 
1298 /*
1299  * Read the specified share information from sharemgr and return
1300  * it in the given smb_share_t structure.
1301  *
1302  * Shares read from sharemgr are marked as permanent/persistent.
1303  */
1304 static uint32_t
1305 smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si)
1306 {
1307 	sa_property_t prop;
1308 	sa_optionset_t opts;
1309 	char *val = NULL;
1310 	char *path;
1311 	char *rname;
1312 
1313 	if ((path = sa_get_share_attr(share, "path")) == NULL)
1314 		return (NERR_InternalError);
1315 
1316 	if ((rname = sa_get_resource_attr(resource, "name")) == NULL) {
1317 		sa_free_attr_string(path);
1318 		return (NERR_InternalError);
1319 	}
1320 
1321 	bzero(si, sizeof (smb_share_t));
1322 	si->shr_flags = SMB_SHRF_PERM;
1323 
1324 	(void) strlcpy(si->shr_path, path, sizeof (si->shr_path));
1325 	(void) strlcpy(si->shr_name, rname, sizeof (si->shr_name));
1326 	sa_free_attr_string(path);
1327 	sa_free_attr_string(rname);
1328 
1329 	val = sa_get_resource_description(resource);
1330 	if (val == NULL)
1331 		val = sa_get_share_description(share);
1332 
1333 	if (val != NULL) {
1334 		(void) strlcpy(si->shr_cmnt, val, sizeof (si->shr_cmnt));
1335 		sa_free_share_description(val);
1336 	}
1337 
1338 	opts = sa_get_derived_optionset(resource, SMB_PROTOCOL_NAME, 1);
1339 	if (opts == NULL)
1340 		return (NERR_Success);
1341 
1342 	prop = (sa_property_t)sa_get_property(opts, SHOPT_AD_CONTAINER);
1343 	if (prop != NULL) {
1344 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1345 			(void) strlcpy(si->shr_container, val,
1346 			    sizeof (si->shr_container));
1347 			free(val);
1348 		}
1349 	}
1350 
1351 	prop = (sa_property_t)sa_get_property(opts, SHOPT_CSC);
1352 	if (prop != NULL) {
1353 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1354 			smb_shr_sa_csc_option(val, si);
1355 			free(val);
1356 		}
1357 	}
1358 
1359 	prop = (sa_property_t)sa_get_property(opts, SHOPT_NONE);
1360 	if (prop != NULL) {
1361 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1362 			(void) strlcpy(si->shr_access_none, val,
1363 			    sizeof (si->shr_access_none));
1364 			free(val);
1365 			si->shr_flags |= SMB_SHRF_ACC_NONE;
1366 		}
1367 	}
1368 
1369 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RO);
1370 	if (prop != NULL) {
1371 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1372 			(void) strlcpy(si->shr_access_ro, val,
1373 			    sizeof (si->shr_access_ro));
1374 			free(val);
1375 			si->shr_flags |= SMB_SHRF_ACC_RO;
1376 		}
1377 	}
1378 
1379 	prop = (sa_property_t)sa_get_property(opts, SHOPT_RW);
1380 	if (prop != NULL) {
1381 		if ((val = sa_get_property_attr(prop, "value")) != NULL) {
1382 			(void) strlcpy(si->shr_access_rw, val,
1383 			    sizeof (si->shr_access_rw));
1384 			free(val);
1385 			si->shr_flags |= SMB_SHRF_ACC_RW;
1386 		}
1387 	}
1388 
1389 	sa_free_derived_optionset(opts);
1390 	return (NERR_Success);
1391 }
1392 
1393 /*
1394  * Map a client-side caching (CSC) option to the appropriate share
1395  * flag.  Only one option is allowed; an error will be logged if
1396  * multiple options have been specified.  We don't need to do anything
1397  * about multiple values here because the SRVSVC will not recognize
1398  * a value containing multiple flags and will return the default value.
1399  *
1400  * If the option value is not recognized, it will be ignored: invalid
1401  * values will typically be caught and rejected by sharemgr.
1402  */
1403 void
1404 smb_shr_sa_csc_option(const char *value, smb_share_t *si)
1405 {
1406 	struct {
1407 		char *value;
1408 		uint32_t flag;
1409 	} cscopt[] = {
1410 		{ "disabled",	SMB_SHRF_CSC_DISABLED },
1411 		{ "manual",	SMB_SHRF_CSC_MANUAL },
1412 		{ "auto",	SMB_SHRF_CSC_AUTO },
1413 		{ "vdo",	SMB_SHRF_CSC_VDO }
1414 	};
1415 
1416 	int i;
1417 
1418 	for (i = 0; i < (sizeof (cscopt) / sizeof (cscopt[0])); ++i) {
1419 		if (strcasecmp(value, cscopt[i].value) == 0) {
1420 			si->shr_flags |= cscopt[i].flag;
1421 			break;
1422 		}
1423 	}
1424 
1425 	switch (si->shr_flags & SMB_SHRF_CSC_MASK) {
1426 	case 0:
1427 	case SMB_SHRF_CSC_DISABLED:
1428 	case SMB_SHRF_CSC_MANUAL:
1429 	case SMB_SHRF_CSC_AUTO:
1430 	case SMB_SHRF_CSC_VDO:
1431 		break;
1432 
1433 	default:
1434 		syslog(LOG_INFO, "csc option conflict: 0x%08x",
1435 		    si->shr_flags & SMB_SHRF_CSC_MASK);
1436 		break;
1437 	}
1438 }
1439 
1440 /*
1441  * looks up sharemgr for the given share (resource) and loads
1442  * the definition into cache if lookup is successful
1443  */
1444 static uint32_t
1445 smb_shr_sa_loadbyname(char *sharename)
1446 {
1447 	sa_handle_t handle;
1448 	sa_share_t share;
1449 	sa_resource_t resource;
1450 	uint32_t status;
1451 
1452 	if ((handle = smb_shr_sa_enter()) == NULL)
1453 		return (NERR_InternalError);
1454 
1455 	resource = sa_find_resource(handle, sharename);
1456 	if (resource == NULL) {
1457 		smb_shr_sa_exit();
1458 		return (NERR_NetNameNotFound);
1459 	}
1460 
1461 	share = sa_get_resource_parent(resource);
1462 	if (share == NULL) {
1463 		smb_shr_sa_exit();
1464 		return (NERR_InternalError);
1465 	}
1466 
1467 	status = smb_shr_sa_load(share, resource);
1468 
1469 	smb_shr_sa_exit();
1470 	return (status);
1471 }
1472 
1473 /*
1474  * ============================================
1475  * Share publishing functions
1476  *
1477  * All the functions are private
1478  * ============================================
1479  */
1480 
1481 static void
1482 smb_shr_publish(const char *sharename, const char *container)
1483 {
1484 	smb_shr_publisher_queue(sharename, container, SMB_SHR_PUBLISH);
1485 }
1486 
1487 static void
1488 smb_shr_unpublish(const char *sharename, const char *container)
1489 {
1490 	smb_shr_publisher_queue(sharename, container, SMB_SHR_UNPUBLISH);
1491 }
1492 
1493 /*
1494  * In domain mode, put a share on the publisher queue.
1495  * This is a no-op if the smb service is in Workgroup mode.
1496  */
1497 static void
1498 smb_shr_publisher_queue(const char *sharename, const char *container, char op)
1499 {
1500 	smb_shr_pitem_t *item = NULL;
1501 
1502 	if (container == NULL || *container == '\0')
1503 		return;
1504 
1505 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
1506 		return;
1507 
1508 	(void) mutex_lock(&ad_queue.spq_mtx);
1509 	switch (ad_queue.spq_state) {
1510 	case SMB_SHR_PQS_READY:
1511 	case SMB_SHR_PQS_PUBLISHING:
1512 		break;
1513 	default:
1514 		(void) mutex_unlock(&ad_queue.spq_mtx);
1515 		return;
1516 	}
1517 	(void) mutex_unlock(&ad_queue.spq_mtx);
1518 
1519 	if ((item = malloc(sizeof (smb_shr_pitem_t))) == NULL)
1520 		return;
1521 
1522 	item->spi_op = op;
1523 	(void) strlcpy(item->spi_name, sharename, sizeof (item->spi_name));
1524 	(void) strlcpy(item->spi_container, container,
1525 	    sizeof (item->spi_container));
1526 
1527 	(void) mutex_lock(&ad_queue.spq_mtx);
1528 	list_insert_tail(&ad_queue.spq_list, item);
1529 	(void) cond_signal(&ad_queue.spq_cv);
1530 	(void) mutex_unlock(&ad_queue.spq_mtx);
1531 }
1532 
1533 /*
1534  * Publishing won't be activated if the smb service is running in
1535  * Workgroup mode.
1536  */
1537 static int
1538 smb_shr_publisher_start(void)
1539 {
1540 	pthread_t publish_thr;
1541 	pthread_attr_t tattr;
1542 	int rc;
1543 
1544 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
1545 		return (0);
1546 
1547 	(void) mutex_lock(&ad_queue.spq_mtx);
1548 	if (ad_queue.spq_state != SMB_SHR_PQS_NOQUEUE) {
1549 		(void) mutex_unlock(&ad_queue.spq_mtx);
1550 		errno = EINVAL;
1551 		return (-1);
1552 	}
1553 
1554 	list_create(&ad_queue.spq_list, sizeof (smb_shr_pitem_t),
1555 	    offsetof(smb_shr_pitem_t, spi_lnd));
1556 	ad_queue.spq_state = SMB_SHR_PQS_READY;
1557 	(void) mutex_unlock(&ad_queue.spq_mtx);
1558 
1559 	(void) pthread_attr_init(&tattr);
1560 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1561 	rc = pthread_create(&publish_thr, &tattr, smb_shr_publisher, 0);
1562 	(void) pthread_attr_destroy(&tattr);
1563 
1564 	return (rc);
1565 }
1566 
1567 static void
1568 smb_shr_publisher_stop(void)
1569 {
1570 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
1571 		return;
1572 
1573 	(void) mutex_lock(&ad_queue.spq_mtx);
1574 	switch (ad_queue.spq_state) {
1575 	case SMB_SHR_PQS_READY:
1576 	case SMB_SHR_PQS_PUBLISHING:
1577 		ad_queue.spq_state = SMB_SHR_PQS_STOPPING;
1578 		(void) cond_signal(&ad_queue.spq_cv);
1579 		break;
1580 	default:
1581 		break;
1582 	}
1583 	(void) mutex_unlock(&ad_queue.spq_mtx);
1584 }
1585 
1586 /*
1587  * This is the publisher daemon thread.  While running, the thread waits
1588  * on a conditional variable until notified that a share needs to be
1589  * [un]published or that the thread should be terminated.
1590  *
1591  * Entries may remain in the outgoing queue if the Active Directory
1592  * service is inaccessible, in which case the thread wakes up every 60
1593  * seconds to retry.
1594  */
1595 /*ARGSUSED*/
1596 static void *
1597 smb_shr_publisher(void *arg)
1598 {
1599 	smb_ads_handle_t *ah;
1600 	smb_shr_pitem_t *shr;
1601 	list_t publist;
1602 	timestruc_t pubretry;
1603 	char hostname[MAXHOSTNAMELEN];
1604 
1605 	(void) mutex_lock(&ad_queue.spq_mtx);
1606 	if (ad_queue.spq_state != SMB_SHR_PQS_READY) {
1607 		(void) mutex_unlock(&ad_queue.spq_mtx);
1608 		return (NULL);
1609 	}
1610 	ad_queue.spq_state = SMB_SHR_PQS_PUBLISHING;
1611 	(void) mutex_unlock(&ad_queue.spq_mtx);
1612 
1613 	(void) smb_gethostname(hostname, MAXHOSTNAMELEN, 0);
1614 
1615 	list_create(&publist, sizeof (smb_shr_pitem_t),
1616 	    offsetof(smb_shr_pitem_t, spi_lnd));
1617 
1618 	for (;;) {
1619 		(void) mutex_lock(&ad_queue.spq_mtx);
1620 
1621 		while (list_is_empty(&ad_queue.spq_list) &&
1622 		    (ad_queue.spq_state == SMB_SHR_PQS_PUBLISHING)) {
1623 			if (list_is_empty(&publist)) {
1624 				(void) cond_wait(&ad_queue.spq_cv,
1625 				    &ad_queue.spq_mtx);
1626 			} else {
1627 				pubretry.tv_sec = 60;
1628 				pubretry.tv_nsec = 0;
1629 				(void) cond_reltimedwait(&ad_queue.spq_cv,
1630 				    &ad_queue.spq_mtx, &pubretry);
1631 				break;
1632 			}
1633 		}
1634 
1635 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
1636 			(void) mutex_unlock(&ad_queue.spq_mtx);
1637 			break;
1638 		}
1639 
1640 		/*
1641 		 * Transfer queued items to the local list so that
1642 		 * the mutex can be released.
1643 		 */
1644 		while ((shr = list_head(&ad_queue.spq_list)) != NULL) {
1645 			list_remove(&ad_queue.spq_list, shr);
1646 			list_insert_tail(&publist, shr);
1647 		}
1648 
1649 		(void) mutex_unlock(&ad_queue.spq_mtx);
1650 
1651 		if ((ah = smb_ads_open()) != NULL) {
1652 			smb_shr_publisher_send(ah, &publist, hostname);
1653 			smb_ads_close(ah);
1654 		}
1655 	}
1656 
1657 	(void) mutex_lock(&ad_queue.spq_mtx);
1658 	smb_shr_publisher_flush(&ad_queue.spq_list);
1659 	list_destroy(&ad_queue.spq_list);
1660 	ad_queue.spq_state = SMB_SHR_PQS_NOQUEUE;
1661 	(void) mutex_unlock(&ad_queue.spq_mtx);
1662 
1663 	smb_shr_publisher_flush(&publist);
1664 	list_destroy(&publist);
1665 	return (NULL);
1666 }
1667 
1668 /*
1669  * Remove items from the specified queue and [un]publish them.
1670  */
1671 static void
1672 smb_shr_publisher_send(smb_ads_handle_t *ah, list_t *publist, const char *host)
1673 {
1674 	smb_shr_pitem_t *shr;
1675 
1676 	while ((shr = list_head(publist)) != NULL) {
1677 		(void) mutex_lock(&ad_queue.spq_mtx);
1678 		if (ad_queue.spq_state != SMB_SHR_PQS_PUBLISHING) {
1679 			(void) mutex_unlock(&ad_queue.spq_mtx);
1680 			return;
1681 		}
1682 		(void) mutex_unlock(&ad_queue.spq_mtx);
1683 
1684 		list_remove(publist, shr);
1685 
1686 		if (shr->spi_op == SMB_SHR_PUBLISH)
1687 			(void) smb_ads_publish_share(ah, shr->spi_name,
1688 			    NULL, shr->spi_container, host);
1689 		else
1690 			(void) smb_ads_remove_share(ah, shr->spi_name,
1691 			    NULL, shr->spi_container, host);
1692 
1693 		free(shr);
1694 	}
1695 }
1696 
1697 /*
1698  * Flush all remaining items from the specified list/queue.
1699  */
1700 static void
1701 smb_shr_publisher_flush(list_t *lst)
1702 {
1703 	smb_shr_pitem_t *shr;
1704 
1705 	while ((shr = list_head(lst)) != NULL) {
1706 		list_remove(lst, shr);
1707 		free(shr);
1708 	}
1709 }
1710