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